diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/CREDITS linux/CREDITS --- v2.2.17/CREDITS Sat Sep 9 18:42:31 2000 +++ linux/CREDITS Sat Dec 9 20:58:01 2000 @@ -46,6 +46,10 @@ P: 1024/85AD9EED AD C0 49 08 91 67 DF D7 FA 04 1A EE 09 E8 44 B0 D: Unix98 pty support. D: APM update to 1.2 spec. +D: /devfs hacking. +S: 322 N. Riverside Dr. +S: Neptune, NJ 07753 +S: USA N: Erik Andersen E: andersee@debian.org @@ -202,6 +206,14 @@ S: 6369 BG Simpelveld S: The Netherlands +N: Peter Berger +E: pberger@brimson.com +W: http://www.brimson.com +D: Author/maintainer of Digi AccelePort USB driver +S: 1549 Hiironen Rd. +S: Brimson, MN 55602 +S: USA + N: Hennus Bergman E: hennus@cybercomm.nl W: http://www.cybercomm.nl/~hennus/ @@ -222,6 +234,14 @@ S: Marrickville NSW 2204 S: Australia +N: Hugh Blemings +E: hugh@linuxcare.com +W: http://www.linuxcare.com.au/hugh/ +D: Author and maintainer of the Keyspan USB to Serial drivers +S: Po Box 234 +S: Belconnen ACT 2616 +S: Australia + N: Philip Blundell E: philb@gnu.org D: Linux/ARM hacker @@ -253,6 +273,14 @@ D: Configuration help text support D: Linux CD and Support Giveaway List +N: Al Borchers +E: alborchers@steinerpoint.com +D: Author/maintainer of Digi AccelePort USB driver +D: work on usbserial and keyspan_pda drivers +S: 4912 Zenith Ave. S. +S: Minneapolis, MN 55410 +S: USA + N: Zoltán Böszörményi E: zboszor@mail.externet.hu D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support @@ -290,6 +318,11 @@ S: Lancaster, LA1 4DN S: UK, England +N: Paul Bristow +E: paul@paulbristow.net +W: http://paulbristow.net/linux +D: ide-floppy maintainer + N: Andries Brouwer E: aeb@cwi.nl D: random Linux hacker @@ -393,6 +426,13 @@ D: Assorted sched/mm titbits S: Oxfordshire, UK. +N: Mark Corner +E: mcorner@umich.edu +W: http://www.eecs.umich.edu/~mcorner/ +D: USB Bluetooth Driver +S: University of Michigan +S: Ann Arbor, MI + N: Alan Cox W: http://roadrunner.swansea.linux.org.uk/alan.shtml E: alan@lxorguk.ukuu.org.uk @@ -500,6 +540,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/ @@ -554,6 +603,13 @@ S: Huntington Beach, California 92649 S: USA +N: Johannes Erdfelt +E: jerdfelt@valinux.com +D: USB +S: 6350 Stoneridge Mall Road +S: Pleasanton, CA 94588 +S: USA + N: Doug Evans E: dje@cygnus.com D: Wrote Xenix FS (part of standard kernel since 0.99.15) @@ -681,6 +737,7 @@ D: parent process death signal to children D: prctl() syscall D: /proc/mtrr support to manipulate MTRRs on Intel P6 family +D: Device FileSystem (devfs) S: CSIRO Australia Telescope National Facility S: P.O. Box 76, Epping S: New South Wales, 2121 @@ -707,6 +764,15 @@ S: Sterling Heights, Michigan 48313 S: USA +N: William Greathouse +E: wgreathouse@smva.com +E: wgreathouse@myfavoritei.com +D: Current Belkin USB Serial Adapter F5U103 hacker +D: Kernel hacker, embedded systems +S: 7802 Fitzwater Road +S: Brecksville, OH 44141-1334 +S: USA + N: Tristan Greaves E: Tristan.Greaves@icl.com E: tmg296@ecs.soton.ac.uk @@ -1128,6 +1194,18 @@ S: L3R 8B2 S: Canada +N: Andrzej M. Krzysztofowicz +E: ankry@mif.pg.gda.pl +D: Some 8-bit XT disk driver and /devfs hacking + +N: Greg Kroah-Hartman +E: greg@kroah.com +W: http://www.kroah.com/linux-usb/ +D: USB Serial Converter driver framework, USB Handspring Visor driver +D: ConnectTech WHITEHeat USB driver, Generic USB Serial driver +D: USB Bluetooth driver, +D: bits and pieces of USB core code. + N: Russell Kroll E: rkroll@exploits.org W: http://www.exploits.org/ @@ -1287,7 +1365,7 @@ N: Pavel Machek E: pavel@atrey.karlin.mff.cuni.cz D: Softcursor for vga, hypertech cdrom support, vcsa bugfix -D: Network block device, sun4/330 port +D: Network block device, sun4/330 port, USB S: Volkova 1131 S: 198 00 Praha 9 S: Czech Republic @@ -1317,6 +1395,15 @@ S: Halifax, Nova Scotia S: Canada B3J 3C8 +N: Petko Manolov +E: petkan@dce.bg +D: USB ethernet (pegasus) driver +D: optimizing i[45]86 string routines +D: i386 task swithing hacks +S: 5, Vrah Mancho str. +S: 1324 Sofia +S: Bulgaria + N: Martin Mares E: mj@atrey.karlin.mff.cuni.cz W: http://atrey.karlin.mff.cuni.cz/~mj/ @@ -1380,10 +1467,19 @@ N: Arnaldo Carvalho de Melo E: acme@conectiva.com.br +E: acme@gnu.org +W: http://bazar.conectiva.com.br/~acme +W: http://advogato.org/person/acme +P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD 841A B6AB 4681 9224 DF01 D: wanrouter hacking -D: cyclades 2X sync card driver (still in early devel stage) -S: R. Prof. Rubens Elke Braga, 558 - Parolin -S: 80220-320 Curitiba - Parana +D: USB hacking +D: misc Makefile, Config.in, drivers and network stacks fixes +D: IPX Multithreading for 2.4 +D: Cyclom 2X synchronous card driver +D: i18n for minicom, net-tools, util-linux, fetchmail, etc +S: Conectiva S.A. +S: R. Tocantins, 89 - Cristo Rei +S: 80050-430 - Curitiba - Paraná S: Brazil N: Michael Meskes @@ -1473,6 +1569,13 @@ S: Fremont, California 94536 S: USA +N: Sam Mosel +E: sam.mosel@computer.org +D: Wacom Intuos USB Support +S: 22 Seaview St +S: Fullarton 5063 +S: South Australia + N: Ian A. Murdock E: imurdock@gnu.ai.mit.edu D: Creator of Debian distribution @@ -1576,7 +1679,7 @@ D: Joystick driver D: arcnet-hardware readme D: Minor ARCnet hacking -D: USB development +D: USB (HID, ACM, Printer ...) S: Ucitelska 1576 S: Prague 8 S: 182 00 Czech Republic @@ -1711,10 +1814,10 @@ S: Germany N: Joerg Reuter -E: jreuter@poboxes.com -W: http://poboxes.com/jreuter/ -W: http://qsl.net/dl1bke/ -D: Generic Z8530 driver, AX.25 DAMA slave implementation +E: jreuter@yaina.de +W: http://yaina.de/jreuter +W: http://www.qsl.net/dl1bke/ +D: Generic Z8530 driver for AX.25, AX.25 DAMA slave implementation D: Several AX.25 hacks N: Francois-Rene Rideau @@ -1800,6 +1903,14 @@ D: Ruggedly handsome. D: Developed Generic IP Firewalling Chains with Michael Neuling. +N: Bill Ryder +E: bryder@sgi.com +D: FTDI_SIO usb/serial converter driver +W: http://reality.sgi.com/bryder_wellington/ftdi_sio +S: I/3 Walter St +S: Wellington +S: New Zealand + N: Thomas Sailer E: sailer@ife.ee.ethz.ch E: HB9JNX@HB9W.CHE.EU (packet radio) @@ -2084,17 +2195,14 @@ S: USA N: Stephen Tweedie -E: sct@dcs.ed.ac.uk +E: sct@redhat.com P: 1024/E7A417AD E2 FE A4 20 34 EC ED FC 7D 7E 67 8D E0 31 D1 69 +P: 1024D/43BE7544 D2A4 8556 08E6 90E7 076C BA3F 243F 20A4 43BE 7544 D: Second extended file system developer D: General filesystem hacker D: kswap vm management code -S: Dept. of Computer Science -S: University of Edinburgh -S: JCMB, The King's Buildings -S: Mayfield Road -S: Edinburgh -S: EH9 3JZ +S: 44 Campbell Park Crescent +S: Edinburgh EH13 0HT S: United Kingdom N: Thomas Uhl @@ -2314,9 +2422,10 @@ D: some Alpha platform porting from 2.0, Memory Technology Devices, D: Acquire watchdog timer, PC speaker driver maintenance, D: various other stuff that annoyed me by not working. -S: c/o Red Hat UK Limited -S: 35-36 Cambridge Place -S: Cambridge. CB2 1NS +S: c/o Red Hat Engineering +S: Rustat House +S: 60 Clifton Road +S: Cambridge. CB1 7EG S: England N: Frank Xia diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/ARM-README linux/Documentation/ARM-README --- v2.2.17/Documentation/ARM-README Fri Apr 21 12:45:49 2000 +++ linux/Documentation/ARM-README Thu Jan 1 01:00:00 1970 @@ -1,181 +0,0 @@ - ARM Linux 2.1.99 - ================ - - Since this is a development kernel, it will not be as stable as the 2.0 - series, and can cause very nasty problems (eg, trashing your hard disk). - When running one of these kernels, I advise you to back up the complete - contents of all your hard disks. - - -Contributors ------------- - - Here is a list of people actively working on the project (If you - wish to be added to the list, please email me): - - Name: Russell King - Mail: linux@arm.uk.linux.org - Desc: Original developer of ARM Linux, project co-ordinator. - - Name: Dave Gilbert - Mail: linux@treblig.org - Desc: A3/4/5xx floppy and hard disk code maintainer. - - Name: Philip Blundell - Mail: Philip.Blundell@pobox.com - Desc: Architecture and processor selection during make config. - - -Todo list ---------- - - This is the list of changes to be done (roughly prioritised): - - * fully test new MEMC translation code - * fully test new AcornSCSI driver. - * reply to email ;) - - - Notes - ===== - -Compilation of kernel ---------------------- - - In order to compile ARM Linux, you will need a compiler capable of - generating ARM ELF code with GNU extensions. GCC-2.7.2.2 is good. - - To build ARM Linux natively, you shouldn't have to alter the ARCH = line in - the top level Makefile. However, if you don't have the ARM Linux ELF tools - installed as default, then you should change the CROSS_COMPILE line as - detailed below. - - If you wish to cross-compile, then alter the following lines in the top - level make file: - - ARCH = - with - ARCH = arm - - and - - CROSS_COMPILE= - to - CROSS_COMPILE= - eg. - CROSS_COMPILE=/usr/bin/arm-unknown-linuxelf- - - Do a 'make config', followed by 'make dep', and finally 'make all' to - build the kernel (vmlinux). A compressed image can be built by doing - a 'make zImage' instead of 'make all'. - - -Bug reports etc. ----------------- - - Please send patches, bug reports and code for the ARM Linux project - to linux@arm.uk.linux.org. Patches will not be included into future - kernels unless they come to me (or the relevant person concerned). - - When sending bug reports, please ensure that they contain all relevant - information, eg. the kernel messages that were printed before/during - the problem, what you were doing, etc. - - For patches, please include some explanation as to what the patch does - and why (if relevant). - - -Modules -------- - - Although modularisation is supported (and required for the FP emulator), - each module on an arm2/arm250/arm3 machine when is loaded will take - memory up to the next 32k boundary due to the size of the pages. Hence is - modularisation on these machines really worth it? - - However, arm6 and up machines allow modules to take multiples of 4k, and - as such Acorn RiscPCs and other architectures using these processors can - make good use of modularisation. - - -ADFS Image files ----------------- - - You can access image files on your ADFS partitions by mounting the ADFS - partition, and then using the loopback device driver. You must have - losetup installed. - - Please note that the PCEmulator DOS partitions have a partition table at - the start, and as such, you will have to give '-o offset' to losetup. - - -Kernel initialisation abort codes ---------------------------------- - - When the kernel is unable to boot, it will if possible display a colour - at the top of the screen. The colours have the following significance - when run in a 16 colour mode with the default palette: - - Stripes of white, red, yellow, and green: - Kernel does not support the processor architecture detected. - - -Request to developers ---------------------- - - When writing device drivers which include a separate assembler file, please - include it in with the C file, and not the arch/arm/lib directory. This - allows the driver to be compiled as a loadable module without requiring - half the code to be compiled into the kernel image. - - In general, try to avoid using assembler unless it is really necessary. It - makes drivers far less easy to port to other hardware. - - -ST506 hard drives ------------------ - - The ST506 hard drive controllers seem to be working fine (if a little - slowly). At the moment they will only work off the controllers on an - A4x0's motherboard, but for it to work off a Podule just requires - someone with a podule to add the addresses for the IRQ mask and the - HDC base to the source. - - As of 31/3/96 it works with two drives (you should get the ADFS - *configure hard drive set to 2). I've got an internal 20 MB and a great - big external 5.25" FH 64 MB drive (who could ever want more :-) ). - - I've just got 240 K/s off it (a dd with bs=128k); that's about half of what - RiscOS gets, but it's a heck of a lot better than the 50 K/s I was getting - last week :-) - - Known bug: Drive data errors can cause a hang; including cases where - the controller has fixed the error using ECC. (Possibly ONLY - in that case...hmm). - - -1772 Floppy ------------ - This also seems to work OK, but hasn't been stressed much lately. It - hasn't got any code for disc change detection in there at the moment which - could be a bit of a problem! Suggestions on the correct way to do this - are welcome. - - -Kernel entry (head-armv.S) --------------------------- - The initial entry into the kernel made via head-armv.S uses architecture - independent code. The architecture is selected by the value of 'r1' on - entry, which must be kept unique. You can register a new architecture - by mailing the following details to rmk@arm.uk.linux.org. Please give - the mail a subject of 'Register new architecture': - - Name: - ARCHDIR: - Description: - - - Please follow this format - it is an automated system. You should - receive a reply the next day. ---- -Russell King (03/05/1998) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/Changes linux/Documentation/Changes --- v2.2.17/Documentation/Changes Sat Sep 9 18:42:32 2000 +++ linux/Documentation/Changes Sun Oct 15 21:15:17 2000 @@ -224,13 +224,14 @@ your system, you don't have to upgrade just so the kernel will work (though feel free to upgrade if you want the gcc bug fixes). - Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad + Note that the latest compilers (pgcc, gcc 2.95) may do Bad Things while compiling your kernel, particularly if absurd -optimizations (like -O9) are used. Caveat emptor. Currently, the only -C compiler available in a binary distribution is egcs. Version 1.1.2 -seems okay; if you have to have a binary, you may be successful using -that. In general, however, gcc-2.7.2.3 is known to be stable, while -egcs and others have not been as thoroughly tested yet. +optimizations (like -O9) are used. Caveat emptor. In general, however, +gcc-2.7.2.3 and egcs 1.1.2 are known to be stable on x86, while gcc 2.95 and +others have not been as thoroughly tested yet. + +For non x86 platforms consult the platform specific information for +recommended compilers. Networking Changes ================== @@ -651,9 +652,9 @@ 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 1.4.7 release: -ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.7.tar.gz -ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.7.tar.gz + +The kernel-level nfs-utils-0.1.6 release: +ftp://nfs.sourceforge.net/pub/nfs/nfs-utils-0.1.6.tar.gz Net-tools ========= diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/Configure.help linux/Documentation/Configure.help --- v2.2.17/Documentation/Configure.help Sat Sep 9 18:42:32 2000 +++ linux/Documentation/Configure.help Thu Dec 7 14:52:03 2000 @@ -13,8 +13,6 @@ # http://www.traduc.org/kernelfr # - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at # http://visar.csustan.edu/~carlos/ -# - Italian, by Alessandro Rubini (rubini@linux.it), at -# ftp://ftp-pavia1.linux.it/pub/linux/Configure.help # - Polish, by Cezar Cichocki (cezar@cs.net.pl), at # http://www.cs.net.pl/~cezar/Kernel # - German, by Jörg Strebel (jstrebel@suse.de) and Karl Eichwalder @@ -624,6 +622,11 @@ say M here and read Documentation/modules.txt. The module will be called ps2esdi.o. +ALI M15X3 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_ALI15X3 + This driver ensures (U)DMA support for ALI 1543 and 1543C, + 1535, 1535D onboard chipsets. + Tekram TRM290 chipset support (EXPERIMENTAL) CONFIG_BLK_DEV_TRM290 This driver adds support for bus master DMA transfers @@ -658,6 +661,13 @@ CONFIG_BLK_DEV_CMD646 Say Y here if you have an IDE controller like this. +Cyrix CS5530 MediaGX chipset support +CONFIG_BLK_DEV_CS5530 + Include support for UDMA on the Cyrix MediaGX 5530 chipset. This + will automatically be detected and configured if found. + + It is safe to say Y to this question. + QDI QD6580 support CONFIG_BLK_DEV_QD6580 This driver is enabled at runtime using the "ide0=qd6580" kernel @@ -681,6 +691,50 @@ I/O speeds to be set as well. See the files Documentation/ide.txt and drivers/block/ali14xx.c for more info. +Generic PC I/O port IDE interface support +CONFIG_BLK_DEV_PCIDE + This is the IDE driver for most generic PC style IDE interfaces. + Say Y if you have a PC and want to use IDE devices (hard disks, CD-ROM + drives, etc.) that are connected to the builtin IDE interface. + +Amiga builtin Gayle IDE interface support +CONFIG_BLK_DEV_GAYLE + This is the IDE driver for the builtin IDE interface on some Amiga + models. It supports both the `A1200 style' (used in A600 and A1200) + and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE + interface. + Say Y if you have such an Amiga model and want to use IDE devices + (hard disks, CD-ROM drives, etc.) that are connected to the builtin + IDE interface. + +Falcon IDE interface support +CONFIG_BLK_DEV_FALCON_IDE + This is the IDE driver for the builtin IDE interface on the Atari + Falcon. + Say Y if you have a Falcon and want to use IDE devices (hard disks, + CD-ROM drives, etc.) that are connected to the builtin IDE interface. + +Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL) +CONFIG_BLK_DEV_BUDDHA + This is the IDE driver for the IDE interfaces on the Buddha and + Catweasel expansion boards. It supports up to two interfaces on the + Buddha and three on the Catweasel. + Say Y if you have a Buddha or Catweasel expansion board and want to + use IDE devices (hard disks, CD-ROM drives, etc.) that are connected + to one of its IDE interfaces. + +Amiga IDE Doubler support (EXPERIMENTAL) +CONFIG_BLK_DEV_IDEDOUBLER + This driver provides support for the so called `IDE doublers' (made by + various manufacturers, e.g. Eyetech) that can be connected to the + builtin IDE interface of some Amiga models. Using such an IDE doubler, + you can connect up to four instead of two IDE devices on the Amiga's + builtin IDE interface. + Note that the normal Amiga Gayle IDE driver may not work correctly if + you have an IDE doubler and don't enable this driver! + Say Y if you have an IDE doubler. The driver is enabled at kernel + runtime using the "ide=doubler" kernel boot parameter. + XT hard disk support CONFIG_BLK_DEV_XD Very old 8 bit hard disk controllers used in the IBM XT computer @@ -1456,6 +1510,61 @@ CONFIG_FB_SGIVW SGI Visual Workstation support for framebuffer graphics. +I2O support +CONFIG_I2O + The Intelligent Input/Output (I2O) architecture allows hardware + drivers to be split into two parts: an operating system specific + module called the OSM and an hardware specific module called the + HDM. The OSM can talk to a whole range of HDM's, and ideally the + HDM's are not OS dependent. This allows for the same HDM driver to + be used under different operating systems if the relevant OSM is in + place. In order for this to work, you need to have an I2O interface + adapter card in your computer. This card contains a special I/O + processor (IOP), thus allowing high speeds since the CPU does not + have to deal with I/O. + + If you say Y here, you will get a choice of interface adapter + drivers and OSM's with the following questions. + + This support is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. You will get modules called i2o_core.o + and i20_config.o. + + If unsure, say N. + +I2O PCI support +CONFIG_I2O_PCI + Say Y for support of PCI bus I2O interface adapters. Currently this + is the only variety supported, so you should say Y. + + This support is also available as a module called i2o_pci.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. + +I2O Block OSM +CONFIG_I2O_BLOCK + Include support for the I2O Block OSM. The Block OSM presents disk + and other structured block devices to the operating system. + + This support is also available as a module called i2o_block.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. + +I2O SCSI OSM +CONFIG_I2O_SCSI + Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel + I2O controller. You can use both the SCSI and Block OSM together if + you wish. + + This support is also available as a module called i2o_scsi.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. + System V IPC CONFIG_SYSVIPC Inter Process Communication is a suite of library functions and @@ -1818,6 +1927,21 @@ CONFIG_FB_ATY This driver supports graphics boards with the ATI Mach64 chips. + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called 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 This driver supports a frame buffer for the graphics adapter in the @@ -1831,7 +1955,8 @@ PowerMac "valkyrie" frame buffer device support CONFIG_FB_VALKYRIE This driver supports a frame buffer for the "valkyrie" graphics - adapter in some Power Macintoshes. + adapter found in some Power Macintoshes, as well as the 580 and 630 + series 68k Macintoshes. Chips 65550 display support CONFIG_FB_CT65550 @@ -1840,8 +1965,9 @@ Mac frame buffer device CONFIG_FB_MAC - This is the frame buffer device driver for the graphics hardware in - m68k Macintoshes. + This is the a generic frame buffer device driver for the graphics + hardware in m68k Macintoshes. It can only use the video mode set + by MacOS at boot time. You should probably say Y here. HP300 frame buffer device CONFIG_FB_HP300 @@ -3525,6 +3651,29 @@ in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The Bridging code is still in test. If unsure, say N. +Frame Diverter (EXPERIMENTAL) +CONFIG_NET_DIVERT + The Frame Diverter allows you to divert packets from the + network, that are not aimed at the interface receiving it (in + promisc. mode). Typically, a Linux box setup as an ethernet bridge + with the Frames Diverter on, can do some *really* transparent www + caching using a Squid proxy for example. + + This is very useful when you don't want to change your router's + config (or if you simply don't have access to it). + + The other possible usages of diverting Ethernet Frames are numberous: + - reroute smtp traffic to another interface + - traffic-shape certain network streams + - transparently proxy smtp connections + - etc... + + For more informations, please refer to: + http://www.freshmeat.net/projects/etherdivert + http://perso.wanadoo.fr/magpie/EtherDivert.html + + If unsure, say N + Packet socket CONFIG_PACKET The Packet protocol is used by applications which communicate @@ -4081,9 +4230,11 @@ tagged command queuing and fast synchronous data transfers up to 80 MB/s with wide FAST-40 LVD devices and controllers. + This driver does not support SYM53C1010 Ultra-160 PCI-SCSI chips. + Support for SYM53C1010 chips requires the "SYM53C8XX SCSI option" to + be configured. This option will configure a different driver. Recent versions of the 53C8XX chips are better supported by the - option "SYM53C8XX SCSI support", below. This option will configure - a different driver. + option "SYM53C8XX SCSI support", below. If you want the kernel to select the recommended driver for each of of your NCR/SYM53C8XX controllers you may just configure both the @@ -4102,7 +4253,8 @@ CONFIG_SCSI_SYM53C8XX This driver supports all the features of recent 53C8XX chips (used in PCI SCSI controllers), notably the hardware phase mismatch - feature of the SYM53C896. + feature of the SYM53C896, SYM53C895A and SYM53C1010. + It also supports Ultra-160 SCSI data transfers for the SYM53C1010. Older versions of the 53C8XX chips are not supported by this driver. If your system uses either a 810 rev. < 16, a 815, or a 825 @@ -4124,8 +4276,8 @@ synchronous data transfers frequency CONFIG_SCSI_NCR53C8XX_SYNC - The SCSI Parallel Interface-2 Standard defines 4 classes of transfer - rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are + The SCSI Parallel Interface-2 Standard defines 5 classes of transfer + rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers are respectively the maximum data transfer rates in mega-transfers per second for each class. For example, a FAST-20 Wide 16 device is able to transfer data at 20 million 16 bit packets per second for a total @@ -4133,9 +4285,9 @@ You may specify 0 if you want to only use asynchronous data transfers. This is the safest and slowest option. Otherwise, specify - a value between 5 and 40, depending on the capability of your SCSI + a value between 5 and 80, depending on the capability of your SCSI controller. The higher the number, the faster the data transfer. - Note that 40 should normally be ok since the driver decreases the + Note that 80 should normally be ok since the driver decreases the value automatically according to the controller's capabilities. Your answer to this question is ignored for controllers with NVRAM, @@ -4146,7 +4298,7 @@ second). The normal answer therefore is not to go with the default but to - select the maximum value 40 allowing the driver to use the maximum + select the maximum value 80 allowing the driver to use the maximum value supported by each controller. If this causes problems with your SCSI devices, you should come back and decrease the value. @@ -4197,7 +4349,9 @@ CONFIG_SCSI_NCR53C8XX_MAX_TAGS This option allows you to specify the maximum number of commands that can be queued to any device, when tagged command queuing is - possible. The default value is 32. Minimum is 2, maximum is 64. + possible. The default value is 32. Minimum is 2, maximum is 64 for + the generic NCR53C8XX driver and 255 for the SYM53C8XX driver. + Modern hard disks are able to support 64 tags and even more, but do not seem to be faster when more than 32 tags are being used. @@ -4449,6 +4603,23 @@ The module will be called qlogicfc.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Compaq 64-bit / 66MHz PCI Fibre Channel Host Adapter +CONFIG_SCSI_CPQFCTS + This driver supports Compaq HBA part #120186-B21, the non- + intelligent Tachyon TL/TS (HPFC-5166A/1.2) based adapter. + Kernel linked or kernel module, SMP support. Information at + /proc/scsi/cpqfcTS/* + + Only supports FC-AL (non-loop mode not supported). Supports Fabric + (FL_Port, public device); tested on Brocade switches. Supports hot- + plug of new devices and movement of devices across ports (i.e., + dynamic re-assignment of 24-bit FC port_id). + + Tested on Compaq RA4x00 (f/w ver 2.40 or newer), RA8000, with Vixel + Rapport 1000 (7-port non-managed), Gadzoox 12-port, Gadzoox Capellix + 3000, Brocade 2010, 2400, 2800. Selective Storage + Presentation (SSP) on RA4x00 f/w 2.54 (no redundancy). + Seagate ST-02 and Future Domain TMC-8xx SCSI support CONFIG_SCSI_SEAGATE These are 8-bit SCSI controllers; the ST-01 is also supported by @@ -5191,6 +5362,14 @@ If you want to do that, say M here. The module will be called sealevel.o. +SyncLink HDLC/SYNCPPP support +CONFIG_SYNCLINK_SYNCPPP + Enables HDLC/SYNCPPP support for the SyncLink WAN driver. + Normally the SyncLink WAN driver works with the main PPP + driver (ppp.c) and pppd program. HDLC/SYNCPPP support allows use + of the Cisco HDLC/PPP driver (syncppp.c). + The SyncLink WAN driver (in character devices) must also be enabled. + Frame Relay (DLCI) support CONFIG_DLCI This is support for the frame relay protocol; frame relay is a fast @@ -5715,6 +5894,20 @@ If you want to compile this as a module, say M and read Documentation/modules.txt. The module will be called comx-proto-fr.o. +Xpeed DSL NIC support +CONFIG_XPEED + This driver supports Xpeed Inc. PCI network cards. + The following cards are supported with this driver: + + Xpeed X200 IDSL NIC (http://www.xpeed.com/Products/x200/x200_c.html) + Xpeed X300 SDSL NIC (http://www.xpeed.com/Products/x300/x300_c.html) + + This driver handles frame relay encapsulation of WAN link and presents + the card to the kernel as an ethernet-like device called dsl0, dsl1, etc. + + Currently the driver only functions as a module. Detailed configuration + information can be found in Documentation/networking/README.xpeed + Generic HDLC driver CONFIG_HDLC Say Y to this option if your Linux box contains a WAN card supported @@ -6929,6 +7122,35 @@ This is support for the DIGITAL series of EISA (DEFEA) and PCI (DEFPA) controllers which can connect you to a local FDDI network. +SysKonnect FDDI PCI support +CONFIG_SKFP + Say Y here if you have a SysKonnect FDDI PCI adapter. + The following adapters are supported by this driver: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC + Read Documentation/networking/skfp.txt for information about + the driver. + Questions concerning this driver can be addressed 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 skfp.o. + HIgh Performance Parallel Interface support (EXPERIMENTAL) CONFIG_HIPPI HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and @@ -7260,6 +7482,650 @@ only driver for hard disks. These should be the first partition (eg. /dev/[sh]d?1) on each of your drives. If unsure, say N. +Support for USB +CONFIG_USB + Universal Serial Bus (USB) is a specification for a serial bus + 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 leaves and the inner + nodes are special USB devices called hubs. Many newer PC's 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. + + Say Y here if your computer has a USB port and you want to 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 to the operating system) and then choose from + among the drivers for USB peripherals. You may want to check out the + information provided in Documentation/usb/ and especially the links + given in Documentation/usb/usb-help.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 usbcore.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB verbose debug messages +CONFIG_USB_DEBUG + Say Y here if you want the USB core & hub drivers to produce a bunch + of debug messages to the system log. Select this if you are having a + problem with USB support and want to see more of what is going on. + +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, you may want to say Y, but see below. 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). + + Currently there exist two drivers for UHCI host controllers: this + one and the so-called JE driver, which you can get from + "UHCI alternate (JE) support", below. You need only one. + + 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. + +UHCI (intel PIIX4, VIA, ...) alternate (JE) support? +CONFIG_USB_UHCI_ALT + 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, you may want to say Y, but see below. 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. + + Currently there exist two drivers for UHCI host controllers: this + so-called JE driver, and the one you get from "UHCI support", above. + You need only one. + + 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 uhci.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +UHCI unlink optimizations (EXPERIMENTAL) +CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE + This option currently does nothing. You may say Y or N. + +OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support +CONFIG_USB_OHCI + 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 (aktual 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.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.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +USB Human Interface Device (HID) support +CONFIG_USB_HID + Say Y here if you want to connect keyboards, mice, joysticks, + graphic tablets, or any other HID based devices to your + computer via USB. More information is available: + Documentation/usb/input.txt. + + 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 hid.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. + + 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 usbkbd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +USB HIDBP Mouse support +CONFIG_USB_MOUSE + 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. + + 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 usbmouse.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +Wacom Intuos/Graphire tablet support +CONFIG_USB_WACOM + Say Y here if you want to use the USB version of the Wacom Intuos + or Graphire tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wacom.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +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. + + 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 wmforce.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Keyboard support +CONFIG_INPUT_KEYBDEV + Say Y here if you want your USB HID keyboard to be able to serve + as a system keyboard. + + 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 keybdev.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Mouse support +CONFIG_INPUT_MOUSEDEV + Say Y here if you want your USB HID mouse (or ADB mouse handled by + the input layer) to be accessible as char devices 13:32+ - + /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2 + mouse. That way, all user space programs will be able to use your + mouse. + + If unsure, say Y. + + 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 mousedev.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Horizontal screen resolution +CONFIG_INPUT_MOUSEDEV_SCREEN_X + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. + +Vertical screen resolution +CONFIG_INPUT_MOUSEDEV_SCREEN_Y + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. + +Joystick support +CONFIG_INPUT_JOYDEV + Say Y here if you want your USB HID joystick or gamepad to be + accessible as char device 13:0+ - /dev/input/jsX device. + + 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 joydev.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Event interface support +CONFIG_INPUT_EVDEV + Say Y here if you want your USB or ADB HID device events be accessible + under char device 13:64+ - /dev/input/eventX 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 scanner.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +USB Audio support +CONFIG_USB_AUDIO + Say Y here if you want to connect UAB audio equipment such as + speakers 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 audio.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Modem (CDC ACM) support +CONFIG_USB_ACM + This driver supports USB modems and ISDN adapters which support the + Communication Device Class Abstract Control Model interface. + Please read Documentation/usb/acm.txt for details. + + 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 Serial converter support +CONFIG_USB_SERIAL + Say Y here if you have a USB device that provides normal serial + ports, and you want to connect it to your USB bus. Supported devices + are the Tech WhiteHEAT multi-port USB to serial converter, and the + FTDI or Keyspan single port USB to serial converter Handspring + Visor. In addition to saying Y here, you need to say Y to the driver + for your specific hardware below. Some other devices may also be + used if you say Y to "USB Generic Serial Driver", below. + + 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 usbserial.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 converter + support" 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. + + 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 whiteheat.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +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. See http://usbvisor.sourceforge.net for + more information on using this driver. + + 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 visor.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB FTDI Single Port Serial Driver +CONFIG_USB_SERIAL_FTDI_SIO + Say Y here if you want to use a FTDI SIO single port USB to serial + converter device. The implementation I have is called the USC-1000. + + See http://reality.sgi.com/bryder_wellington/ftdi_sio for more + information on this driver and the device. + + 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 ftdi_sio.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Keyspan PDA Single Port Serial Driver +CONFIG_USB_SERIAL_KEYSPAN_PDA + Say Y here if you want to use a Keyspan PDA single port USB to + serial converter device. This driver makes use of firmware + developed from scratch by Brian Warner. + + 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 keyspan_pda.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +USB Keyspan USA-xxx Serial Driver +CONFIG_USB_SERIAL_KEYSPAN + Say Y here if you want to use Keyspan USB to serial converter + devices. This driver makes use of Keyspan's official firmware + and was developed with their support. You must also include + firmware to support your particular device(s). + + See http://www.linuxcare.com.au/hugh/keyspan.html 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 keyspan.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Keyspan USA-28 Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA28 + Say Y here to include firmware for the USA-28 converter. + +USB Keyspan USA-28X Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA28X + Say Y here to include firmware for the USA-28X converter. + +USB Keyspan USA-19 Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA19 + Say Y here to include firmware for the USA-19 converter. + +USB Keyspan USA-18X Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA18X + Say Y here to include firmware for the USA-18X converter. + +USB Keyspan USA-19W Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA19W + Say Y here to include firmware for the USA-19W converter. + +USB ZyXEL omni.net LCD Plus Driver +CONFIG_USB_SERIAL_OMNINET + Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA. + + 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 omninet.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Digi International AccelePort USB Serial Driver +CONFIG_USB_SERIAL_DIGI_ACCELEPORT + Say Y here if you want to use Digi AccelePort USB 2 or 4 devices, + 2 port (plus parallel port) and 4 port USB serial converters. The + parallel port on the USB 2 appears as a third serial port on Linux. + The Digi Acceleport USB 8 is not yet supported by this driver. + + This driver works under SMP with the usb-uhci driver. It does not + work under SMP with the uhci driver. + + 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 digi_acceleport.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +USB Serial Converter verbose debug +CONFIG_USB_SERIAL_DEBUG + Say Y here if you want verbose debug messages from the USB Serial + Converter. + +USB Printer support +CONFIG_USB_PRINTER + 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 + inserted in and removed from the running kernel whenever you want). + The module will be called printer.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB IBM (Xirlink) C-It Camera support +CONFIG_USB_IBMCAM + Say Y here if you want to connect a IBM "C-It" camera, also known as + "Xirlink PC Camera" to your computer's USB port. For more + information, read Documentation/usb/ibmcam.txt. + + This driver uses the Video For Linux API. You must enable + (Y or M in config) Video For Linux (under Character Devices) + to use this driver. Information on this API and pointers to + "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + 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 ibmcam.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. This camera + has several configuration options which can be specified when you + load the module. Read Documentation/usb/ibmcam.txt to learn more. + +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 driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Character Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + 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 ADMtek Pegasus-based ethernet device support +CONFIG_USB_PEGASUS + Say Y if you want to use your USB ethernet device. Supported + cards until now are: + ADMtek AN986 (eval. board) + Accton 10/100 + Billington USB-100 + Corega FEter USB-TX + MELCO/BUFFALO LUA-TX + D-Link DSB-650TX, DSB-650TX-PNA, DSB-650, DU-E10, DU-E100 + Linksys USB100TX, USB10TX + LANEED Ethernet LD-USB/TX + SMC 202 + SOHOware NUB Ethernet + If you have devices with vendor IDs other than noted above + you should add them in the driver code and send a message + to me (petkan@dce.bg) for update. + + 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 pegasus.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 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). + + 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 dc2xx.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Mustek MDC800 Digital Camera Support +CONFIG_USB_MDC800 + Say Y here if you want to connect this type of still camera to + your computer's USB port. This driver can be used with gphoto 0.4.3 + and higher (look at http://www.gphoto.org ). + To use it create a device node with "mknod /dev/mustek c 180 32" and + configure it in your software. + + 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 mdc800.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Mass Storage support +CONFIG_USB_STORAGE + 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-storage.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +USB Mass Storage verbose debug +CONFIG_USB_STORAGE_DEBUG + Say Y here in order to have the USB Mass Storage code generate + verbose debugging messages. + +USS720 parport driver +CONFIG_USB_USS720 + This driver is for USB parallel port adapters that use the Lucent + Technologies USS-720 chip. These cables are plugged into your USB + port and provide USB compatibility to peripherals designed with + parallel port interfaces. + + The chip has two modes: automatic mode and manual mode. In automatic + mode, it looks to the computer like a standard USB printer. Only + printers may be connected to the USS-720 in this mode. The generic + USB printer driver ("USB Printer support", above) may be used in + that mode, and you can say N here if you want to use the chip only + in this mode. + + 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 magnitude + slower than on a PCI/ISA Parallel Port, so timing critical + applications might not work. + + Say Y here if you own an USS-720 USB->Parport cable and intend to + connect anything other than a printer to it. + + 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 uss720.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB device file system +CONFIG_USB_DEVICEFS + If you say Y here (and to "/proc file system support" below), you + will get a file /proc/usb/devices which lists the devices currently + connected to your USB busses, a file /proc/usb/drivers which lists + the USB kernel client drivers currently loaded, and for every + connected device a file named "/proc/usb/xxx/yyy", where xxx is the + bus number and yyy the device number; the latter files can be used + by user space programs to talk directly to the device. These files + are "virtual", meaning they are generated on the fly and not stored + on the hard drive. + + For the format of the /proc/usb/ files, please read + Documentation/usb/proc_usb_info.txt. + + Please note that this code is completely unrelated to devfs, the + "/dev file system support". + + Most users want to say Y here. + +Support for hot-pluggable USB devices +CONFIG_HOTPLUG + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + Enable this with KMOD, and your kernel will automatically + call out to a user mode "policy agent" to load drivers and other + modules needed to use USB devices you plug in. With a bit of work, + it can invoke other device setup tasks. Get such agent software + (at http://www.linux-usb.org/policy.html) and install it. + +USB Bandwidth allocation +CONFIG_USB_BANDWIDTH + If you say Y here, the USB subsystem enforces USB bandwidth + allocation and will prevent some device opens from succeeding + if they would cause USB bandwidth usage to go above 90% of + the bus bandwidth. + + If you say N here, these conditions will cause warning messages + about USB bandwidth usage to be logged and some devices or + drivers may not work correctly. + +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. URB's are explained in + Documentation/usb/URB.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 dabusb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +PLUSB driver +CONFIG_USB_PLUSB + A driver for the Prolific PL-2302 USB-to-USB network device. This + 'USB cable' connects two hosts via a point-to-point network with + bandwidth of 5 Mbit/s. Configure this driver after connecting the + USB cable via ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 (and + vice versa on the other host). + + 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 plusb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Diamond Rio500 support +CONFIG_USB_RIO500 + Say Y here if you want to connect a USB Rio500 mp3 player to your + computer's USB port. Please read Documentation/usb/rio.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 rio500.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +D-Link DSB-R100 FM radio support +CONFIG_USB_DSBR + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + This driver uses the Video For Linux API. You must enable + (Y or M in config) Video For Linux (under Character Devices) + to use this driver. Information on this API and pointers to + "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + 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 dsbr100.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Microtek USB scanner support +CONFIG_USB_MICROTEK + Say Y here if you want support for the Microtek X6USB and possibly + some other scanners by that vendor. The scanner will appear as a + scsi generic device to the rest of the system. + A patched version of SANE is necessary to use the + scanner. It's available at + http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html + This driver can be compiled as a module. + +USB Bluetooth support +CONFIG_USB_BLUETOOTH + Say Y here if you want to connect a USB Bluetooth device to your + computer's USB port. You will need the Bluetooth stack (available + at http://developer.axis.com/software/index.shtml) to fully use + the device. + + 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 bluetooth.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Kawasaki USB ethernet controller support +CONFIG_USB_KAWETH + Say Y here if you want support for devices based on the Kawasaki + LSI KL5KUSB100 USB to Ethernet 1-Chip Controller, such as the + NetGear EA101 USB to Ethernet Adapter. + + 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 kaweth.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about OS's. @@ -7535,31 +8401,33 @@ 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 kernel based solution is faster and is now the recommended + solution: no further development is occurring on the userspace server and + support of it may be discontinued in future. In either case, you will need support software; the respective locations are given in the file Documentation/Changes in the NFS section. - Please read the NFS-HOWTO, available via FTP (user: anonymous) from - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. + Please read the NFS-HOWTO, available from + 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 daemon -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 yes here. If unsure, say N. +Provide NFSv3 server support (EXPERIMENTAL) +CONFIG_NFSD_V3 + If you would like to include the NFSv3 server as well as the NFSv2 + server, say Y here. File locking, via the NLMv4 protocol, is now + supported. If unsure, say N. OS/2 HPFS filesystem support (read only) CONFIG_HPFS_FS @@ -7891,6 +8759,20 @@ want), say M here and read Documentation/modules.txt. The module will be called smbfs.o. Most people say N, however. +use nls by default +CONFIG_SMB_NLS_DEFAULT + Enabling this will make smbfs use nls translations by default. You + need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls + settings and you need to give the default nls for the SMB server as + CONFIG_SMB_NLS_REMOTE. + +nls support setting +CONFIG_SMB_NLS_REMOTE + This setting allows you to specify a default value for which + codepage the server uses. If this field is left blank no + translations will be done. The local codepage/charset default to + CONFIG_NLS_DEFAULT, you need to set that value in the NLS menu. + Coda filesystem support CONFIG_CODA_FS Coda is an advanced network filesystem, similar to NFS in that it @@ -9197,6 +10079,33 @@ speed. If unsure, leave this disabled, i.e. leave it at 2000 bits/sec. +Direct Rendering Manager (XFree86 DRI support) +CONFIG_DRM + Kernel-level support for the Direct Rendering Infrastructure (DRI) + introduced in XFree86 4.x. These modules provide support for + synchronization, security, and DMA transfers. Select the module that + provides support for your graphics card. + +3dfx Banshee/Voodoo3+ +CONFIG_DRM_TDFX + Choose M here if you have a 3dfx Banshee/Voodoo3 graphics card. + +3dlabs GMX 2000 +CONFIG_DRM_GAMMA + Choose M here if you have a 3dlabs GMX 2000 graphics card. + +ATI Rage 128 +CONFIG_DRM_R128 + Choose M here if you have a ATI Rage 128 graphics card. + +Intel I810 +CONFIG_DRM_I810 + Choose M here if you have an Intel I810 AGP graphics card. + +Matrox g200/g400 +CONFIG_DRM_MGA + Choose M here if you have a Matrox g200/g400 AGP graphics card. + MTRR control and configuration CONFIG_MTRR On Intel P6 family processors (Pentium Pro, Pentium II and later) @@ -9501,6 +10410,38 @@ You can compile this driver directly into the kernel, or use it as a module. The module will be called sbc60xxwdt.o. +CONFIG_MICROCODE + /dev/cpu/microcode - Intel P6 CPU microcode support + + If you say Y here you will be able to update the microcode on + Intel processors in the P6 family, e.g. Pentium Pro, Pentium II, + Pentium III, Xeon etc. You will obviously need the actual microcode + binary data itself which is not shipped with the Linux kernel. + + For latest news and information on obtaining all the required + ingredients for this driver, check: + http://www.urbanmyth.org/microcode/ + + 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 microcode.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +/dev/cpu/*/msr - Model-specific register support +CONFIG_X86_MSR + This device gives privileged processes access to the x86 + Model-Specific Registers (MSRs). It is a character device with + major 202 and minors 0 to 31 for /dev/cpu/0/msr to /dev/cpu/31/msr. + MSR accesses are directed to a specific CPU on multi-processor + systems. + +/dev/cpu/*/cpuid - CPU information support +CONFIG_X86_CPUID + This device gives processes access to the x86 CPUID instruction to + be executed on a specific processor. It is a character device + with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to + /dev/cpu/31/cpuid. + Enhanced Real Time Clock Support CONFIG_RTC If you say Y here and create a character special file /dev/rtc with @@ -9519,6 +10460,74 @@ sampling), then say Y here, and read Documentation/rtc.txt for details. +AGP/GART support +CONFIG_AGP + This provides a kernel interface (/dev/agpgart) for programming AGP + transfers on motherboards that support them. Primarily, this is used + for hardware-accelerated 3d graphics, though any other AGP device + could take advantage of it. + + If you have a 3d-capable AGP video card say 'M' or 'Y' here. + Otherwise, say 'N'. + + You will also have to indicate support for your specific chipset. + Consult the output of lspci, your motherboard manual, or the inside + of your computer if unsure what to choose. Multiple selections are ok. + +Intel 440LX/BX/GX support +CONFIG_AGP_INTEL + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on Intel 440LX/BX/GX chipsets. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +Intel I810/I810 DC100/I810e support +CONFIG_AGP_I810 + This option give you AGP support for the Xserver for the intel + 810 chipset boards. This is required to do any useful video + modes. + +VIA VP3/MVP3/Apollo Pro support +CONFIG_AGP_VIA + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on VIA MPV3/Apollo Pro chipsets. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +AMD Irongate support +CONFIG_AGP_AMD + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on Intel AMD Irongate chipset. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +Generic SiS support +CONFIG_AGP_SIS + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on Silicon Integrated Systems [SiS] + chipsets. + + Note than 5591/5592 AGP chipsets are NOT supported. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +ALI M1541 support +CONFIG_AGP_ALI + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on ALI M1541 chipset. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + Tadpole ANA H8 Support CONFIG_H8 The Hitachi H8/337 is a microcontroller used to deal with the power @@ -10275,7 +11284,7 @@ Creative EMU10K1 based PCI sound cards CONFIG_SOUND_EMU10K1 Say Y or M if you have a PCI sound card using the EMU10K1 - chipset, such as the Creative SBLive! or SB PCI512. + chipset, such as the Creative SBLive!, SB PCI512 or Emu-APS. Ensoniq ES1370 based PCI sound cards CONFIG_SOUND_ES1370 @@ -10960,6 +11969,32 @@ If you anticipate running this kernel on a computer with a MC68060 processor, say Y. Otherwise, say N. +Math emulation support +CONFIG_FPU_EMU + At some point in the future, this will cause floating-point math + instructions to be emulated by the kernel on machines that lack a + floating-point math coprocessor. Thrill-seekers and chronically + sleep-deprived psychotic hacker types can say Y now, everyone else + should probably wait a while. + +Math emulation only kernel +CONFIG_FPU_EMU_ONLY + This option prevents any floating-point instructions from being + compiled into the kernel, thereby the kernel doesn't save any + floating point context anymore during task switches, so this + kernel will only be usable on machines without a floating-point + math coprocessor. This makes the kernel a bit faster as no tests + needs to be executed whether a floating-point instruction in the + kernel should be executed or not. + +Math emulation extra precision +CONFIG_FPU_EMU_EXTRAPREC + The fpu uses normally a few bit more during calculations for + correct rounding, the emulator can (often) do the same but this + extra calculation can cost quite some time, so you can disable + it here. The emulator will then only calculate with a 64 bit + mantissa and round slightly incorrect. + Advanced processor options CONFIG_ADVANCED_CPU This gives you access to some advanced options for the CPU. The @@ -11162,6 +12197,21 @@ has only been tested on a Hades with a 68060 processor. Before you use this, make backups of your entire hard disk. +Macintosh NCR5380 (II-series) SCSI +CONFIG_MAC_SCSI + If you have a Macintosh with NCR5380-based SCSI, say Y. Otherwise, + say N. This SCSI adaptor is found on all 68030-based Macs, + including the II, IIx, IIcx, IIci, IIsi, IIvx, IIvi, Color Classic, + Classic II, LC II, LC III, and their associated Performa models, as + well as the 68030-based PowerBooks and Duos. + +Macintosh NCR53c9[46] (Quadra/Centris) SCSI +CONFIG_SCSI_MAC_ESP + If you have a Macintosh with NCR53c96 or NCR53c94-based SCSI, say + Y. Otherwise, say N. These SCSI adaptors are found on all + 68040-based Macs, including all Quadra and Centris models, the LC + 475/476 and 575, and the Performa 575, 580, and 630. + Ariadne support CONFIG_ARIADNE If you have a Village Tronic Ariadne Ethernet adapter, say Y. @@ -11229,6 +12279,30 @@ ACSI port ("ACSI node"). The driver works (has to work...) with a polled I/O scheme, so it's rather slow :-( +Macintosh NS 8390 based ethernet cards +CONFIG_DAYNAPORT + Say Y to include support for Macintosh ethernet adaptors based on + the National Semiconductor 8390 and ST-NIC chips. This family of + cards includes the majority of NuBus ethernet cards, as well as many + LC-PDS slot cards, from Apple, Asante, Cabletron, Farallon, and + other manufacturers. + +Macintosh SONIC based ethernet +CONFIG_MACSONIC + Say Y to include support for Macintosh ethernet adaptors based on + the National Semiconductor SONIC chip (83932 and 83934). If you + have a Quadra with onboard SONIC ethernet, say Y here. Onboard + SONIC ethernet chips are found on all Quadra 605, 610, 650, 700, + 800, 900, and 950 models, all Centris 650, most Centris 610, and all + LC475/476 models. It is also found in the DuoDock Plus and DuoDock + II, as well as many NuBus, LC-PDS, and comm-slot cards. + +Macintosh (AV) onboard MACE ethernet +CONFIG_MACMACE + Say Y here if you have a Centris 660AV, a Quadra 660AV, or a Quadra + 840AV, and you would like to use the onboard MACE Ethernet adaptor. + + Multiface Card III parallel support CONFIG_MULTIFACE_III_LP If you have a Multiface III card for your Amiga, and want to use its @@ -11344,6 +12418,11 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. +Macintosh SCC serial support +CONFIG_MAC_SCC + If you have a Macintosh and would like to use its serial + ("Printer" and "Modem") ports in Linux, say Y. Otherwise, say N. + Amiga or Atari DMA sound support CONFIG_DMASOUND If you want to use the internal audio of your Atari or Amiga in @@ -11588,6 +12667,23 @@ CONFIG_RADIO_CADET_PORT Enter the I/O address of the card here (most commonly 330). +Maestro Radio +CONFIG_RADIO_MAESTRO + Choose Y here if you have one of these Maestro sound cards + with FM radio included. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-maestro.o + SF16FMI Radio CONFIG_RADIO_SF16FMI Choose Y here if you have one of these FM radio cards, and then fill @@ -12332,6 +13428,14 @@ boards supported by this driver, and for further information on the use of this driver. +Compaq Smart Array support +CONFIG_BLK_CPQ_CISS_DA + This is the driver for Compaq Smart Array controllers. + Everyone using these boards should say Y here. + See "linux/Documentation/cciss.txt" for the current list of + 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 @@ -12415,7 +13519,7 @@ # # LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab # LocalWords: unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz -# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd +# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia pl pd # LocalWords: HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN # LocalWords: ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt # LocalWords: BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/IO-mapping.txt linux/Documentation/IO-mapping.txt --- v2.2.17/Documentation/IO-mapping.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/IO-mapping.txt Sun Oct 15 21:34:58 2000 @@ -176,7 +176,7 @@ didn't think straight when I wrote it originally. People who have to support both can do something like: - /* support old naming sillyness */ + /* support old naming silliness */ #if LINUX_VERSION_CODE < 0x020100 #define ioremap vremap #define iounmap vfree diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/README.DAC960 linux/Documentation/README.DAC960 --- v2.2.17/Documentation/README.DAC960 Sat Sep 9 18:42:32 2000 +++ linux/Documentation/README.DAC960 Sun Sep 10 14:46:08 2000 @@ -1,11 +1,11 @@ Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers - Version 2.2.8 for Linux 2.2.16 - Version 2.4.8 for Linux 2.4.0 + Version 2.2.9 for Linux 2.2.17 + Version 2.4.9 for Linux 2.4.0 PRODUCTION RELEASE - 19 August 2000 + 7 September 2000 Leonard N. Zubkoff Dandelion Digital @@ -203,13 +203,13 @@ DRIVER INSTALLATION -This distribution was prepared for Linux kernel version 2.2.16 or 2.4.0. +This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0. To install the DAC960 RAID driver, you may use the following commands, replacing "/usr/src" with wherever you keep your Linux kernel source tree: cd /usr/src - tar -xvzf DAC960-2.2.8.tar.gz (or DAC960-2.4.8.tar.gz) + tar -xvzf DAC960-2.2.9.tar.gz (or DAC960-2.4.9.tar.gz) mv README.DAC960 linux/Documentation mv DAC960.[ch] linux/drivers/block patch -p0 < DAC960.patch (if DAC960.patch is included) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/SubmittingDrivers linux/Documentation/SubmittingDrivers --- v2.2.17/Documentation/SubmittingDrivers Thu Jan 1 01:00:00 1970 +++ linux/Documentation/SubmittingDrivers Sun Oct 15 21:13:17 2000 @@ -0,0 +1,112 @@ +Submitting Drivers For The Linux Kernel +--------------------------------------- + +This document is intended to explain how to submit device drivers to the +Linux 2.2 and 2.4test kernel trees. Note that if you are interested in video +card drivers you should probably talk to XFree86 (http://wwww.xfree86.org) +instead. + +Allocating Device Numbers +------------------------- + +Major and minor numbers for devices are allocated by the Linux assigned name +and number authority (currently better known as H Peter Anvin). The +site is http://www.lanana.org/. This also deals with allocating numbers for +devices that are not going to be submitted to the mainstream kernel. + +If you don't use assigned numbers then when you device is submitted it will +get given an assigned number even if that is different from values you may +have shipped to customers before. + +Who To Submit Drivers To +------------------------ + +Linux 2.0: + No new drivers are accepted for this kernel tree + +Linux 2.2: + If the code area has a general maintainer then please submit it to + the maintainer listed in MAINTAINERS in the kernel file. If the + maintainer does not respond or you cannot find the appropriate + maintainer then please contact Alan Cox + +Linux 2.4test: + This kernel tree is under active development. The same rules apply + as 2.2 but you may wish to submit your driver via linux-kernel (see + resources) and follow that list to track changes in API's. These + should no longer be occuring as we are now in a code freeze. + The final contact point for Linux 2.4 submissions is + . + +What Criteria Determine Acceptance +---------------------------------- + +Licensing: The code must be released to us under the GNU General Public + License. We don't insist on any kind of exclusively GPL + licensing, and if you wish the driver to be useful to other + communities such as BSD you may well wish to release under + multiple licenses. + +Interfaces: If your driver uses existing interfaces and behaves like + other drivers in the same class it will be much more likely + to be accepted than if it invents gratuitous new ones. + If you need to implement a common API over Linux and NT + drivers do it in userspace. + +Code: Please use the Linux style of code formatting as documented + in Documentation/CodingStyle. If you have sections of code + that need to be in other formats, for example because they + are shared with a windows driver kit and you want to + maintain them just once seperate them out nicely and note + this fact. + +Portability: Pointers are not always 32bits, people do not all have + floating point and you shouldn't use inline x86 assembler in + your driver without careful thought. Pure x86 drivers + generally are not popular. If you only have x86 hardware it + is hard to test portability but it is easy to make sure the + code can easily be made portable. + +Clarity: It helps if anyone can see how to fix the driver. It helps + you because you get patches not bug reports. If you submit a + driver that intentionally obfuscates how the hardware works + it will go in the bitbucket. + +Control: In general if there is active maintainance of a driver by + the author then patches will be redirected to them unless + they are totally obvious and without need of checking. + If you want to be the contact and update point for the + driver it is a good idea to state this in the comments. + +What Criteria Do Not Determine Acceptance +----------------------------------------- + +Vendor: Being the hardware vendor and maintaining the driver is + often a good thing. If there is a stable working driver from + other people already in the tree don't expect 'we are the + vendor' to get your driver chosen. Ideally work with the + existing driver author to build a single perfect driver. + +Author: It doesn't matter if a large Linux company wrote the driver, + or you did. Nobody has any special access to the kernel + tree. Anyone who tells you otherwise isn't telling the + whole story. + + +Resources +--------- + +Linux kernel master tree: + ftp.kernel.org:/pub/linux/kernel/... + +Linux kernel mailing list: + linux-kernel@vger.kernel.org + [mail majordomo@vger.kernel.org to subscribe] + +Kernel traffic: + Weekly summary of kernel list activity (much easier to read) + [http://kt.linuxcare.com/kernel-traffic] + +Linux USB project: + http://sourceforge.net/projects/linux-usb/ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/arm/nwfpe/README linux/Documentation/arm/nwfpe/README --- v2.2.17/Documentation/arm/nwfpe/README Fri Apr 21 12:45:49 2000 +++ linux/Documentation/arm/nwfpe/README Sun Oct 15 21:34:58 2000 @@ -15,7 +15,7 @@ important. Another choice I made was in the file structure. I have attempted to -contain all operating system specfic code in one module (fpmodule.*). +contain all operating system specific code in one module (fpmodule.*). All the other files contain emulator specific code. This should allow others to port the emulator to NetBSD for instance relatively easily. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/cciss.txt linux/Documentation/cciss.txt --- v2.2.17/Documentation/cciss.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/cciss.txt Fri Sep 1 13:32:52 2000 @@ -0,0 +1,47 @@ +This driver is for Compaq's SMART Array Controllers. + +Supported Cards: +---------------- + +This driver is known to work with the following cards: + + * SA 5300 + +If notes are not already created in the /dev/cciss directory + +# mkdev.cciss [ctlrs] + +Where ctlrs is the number of controllers you have (defaults to 1 if not +specified). + +Device Naming: +-------------- + +You need some entries in /dev for the cciss device. The mkdev.cciss script +can make device nodes for you automatically. Currently the device setup +is as follows: + +Major numbers: + 104 cciss0 + 105 cciss1 + 106 cciss2 + etc... + +Minor numbers: + b7 b6 b5 b4 b3 b2 b1 b0 + |----+----| |----+----| + | | + | +-------- Partition ID (0=wholedev, 1-15 partition) + | + +-------------------- Logical Volume number + +The suggested device naming scheme is: +/dev/cciss/c0d0 Controller 0, disk 0, whole device +/dev/cciss/c0d0p1 Controller 0, disk 0, partition 1 +/dev/cciss/c0d0p2 Controller 0, disk 0, partition 2 +/dev/cciss/c0d0p3 Controller 0, disk 0, partition 3 + +/dev/cciss/c1d1 Controller 1, disk 1, whole device +/dev/cciss/c1d1p1 Controller 1, disk 1, partition 1 +/dev/cciss/c1d1p2 Controller 1, disk 1, partition 2 +/dev/cciss/c1d1p3 Controller 1, disk 1, partition 3 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex --- v2.2.17/Documentation/cdrom/cdrom-standard.tex Fri Apr 21 12:45:49 2000 +++ linux/Documentation/cdrom/cdrom-standard.tex Sun Oct 15 21:34:59 2000 @@ -24,7 +24,7 @@ \title{A \linux\ \cdrom\ standard} \author{David van Leeuwen\\{\normalsize\tt david@ElseWare.cistron.nl} \\{\footnotesize updated by Erik Andersen {\tt(andersee@debian.org)}} -\\{\footnotesize updated by Jens Axboe {\tt(axboe@image.dk)}}} +\\{\footnotesize updated by Jens Axboe {\tt(axboe@suse.de)}}} \date{12 March 1999} \maketitle @@ -919,7 +919,7 @@ than fixing this interface by changing the assumptions it was made under, thereby breaking all user applications that use this function, the \UCD\ implements this $ioctl$ as follows: If the CD in - question has audio tracks on it, and it has absolutly no CD-I, XA, + question has audio tracks on it, and it has absolutely no CD-I, XA, or data tracks on it, it will be reported as $CDS_AUDIO$. If it has both audio and data tracks, it will return $CDS_MIXED$. If there are no audio tracks on the disc, and if the CD in question has any diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd --- v2.2.17/Documentation/cdrom/ide-cd Fri Apr 21 12:45:49 2000 +++ linux/Documentation/cdrom/ide-cd Sun Oct 15 21:34:59 2000 @@ -1,7 +1,7 @@ IDE-CD driver documentation Originally by scott snyder (19 May 1996) Carrying on the torch is: Erik Andersen -New maintainers (19 Oct 1998): Jens Axboe +New maintainer (19 Oct 1998): Jens Axboe 1. Introduction --------------- @@ -286,7 +286,7 @@ Unfortunately, these drives seem to become very confused when we perform the standard Linux ATA disk drive probe. If you own one of these drives, you can bypass the ATA probing which confuses these CDROM drives, by - adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and runing + adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and running lilo (again where X is the drive letter corresponding to where your drive is installed.) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/computone.txt linux/Documentation/computone.txt --- v2.2.17/Documentation/computone.txt Sun Jun 11 21:44:08 2000 +++ linux/Documentation/computone.txt Sun Oct 15 21:34:59 2000 @@ -93,7 +93,7 @@ to update the character drivers' makefile and configuration file, and other kernel source files. A build script (ip2build) was included which applies the patches if needed, and build any utilities needed. -What you recieve may be a single patch file in conventional kernel +What you receive may be a single patch file in conventional kernel patch format build script. That form can also be applied by running patch -p1 < ThePatchFile. Otherwise run ip2build. @@ -191,7 +191,7 @@ Intelliport II installations using the PowerPort expansion module can use the custom speed setting to select the highest speeds: 153,600 bps, 230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for -custom baud rate configuration is fixed at 921,600 for cards/expantion +custom baud rate configuration is fixed at 921,600 for cards/expansion modules with ST654's and 115200 for those with Cirrus CD1400's. This corresponds to the maximum bit rates those chips are capable. For example if the baud base is 921600 and the baud divisor is 18 then @@ -220,13 +220,13 @@ 2.2.x kernels and available as a configuration option in 2.3.46 and higher. Devfs allows for the automatic creation and management of device names under control of the device drivers themselves. The Devfs namespace is -hierarchial and reduces the clutter present in the normal flat /dev +hierarchical and reduces the clutter present in the normal flat /dev namespace. Devfs names and conventional device names may be intermixed. A userspace daemon, devfsd, exists to allow for automatic creation and management of symbolic links from the devfs name space to the conventional names. More details on devfs can be found on the DEVFS home site at or in the file kernel -documenation files, .../linux/Documenation/filesystems/devfs/REAME. +documentation files, .../linux/Documentation/filesystems/devfs/REAME. If you are using devfs, existing devices are automatically created within the devfs name space. Normal devices will be ttf/0 - ttf/255 and callout diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/cpqarray.txt linux/Documentation/cpqarray.txt --- v2.2.17/Documentation/cpqarray.txt Sat Sep 9 18:42:32 2000 +++ linux/Documentation/cpqarray.txt Sun Oct 15 21:34:59 2000 @@ -1,4 +1,4 @@ -This driver is for Compaq's SMART2 Intellegent Disk Array Controllers. +This driver is for Compaq's SMART2 Intelligent Disk Array Controllers. Supported Cards: ---------------- diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/fb/matroxfb.txt linux/Documentation/fb/matroxfb.txt --- v2.2.17/Documentation/fb/matroxfb.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/fb/matroxfb.txt Sat Nov 18 19:18:56 2000 @@ -105,7 +105,7 @@ Configuration ============= -You can pass kernel command line options to vesafb with +You can pass kernel command line options to matroxfb with `video=matrox:option1,option2:value2,option3' (multiple options should be separated by comma, values are separated from options by `:'). Accepted options: @@ -228,7 +228,7 @@ `vesa'. If you know capabilities of your monitor, you can specify some (or all) of -`pixclk', `fh' and `fv'. In this case, `pixclock' is computed so that +`maxclk', `fh' and `fv'. In this case, `pixclock' is computed so that pixclock <= maxclk, real_fh <= fh and real_fv <= fv. maxclk:X - maximum dotclock. X can be specified in MHz, kHz or Hz. Default is diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/fb/vesafb.txt linux/Documentation/fb/vesafb.txt --- v2.2.17/Documentation/fb/vesafb.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/fb/vesafb.txt Sun Oct 15 21:34:59 2000 @@ -62,7 +62,7 @@ 16M | 0x312 0x315 0x318 0x31B To enable one of those modes you have to specify "vga=ask" in the -lilo.conf file and rerun LILO. Then you can type in the descired +lilo.conf file and rerun LILO. Then you can type in the desired mode at the "vga=ask" prompt. For example if you like to use 1024x768x256 colors you have to say "305" at this prompt. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/filesystems/affs.txt linux/Documentation/filesystems/affs.txt --- v2.2.17/Documentation/filesystems/affs.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/filesystems/affs.txt Sun Oct 15 21:34:59 2000 @@ -158,7 +158,7 @@ have an Amiga harddisk connected to your PC, it will overwrite the bytes 0x00dc..0x00df of block 0 with garbage, thus invalidating the Rigid Disk Block. Sheer luck has it that this is an unused -area of the RDB, so only the checksum doesn's match anymore. +area of the RDB, so only the checksum doesn't match anymore. Linux will ignore this garbage and recognize the RDB anyway, but before you connect that drive to your Amiga again, you must restore or repair your RDB. So please do make a backup copy of it diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/filesystems/coda.txt linux/Documentation/filesystems/coda.txt --- v2.2.17/Documentation/filesystems/coda.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/filesystems/coda.txt Sun Oct 15 21:34:59 2000 @@ -1531,7 +1531,7 @@ DDeessccrriippttiioonn Remove all entries in the cache lying in a directory - CodaFid, and all children of this directory. This call is issed when + CodaFid, and all children of this directory. This call is issued when Venus receives a callback on the directory. @@ -1630,7 +1630,7 @@ The following requirements should be accommodated: - 1. The message queueus should have open and close routines. On Unix + 1. The message queues should have open and close routines. On Unix the opening of the character devices are such routines. +o Before opening, no messages can be placed. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/filesystems/fat_cvf.txt linux/Documentation/filesystems/fat_cvf.txt --- v2.2.17/Documentation/filesystems/fat_cvf.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/filesystems/fat_cvf.txt Sun Oct 15 21:34:59 2000 @@ -140,7 +140,7 @@ THE KIND OF CVF I SUPPORT". The function must maintain the module usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning and MOD_DEC_USE_COUNT at the end. The function *must not* assume that - successful recongition would lead to a call of the mount_cvf function + successful recognition would lead to a call of the mount_cvf function later. - mount_cvf: A function that sets up some values or initializes something additional diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/filesystems/ufs.txt linux/Documentation/filesystems/ufs.txt --- v2.2.17/Documentation/filesystems/ufs.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/filesystems/ufs.txt Sun Oct 15 21:34:59 2000 @@ -9,7 +9,7 @@ ufstype=type_of_ufs UFS is a file system widely used in different operating systems. - The problem are differencies among implementations. Features of + The problem are differences among implementations. Features of some implementations are undocumented, so its hard to recognize type of ufs automatically. That's why user must specify type of ufs manually by mount option ufstype. Possible values are: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.2.17/Documentation/ioctl-number.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/ioctl-number.txt Fri Sep 15 22:44:39 2000 @@ -85,6 +85,7 @@ 'W' 20-27 linux/octal-relay.h in development 'W' 28-2F linux/iso16-relay.h in development 'Y' all linux/cyclades.h +'Z' all linux/drivers/scsi/cpqfcTSioctl.h 'a' all various, see http://lrcwww.epfl.ch/linux-atm/magic.html 'b' 00-FF bit3 vme host bridge in development: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/00-INDEX linux/Documentation/isdn/00-INDEX --- v2.2.17/Documentation/isdn/00-INDEX Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/00-INDEX Sun Oct 15 21:38:02 2000 @@ -31,7 +31,7 @@ README.eicon - info on driver for Eicon active cards. README.concap - - info on "CONCAP" ecapsulation protocol interface used for X.25. + - info on "CONCAP" encapsulation protocol interface used for X.25. README.diversion - info on module for isdn diversion services. README.sc diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/INTERFACE.fax linux/Documentation/isdn/INTERFACE.fax --- v2.2.17/Documentation/isdn/INTERFACE.fax Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/INTERFACE.fax Sat Nov 18 00:55:28 2000 @@ -1,10 +1,10 @@ -$Id: INTERFACE.fax,v 1.1 1999/08/11 20:30:28 armin Exp $ +$Id: INTERFACE.fax,v 1.2 2000/08/06 09:22:50 armin Exp $ Description of the fax-subinterface between linklevel and hardwarelevel of isdn4linux. - The communication between linklevel (LL) and harwarelevel (HL) for fax + The communication between linklevel (LL) and hardwarelevel (HL) for fax is based on the struct T30_s (defined in isdnif.h). This struct is allocated in the LL. In order to use fax, the LL provides the pointer to this struct with the @@ -60,7 +60,7 @@ depending on progress and type of connection. If the phase changes because of an AT command, the LL driver changes this value. Otherwise the HL-driver takes care of it, but - only neccessary on call establishment (from IDLE to PHASE_A). + only necessary on call establishment (from IDLE to PHASE_A). (one of the constants ISDN_FAX_PHASE_[IDLE,A,B,C,D,E]) - direction diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README linux/Documentation/isdn/README --- v2.2.17/Documentation/isdn/README Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README Sat Nov 18 00:55:28 2000 @@ -146,7 +146,7 @@ x = 38400: 198 Note on value in Reg 19: There is _NO_ common convention for 38400 baud. - The value 198 is choosen arbitrarily. Users + The value 198 is chosen arbitrarily. Users _MUST_ negotiate this value before establishing a connection. AT&Sx Set window-size (x = 1..8) (not yet implemented) @@ -242,7 +242,7 @@ 0 = transparent 1 = transparent with audio features (e.g. DSP) 2 = Fax G3 Class 2 commands (S14 has to be set to 11) - 2 = Fax G3 Class 1 commands (S14 has to be set to 11) + 3 = Fax G3 Class 1 commands (S14 has to be set to 11) 16 250 Send-Packet-size/16 17 8 Window-size (not yet implemented) 18 4 Bit coded register, Service-Octet-1 to accept, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.2.17/Documentation/isdn/README.HiSax Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README.HiSax Sun Oct 15 21:38:02 2000 @@ -77,7 +77,7 @@ If you know other passive cards with the Siemens chipset, please let me know. To use the PNP cards you need the isapnptools. -You can combine any card, if there is no conflict between the ressources +You can combine any card, if there is no conflict between the resources (io, mem, irq). @@ -532,7 +532,7 @@ /sbin/isdnctrl huptimeout isdn0 0 /sbin/isdnctrl l2_prot isdn0 hdlc # Attention you must not set an outgoing number !!! This won't work !!! - # The incomming number is LEASED0 for the first card, LEASED1 for the + # The incoming number is LEASED0 for the first card, LEASED1 for the # second and so on. /sbin/isdnctrl addphone isdn0 in LEASED0 # Here is no need to bind the channel. @@ -551,7 +551,7 @@ Here an example script: #!/bin/sh -# Start/Stop ISDN lesaed line connection +# Start/Stop ISDN leased line connection I4L_AS_MODULE=yes I4L_REMOTE_IS_CISCO=no diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README.act2000 linux/Documentation/isdn/README.act2000 --- v2.2.17/Documentation/isdn/README.act2000 Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README.act2000 Sat Sep 23 13:15:35 2000 @@ -1,4 +1,4 @@ -$Id: README.act2000,v 1.2 1998/04/29 19:49:06 he Exp $ +$Id: README.act2000,v 1.3 2000/08/06 09:22:51 armin Exp $ This document describes the ACT2000 driver for the IBM Active 2000 ISDN card. @@ -7,7 +7,7 @@ Version. Currently, only the ISA-Bus version of the card is supported. However MCA and PCMCIA will follow soon. -The ISA-Bus Version uses 8 IO-ports. The base port adress has to be set +The ISA-Bus Version uses 8 IO-ports. The base port address has to be set manually using the DIP switches. Setting up the DIP switches for the IBM Active 2000 ISDN card: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README.avmb1 linux/Documentation/isdn/README.avmb1 --- v2.2.17/Documentation/isdn/README.avmb1 Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README.avmb1 Sat Sep 23 13:15:35 2000 @@ -175,7 +175,7 @@ subscribe linux-avmb1 in the body. -German documentaion and several scripts can be found at +German documentation and several scripts can be found at ftp://ftp.avm.de/cardware/b1/linux/ Bugs diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README.concap linux/Documentation/isdn/README.concap --- v2.2.17/Documentation/isdn/README.concap Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README.concap Sat Sep 23 13:15:35 2000 @@ -68,7 +68,7 @@ Likewise, a similar encapsulation protocol will frequently be needed by several different interfaces of even different hardware type, e.g. the synchronous ppp implementation used by the isdn driver and the -asyncronous ppp implementation used by the ppp driver have a lot of +asynchronous ppp implementation used by the ppp driver have a lot of similar code in them. By cleanly separating the encapsulation protocol from the hardware specific interface stuff such code could be shared better in future. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README.diversion linux/Documentation/isdn/README.diversion --- v2.2.17/Documentation/isdn/README.diversion Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README.diversion Sat Sep 23 13:15:35 2000 @@ -57,7 +57,7 @@ compared to the mechanism of ipfwadm or ipchains. If a given rule matches the checking process is finished and the rule matching will be applied to the call. - The rules include primary and secondary service indentifiers, called + The rules include primary and secondary service identifiers, called number and subaddress, callers number and subaddress and whether the rule matches to all filtered calls or only those when all B-channel resources are exhausted. @@ -82,7 +82,7 @@ available in some countries (for example germany). Countries requiring the keypad protocol for activating static diversions (like the netherlands) are not supported but may use the tty devices for this purpose. - The dynamic diversion servives may be used in all countries if the provider + The dynamic diversion services may be used in all countries if the provider enables the feature CF (call forwarding). This should work on both MSN- and point-to-point lines. To add and delete rules the additional divertctrl program is needed. This diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README.icn linux/Documentation/isdn/README.icn --- v2.2.17/Documentation/isdn/README.icn Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README.icn Sat Sep 23 13:15:35 2000 @@ -1,4 +1,4 @@ -$Id: README.icn,v 1.6 1998/04/29 19:49:08 he Exp $ +$Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $ You can get the ICN-ISDN-card from: @@ -139,7 +139,7 @@ To load a 4B-card, the same command is used, except a second firmware file is appended to the commandline of icnctrl. - -> After dowloading firmware, the two LEDs at the back cover of the card + -> After downloading firmware, the two LEDs at the back cover of the card (ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection is up, the corresponding led is lit continuously. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/isdn/README.sc linux/Documentation/isdn/README.sc --- v2.2.17/Documentation/isdn/README.sc Fri Apr 21 12:45:49 2000 +++ linux/Documentation/isdn/README.sc Sun Oct 15 21:38:02 2000 @@ -93,7 +93,7 @@ this driver release? Before you can compile, install and use the SpellCaster ISA ISDN driver, you -must ensure that the following software is installed, configuraed and running: +must ensure that the following software is installed, configured and running: - Linux kernel 2.0.20 or later with the required init and ps versions. Please see your distribution vendor for the correct @@ -189,7 +189,7 @@ basic HDLC connection between its two channels. Two network interfaces are created and two routes added between the channels. - i) using the isdnctrl utitity, add an interface with "addif" and + i) using the isdnctrl utility, add an interface with "addif" and name it "isdn0" ii) add the outgoing and inbound telephone numbers iii) set the Layer 2 protocol to hdlc @@ -213,7 +213,7 @@ This file is a script used to configure a BRI ISDN TA to establish a PPP connection between the two channels. The file is almost identical to the HDLC connection example except that the packet - ecapsulation type has to be set. + encapsulation type has to be set. use the same procedure as in the HDLC connection from steps i) to iii) then, after the Layer 2 protocol is set, set the encapsulation @@ -238,7 +238,7 @@ This file is a script used to configure a BRI ISDN TA to accept a Multi Link PPP connection. - i) using the isdnctrl utitity, add an interface with "addif" and + i) using the isdnctrl utility, add an interface with "addif" and name it "ippp0" ii) add the inbound telephone number iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/joystick-api.txt linux/Documentation/joystick-api.txt --- v2.2.17/Documentation/joystick-api.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/joystick-api.txt Sun Oct 15 21:38:02 2000 @@ -29,13 +29,13 @@ where js_event is defined as struct js_event { - __u32 time; /* event timestamp in miliseconds */ + __u32 time; /* event timestamp in milliseconds */ __s16 value; /* value */ __u8 type; /* event type */ __u8 number; /* axis/button number */ }; -If the read is successfull, it will return sizeof(struct js_event), unless +If the read is successful, it will return sizeof(struct js_event), unless you wanted to read more than one event per read as described in section 3.1. @@ -225,7 +225,7 @@ ~~~~~~~~~~~~~~ JSIOCGNAME(len) allows you to get the name string of the joystick - the same -as is being printed at boot time. The 'len' argument is the lenght of the +as is being printed at boot time. The 'len' argument is the length of the buffer provided by the application asking for the name. It is used to avoid possible overrun should the name be too long. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/joystick-parport.txt linux/Documentation/joystick-parport.txt --- v2.2.17/Documentation/joystick-parport.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/joystick-parport.txt Sun Oct 15 21:38:02 2000 @@ -22,7 +22,7 @@ 2. Devices supported ~~~~~~~~~~~~~~~~~~~~ - Many console and 8-bit coputer gamepads and joysticks are supported. The + Many console and 8-bit computer gamepads and joysticks are supported. The following subsections discuss usage of each. 2.1 NES and SNES diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/kbuild/commands.txt linux/Documentation/kbuild/commands.txt --- v2.2.17/Documentation/kbuild/commands.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/kbuild/commands.txt Sun Oct 15 21:38:02 2000 @@ -84,7 +84,7 @@ occasionally. If you are adding configuration options, it's nice if you do it before you publish your patch! - You can run 'make checkhelp' withoug configuring the kernel. + You can run 'make checkhelp' without configuring the kernel. Also, 'make checkhelp' does not modify any files. make dep, make depend diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/kbuild/config-language.txt linux/Documentation/kbuild/config-language.txt --- v2.2.17/Documentation/kbuild/config-language.txt Sun Jun 11 21:44:08 2000 +++ linux/Documentation/kbuild/config-language.txt Sun Oct 15 21:38:02 2000 @@ -80,7 +80,7 @@ A /word/ is a single unquoted word, a single-quoted string, or a double-quoted string. If the word is unquoted or double quoted, - then $-substition will be performed on the word. + then $-substitution will be performed on the word. A /symbol/ is a single unquoted word. A symbol must have a name of the form CONFIG_*. scripts/mkdep.c relies on this convention in order @@ -231,7 +231,7 @@ trying to write Config Language scripts with a default value for bool, but *all* of the existing language interpreters discard additional values. Feel free to submit a multi-interpreter patch to linux-kbuild if you -want to implement this as an enhancment. +want to implement this as an enhancement. Configure: implemented Menuconfig: implemented diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/mkdev.cciss linux/Documentation/mkdev.cciss --- v2.2.17/Documentation/mkdev.cciss Thu Jan 1 01:00:00 1970 +++ linux/Documentation/mkdev.cciss Fri Sep 1 13:32:52 2000 @@ -0,0 +1,40 @@ +#!/bin/sh +# Script to create device nodes for SMART array controllers +# Usage: +# mkdev.cciss [num controllers] [num log volumes] [num partitions] +# +# With no arguments, the script assumes 1 controller, 16 logical volumes, +# and 16 partitions/volume, which is adequate for most configurations. +# +# If you had 5 controllers and were planning on no more than 4 logical volumes +# each, using a maximum of 8 partitions per volume, you could say: +# +# mkdev.cciss 5 4 8 +# +# Of course, this has no real benefit over "mkdev.cciss 5" except that it +# doesn't create so many device nodes in /dev/cciss. + +NR_CTLR=${1-1} +NR_VOL=${2-16} +NR_PART=${3-16} + +if [ ! -d /dev/cciss ]; then + mkdir -p /dev/cciss +fi + +C=0; while [ $C -lt $NR_CTLR ]; do + MAJ=`expr $C + 104` + D=0; while [ $D -lt $NR_VOL ]; do + P=0; while [ $P -lt $NR_PART ]; do + MIN=`expr $D \* 16 + $P` + if [ $P -eq 0 ]; then + mknod /dev/cciss/c${C}d${D} b $MAJ $MIN + else + mknod /dev/cciss/c${C}d${D}p${P} b $MAJ $MIN + fi + P=`expr $P + 1` + done + D=`expr $D + 1` + done + C=`expr $C + 1` +done diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/modules.txt linux/Documentation/modules.txt --- v2.2.17/Documentation/modules.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/modules.txt Thu Aug 31 15:02:02 2000 @@ -124,7 +124,7 @@ To use modprobe successfully, you generally place the following command in your /etc/rc.d/rc.S script. (Read more about this in the -"rc.hints" file in the module utilities package, "modules-x.y.z.tar.gz".) +"rc.hints" file in the module utilities package, "modutils-x.y.z.tar.gz".) /sbin/depmod -a diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/moxa-smartio linux/Documentation/moxa-smartio --- v2.2.17/Documentation/moxa-smartio Fri Apr 21 12:45:49 2000 +++ linux/Documentation/moxa-smartio Sun Oct 15 21:38:02 2000 @@ -23,7 +23,7 @@ -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 + contributed driver code and merged into Linux 2.2.14pre. In particular official major/minor numbers have been assigned which are different to those the original Moxa supplied driver used. @@ -83,7 +83,7 @@ PCI board --------- - You may need to adjust IRQ useage in BIOS to avoid from IRQ conflict + You may need to adjust IRQ usage in BIOS to avoid from IRQ conflict with other ISA devices. Please refer to hardware installation procedure in User's Manual in advance. @@ -150,7 +150,7 @@ # insmod mxser - to activate the moduler driver. You may run "lsmod" to check + to activate the modular driver. You may run "lsmod" to check if "mxser.o" is activated. 2. Create special files by executing "msmknod". @@ -158,7 +158,7 @@ # ./msmknod Default major numbers for dial-in device and callout device are - 174, 175. Msmknod will delete any special files occuping the same + 174, 175. Msmknod will delete any special files occupying the same device naming. 3. Up to now, you may manually execute "insmod mxser" to activate @@ -209,7 +209,7 @@ below. a. # cd /moxa/mxser/driver # vi mxser.c - b. Find the array mxserBoardCAP[] as belows. + b. Find the array mxserBoardCAP[] as below. static int mxserBoardCAP[] = {0x00, 0x00, 0x00, 0x00}; @@ -260,7 +260,7 @@ 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 + check /etc/lilo.conf 'image' item specified the path which is the 'vmlinuz' path, or you will load wrong (or old) boot kernel image (vmlinuz). h. chmod 400 /vmlinuz @@ -372,7 +372,7 @@ ----------------------------------------------------------------------------- 6. Troubleshooting - The boot time error mesages and solutions are stated as clearly as + The boot time error messages and solutions are stated as clearly as possible. If all the possible solutions fail, please contact our technical support team to get more help. @@ -388,7 +388,7 @@ 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. + Error msg: Board #: C1xx Series(CAP=xxx) interrupt 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. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/README.sb1000 linux/Documentation/networking/README.sb1000 --- v2.2.17/Documentation/networking/README.sb1000 Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/README.sb1000 Sun Oct 15 21:38:02 2000 @@ -30,7 +30,7 @@ http://home.adelphia.net/~siglercm/sb1000.html http://linuxpower.cx/~cable/ - along with these utilties. + along with these utilities. 3.) The standard isapnp tools. These are necessary to configure your SB1000 card at boot time (or afterwards by hand) since it's a PnP card. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/README.xpeed linux/Documentation/networking/README.xpeed --- v2.2.17/Documentation/networking/README.xpeed Thu Jan 1 01:00:00 1970 +++ linux/Documentation/networking/README.xpeed Sun Oct 15 21:57:14 2000 @@ -0,0 +1,52 @@ +Driver for Xpeed Inc. PCI network cards +--------------------------------------- +The following cards are supported with this driver: + +Xpeed X200 IDSL NIC (http://www.xpeed.com/Products/x200/x200_c.html) +Xpeed X300 SDSL NIC (http://www.xpeed.com/Products/x300/x300_c.html) + +This driver handles frame relay encapsulation of WAN link and presents +the card to the kernel as an ethernet-like device called dsl0, dsl1, etc. + +The driver supports up to 6 cards and supports operation in either +RFC1490 frame relay or bridged ethernet modes. Note that when operating +in RFC1490 frame relay mode, "ifconfig -arp" (no ARP) should be used. + +=============================== NOTE ==================================== +You will NEED to use the xpds-config utility to configure the link speed, +change LT/NT mode, change swap/invert parameters, and reflash the adapter +firmware. This utility and other support files can be downloaded at +ftp://ftp.xpeed.com/pub/linux/ +=============================== NOTE ==================================== + +The driver accepts the following parameters when compiled as a module: + +xpds_default_dlci + Defines the DLCI to be used for the local interface. Default is 16. + +xpds_default_dlci_cr + A special mask value to be used when speaking with certain buggy + vendor equipment. Can be 0 or 2. Default is 0. + +xpds_default_dlci_lmi + Defines how the card will perform LMI protocol negotiation. + Valid values are: + 0 No LMI will be used. + 1 LMI will operate in LT (Line Termination) mode. + 2 LMI will operate in NT (Network Termination) mode. + 3 LMI will operation in bidirectional NT mode. + -1 Attempt to autoconfigure LMI mode. (Default) + +xpds_default_bridged + Defines whether the card will operate in RFC1490 frame relay or + bridged ethernet mode. Default is 0, RFC1490 frame relay mode. + +Typical usage for a connection in RFC1490 frame relay mode: + +# modprobe xpds-fr +# ifconfig dsl0 10.0.0.2 netmask 255.255.255.0 broadcast 10.0.0.255 -arp + +Typical usage for a connection in bridged ethernet mode: + +# modprobe xpds-fr xpds_default_bridged=1 +# ifconfig dsl0 10.0.0.2 netmask 255.255.255.0 broadcast 10.0.0.255 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/comx.txt linux/Documentation/networking/comx.txt --- v2.2.17/Documentation/networking/comx.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/comx.txt Sun Oct 15 21:38:02 2000 @@ -63,7 +63,7 @@ When you're ready with filling in the files in the comx[n] directory, you can configure the corresponding network interface with the standard network -configuration utilites. If you're unble to bring the interfaces up, look up +configuration utilities. If you're unable to bring the interfaces up, look up the various kernel log files on your system, and consult the messages for a probable reason. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/dmfe.txt linux/Documentation/networking/dmfe.txt --- v2.2.17/Documentation/networking/dmfe.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/dmfe.txt Sun Oct 15 21:38:02 2000 @@ -29,7 +29,7 @@ /net/inet -Wall -Wstrict-prototypes -O6 -c dmfe.c" - B. The following steps teach you how to active DM9102 board: + B. The following steps teach you how to activate a DM9102 board: 1. Used the upper compiler command to compile dmfe.c @@ -44,13 +44,13 @@ "ifconfig eth0 172.22.3.18" ^^^^^^^^^^^ Your IP address - 4. Active the IP routing table. For some distributions, it is not + 4. Activate the IP routing table. For some distributions, it is not necessary. You can type "route" to check. "route add default eth0" - 5. Well done. Your DM9102 adapter actived now. + 5. Well done. Your DM9102 adapter is now activated. C. Object files description: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/olympic.txt linux/Documentation/networking/olympic.txt --- v2.2.17/Documentation/networking/olympic.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/olympic.txt Sun Oct 15 21:38:02 2000 @@ -38,14 +38,14 @@ message_level: Controls level of messages created by the driver. Defaults to 0: which only displays start-up and critical messages. Presently any non-zero value will display all soft messages as well. NB This does not turn -debuging messages on, that must be done by modified the source code. +debugging messages on, that must be done by modified the source code. Multi-card: The driver will detect multiple cards and will work with shared interrupts, each card is assigned the next token ring device, i.e. tr0 , tr1, tr2. The driver should also happily reside in the system with other drivers. It has -been tested with ibmtr.c running, and I personnally have had one Olicom PCI +been tested with ibmtr.c running, and I personally have had one Olicom PCI card and two IBM olympic cards (all on the same interrupt), all running together. @@ -68,7 +68,7 @@ by the driver and the source and destination addresses printed. Also an entry will be added in /proc/net called olympic_tr. This displays low level information about the configuration of the ring and -the adapter. This feature has been designed for network adiministrators +the adapter. This feature has been designed for network administrators to assist in the diagnosis of network / ring problems. 6/8/99 Peter De Schrijver and Mike Phillips diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/shaper.txt linux/Documentation/networking/shaper.txt --- v2.2.17/Documentation/networking/shaper.txt Sun Jun 11 21:44:08 2000 +++ linux/Documentation/networking/shaper.txt Sun Oct 15 21:38:02 2000 @@ -42,7 +42,7 @@ There is no "borrowing" or "sharing" scheme. This is a simple traffic limiter. We implement Van Jacobson and Sally Floyd's CBQ -architecture into Linux 2.2. THis is the preferred solution. Shaper is +architecture into Linux 2.2. This is the preferred solution. Shaper is for simple or back compatible setups. Alan diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/sis900.txt linux/Documentation/networking/sis900.txt --- v2.2.17/Documentation/networking/sis900.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/sis900.txt Sun Oct 15 21:38:03 2000 @@ -161,7 +161,7 @@ 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 + the usual 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 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/sk98lin.txt linux/Documentation/networking/sk98lin.txt --- v2.2.17/Documentation/networking/sk98lin.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/sk98lin.txt Sun Oct 15 21:38:03 2000 @@ -138,7 +138,7 @@ options sk98lin ... For "...", use the same syntax as described below for the command -line paramaters of insmod. +line parameters 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: @@ -187,7 +187,7 @@ 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 + It is useful if your link partner does not support all possible combinations. - Flow Control @@ -269,7 +269,7 @@ 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. +transferring 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: @@ -285,7 +285,7 @@ You can switch back to the standard ethernet frame size with: ifconfig eth0 mtu 1500 -To make this setting persitent, add a script with the 'ifconfig' +To make this setting persistent, add a script with the 'ifconfig' line to the system startup sequence (named something like "S99sk98lin" in /etc/rc.d/rc2.d). *** diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/skfp.txt linux/Documentation/networking/skfp.txt --- v2.2.17/Documentation/networking/skfp.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/networking/skfp.txt Fri Sep 1 13:48:23 2000 @@ -0,0 +1,224 @@ +(C)Copyright 1998-2000 SysKonnect, +=========================================================================== + +skfp.txt created 17-Jul-2000 + +Readme File for skfp.o v2.07 + + +This file contains +(1) OVERVIEW +(2) SUPPORTED ADAPTERS +(3) GENERAL INFORMATION +(4) INSTALLATION +(5) INCLUSION OF THE ADAPTER IN SYSTEM START +(6) TROUBLESHOOTING +(7) FUNCTION OF THE ADAPTER LEDS +(8) HISTORY + +=========================================================================== + + + +(1) OVERVIEW +============ + +This README explains how to use the driver 'skfp' for Linux with your +network adapter. + +Chapter 2: Contains a list of all network adapters that are supported by + this driver. + +Chapter 3: Gives some general information. + +Chapter 4: Describes common problems and solutions. + +Chapter 5: Shows the changed functionality of the adapter LEDs. + +Chapter 6: History of development. + +*** + + +(2) SUPPORTED ADAPTERS +====================== + +The network driver 'skfp' supports the following network adapters: +SysKonnect adapters: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) +Compaq adapters (not tested): + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC +*** + + +(3) GENERAL INFORMATION +======================= + +From v2.01 on, the driver is integrated in the linux kernel sources. +Therefor, the installation is the same as for any other adapter +supported by the kernel. +Refer to the manual of your distribution about the installation +of network adapters. +Makes my life much easier :-) +*** + + +(4) TROUBLESHOOTING +=================== + +If you run into problems during installation, check those items: + +Problem: The FDDI adapter can not be found by the driver. +Reason: Look in /proc/pci for the following entry: + 'FDDI network controller: SysKonnect SK-FDDI-PCI ...' + If this entry exists, then the FDDI 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') and no workaround is available. + +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. + +If your problem is not listed here, please contact our +technical support for help. +You can send email to: + 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 + +*** + + +(5) FUNCTION OF THE ADAPTER LEDS +================================ + + The functionality of the LED's on the FDDI network adapters was + changed in SMT version v2.82. With this new SMT version, the yellow + LED works as a ring operational indicator. An active yellow LED + indicates that the ring is down. The green LED on the adapter now + works as a link indicator where an active GREEN LED indicates that + the respective port has a physical connection. + + With versions of SMT prior to v2.82 a ring up was indicated if the + yellow LED was off while the green LED(s) showed the connection + status of the adapter. During a ring down the green LED was off and + the yellow LED was on. + + All implementations indicate that a driver is not loaded if + all LEDs are off. + +*** + + +(6) HISTORY +=========== + +v2.07 (20000717) (In-Kernel version) + New features: + - in kernel 2.2.17 (hopefully !) + +v2.06 (20000511) (In-Kernel version) + New features: + - 64 bit support + - new pci dma interface + - in kernel 2.3.99 + +v2.05 (20000217) (In-Kernel version) + New features: + - Changes for 2.3.45 kernel + +v2.04 (20000207) (Standalone version) + New features: + - Added rx/tx byte counter + +v2.03 (20000111) (Standalone version) + Problems fixed: + - Fixed printk statements from v2.02 + +v2.02 (991215) (Standalone version) + Problems fixed: + - Removed unnecessary output + - Fixed path for "printver.sh" in makefile + +v2.01 (991122) + New features: + - Integration in Linux kernel sources + - Support for memory mapped I/O + +v2.00 (991112) + New features: + - Full source released under GPL + +v1.05 (991023) + Problems fixed: + - Compilation with kernel version 2.2.13 failed + +v1.04 (990427) + Changes: + - New SMT module included, changing LED functionality + Problems fixed: + - Synchronization on SMP machines was buggy + +v1.03 (990325) + Problems fixed: + - Interrupt routing on SMP machines could be incorrect + +v1.02 (990310) + New features: + - Support for kernel versions 2.2.x added + - Kernel patch instead of private duplicate of kernel functions + +v1.01 (980812) + Problems fixed: + Connection hangup with telnet + Slow telnet connection + +v1.00 beta 01 (980507) + New features: + None. + Problems fixed: + None. + Known limitations: + - tar archive instead of standard package format (rpm). + - FDDI statistic is empty. + - not tested with 2.1.xx kernels + - integration in kernel not tested + - not tested simultaneously with FDDI adapters from other vendors. + - only X86 processors supported. + - SBA (Synchronous Bandwidth Allocator) parameters can + not be configured. + - does not work on some COMPAQ machines. See the PCI howto + document for details about this problem. + - data corruption with kernel versions below 2.0.33. + +*** End of information file *** diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/tlan.txt linux/Documentation/networking/tlan.txt --- v2.2.17/Documentation/networking/tlan.txt Sat Sep 9 18:42:32 2000 +++ linux/Documentation/networking/tlan.txt Sun Oct 15 21:38:03 2000 @@ -44,7 +44,7 @@ 0x01 Turn on general debugging messages. 0x02 Turn on receive debugging messages. 0x04 Turn on transmit debugging messages. - 0x08 Turn on list debugging messsages. + 0x08 Turn on list debugging messages. 2. You can append aui=1 to the end of the insmod line to cause the adapter to use the AUI interface instead of the 10 Base T diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt --- v2.2.17/Documentation/networking/wan-router.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/wan-router.txt Sun Oct 15 21:38:03 2000 @@ -142,11 +142,11 @@ 2.0.8 Nov 02, 1999 - Fixed up the X25API code. - Clear call bug fixed.i - - Eanbled driver for multi-card + - Enabled driver for multi-card operation. 2.0.7 Aug 26, 1999 - Merged X25API code into WANPIPE. - - Fixed a memeory leak for X25API + - Fixed a memory leak for X25API - Updated the X25API code for 2.2.X kernels. - Improved NEM handling. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/wanpipe.txt linux/Documentation/networking/wanpipe.txt --- v2.2.17/Documentation/networking/wanpipe.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/wanpipe.txt Sun Oct 15 21:38:03 2000 @@ -228,7 +228,7 @@ creating applications using BiSync streaming. -2.0.5 Aug 04, 1999 CHDLC initializatin bug fix. +2.0.5 Aug 04, 1999 CHDLC initialization bug fix. PPP interrupt driven driver: Fix to the PPP line hangup problem. New PPP firmware @@ -241,13 +241,13 @@ Streaming HDLC API has been taken out. Available as a patch. -2.0.6 Aug 17, 1999 Increased debugging in statup scripts - Fixed insallation bugs from 2.0.5 +2.0.6 Aug 17, 1999 Increased debugging in startup scripts + Fixed installation bugs from 2.0.5 Kernel patch works for both 2.2.10 and 2.2.11 kernels. There is no functional difference between the two packages 2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE. - o Fixed a memeory leak for X25API + o Fixed a memory leak for X25API o Updated the X25API code for 2.2.X kernels. o Improved NEM handling. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/networking/z8530drv.txt linux/Documentation/networking/z8530drv.txt --- v2.2.17/Documentation/networking/z8530drv.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/networking/z8530drv.txt Thu Oct 19 01:28:39 2000 @@ -4,17 +4,14 @@ Internet: ========= -1. ftp://ftp.ccac.rwth-aachen.de/pub/jr/z8530drv-utils-3.0-1.tar.gz +1. ftp://ftp.ccac.rwth-aachen.de/pub/jr/z8530drv-utils_3.0-3.tar.gz -2. ftp://ftp.pspt.fi/pub/ham/linux/ax25/z8530drv-utils-3.0-1.tar.gz - -3. ftp://ftp.ucsd.edu/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz - If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz +2. ftp://ftp.pspt.fi/pub/ham/linux/ax25/z8530drv-utils_3.0-3.tar.gz Please note that the information in this document may be hopelessly outdated. A new version of the documentation, along with links to other important Linux Kernel AX.25 documentation and programs, is available on -http://www.rat.de/jr +http://yaina.de/jreuter ----------------------------------------------------------------------------- @@ -23,7 +20,7 @@ ******************************************************************** - (c) 1993,1998 by Joerg Reuter DL1BKE + (c) 1993,2000 by Joerg Reuter DL1BKE portions (c) 1993 Guido ten Dolle PE1NNZ @@ -650,11 +647,10 @@ Mysteriously this board seems not to work with the driver. Anyone got it up-and-running? - Many thanks to Linus Torvalds and Alan Cox for including the driver in the Linux standard distribution and their support. Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org - AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU - Internet: jreuter@poboxes.com - WWW : http://www.rat.de/jr/ + AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU + Internet: jreuter@yaina.de + WWW : http://yaina.de/jreuter diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/nmi_watchdog.txt linux/Documentation/nmi_watchdog.txt --- v2.2.17/Documentation/nmi_watchdog.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/nmi_watchdog.txt Tue Sep 12 11:51:04 2000 @@ -0,0 +1,34 @@ + +Is your SMP system locking up unpredictably? No keyboard activity, just +a frustrating complete hard lockup? Do you want to help us debugging +such lockups? If all yes then this document is definitely for you. + +on Intel SMP hardware there is a feature that enables us to generate +'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get +executed even if the system is otherwise locked up hard) This can be +used to debug hard kernel lockups. By executing periodic NMI interrupts, +the kernel can monitor wether any CPU has locked up, and print out +debugging messages if so. You can enable/disable the NMI watchdog at boot +time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant +lilo.conf entry: + + append="nmi_watchdog=1" + +A 'lockup' is the following scenario: if any CPU in the system does not +execute the period local timer interrupt for more than 5 seconds, then +the NMI handler generates an oops and kills the process. This +'controlled crash' (and the resulting kernel messages) can be used to +debug the lockup. Thus whenever the lockup happens, wait 5 seconds and +the oops will show up automatically. If the kernel produces no messages +then the system has crashed so hard (eg. hardware-wise) that either it +cannot even accept NMI interrupts, or the crash has made the kernel +unable to print messages. + +You can find NMI watchdog patch against Linux 2.2.x at +http://people.redhat.com/mingo/NMI-watchdog-patches/ + + +[ feel free to send bug reports, suggestions and patches to + Ingo Molnar or the Linux SMP mailing + list at ] + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/s390/DASD linux/Documentation/s390/DASD --- v2.2.17/Documentation/s390/DASD Fri Apr 21 12:45:49 2000 +++ linux/Documentation/s390/DASD Sun Oct 15 21:39:07 2000 @@ -30,7 +30,7 @@ We currently implement one partition per volume, which is the whole volume, skipping the first blocks up to the volume label. These are reserved for IPL records and IBM's volume label to assure -accessability of the DASD from other OSs. In a later stage we will +accessibility of the DASD from other OSs. In a later stage we will provide support of partitions, maybe VTOC oriented or using a kind of partition table in the label record. @@ -38,7 +38,7 @@ -Low-level format (?CKD only) For using an ECKD-DASD as a Linux harddisk you have to low-level -format the tracks by issueing the BLKDASDFORMAT-ioctl on that +format the tracks by issuing the BLKDASDFORMAT-ioctl on that device. This will erase any data on that volume including IBM volume labels, VTOCs etc. The ioctl may take a 'struct format_data *' or 'NULL' as an argument. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/s390/cds.txt linux/Documentation/s390/cds.txt --- v2.2.17/Documentation/s390/cds.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/s390/cds.txt Sun Oct 15 21:39:07 2000 @@ -778,7 +778,7 @@ The halt_IO() function returns : 0 - successful completion or request successfuly initiated --EBUSY - the device is currently performing a sysnchonous I/O +-EBUSY - the device is currently performing a synchronous I/O operation : do_IO() with flag DOIO_WAIT_FOR_INTERRUPT or an error was encountered and the device is currently be sensed diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/s390/xpram.txt linux/Documentation/s390/xpram.txt --- v2.2.17/Documentation/s390/xpram.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/s390/xpram.txt Wed Nov 8 23:09:58 2000 @@ -0,0 +1,133 @@ +XPRAM +===== + +The S/390 architecture supports more RAM than can be accessed as main memory. +The LINUX for S/390 main memory is limited to 2 GB. However, additional +memory can be declared as expanded storage. The S/390 architecture allows +applications to access up to 16 TB of expanded storage (although the current +hardware can only be equipped with up to 32 GB memory). Memory in the +expanded storage range can be copied in 4 KB blocks to, or from, the main +memory. + +An interesting feature of expanded storage is that is persistent with respect +to IPLs (booting) but volatile with respect to IMLs (power off/on). + +The XPRAM device driver is a block device driver that supports LINUX for S/390 +allowing it to access the expanded storage. Thus XPRAM can be used as a basis +for fast swap devices and/or fast file systems. + +Features +++++++++ +XPRAM automatically detects whether expanded storage is available on the +system. The expanded storage can be subdivided into up to 32 partitions, the +default being a single partition. The XPRAM device driver has major number 35. +The partitions have minor numbers 0 through 31. The hard sector size of XPRAM +is set to 4096 bytes. + +Limitations ++++++++++++ +If expanded storage is not available, XPRAM cannot be used. Its initialization +fails gracefully with a log message reporting the lack of expanded storage. + +Configuration option +++++++++++++++++++++ + +CONFIG_XPRAM + +Module name ++++++++++++ + +XPRAM can be used as module. Its moduel name is xpram.o. + +Kernel parameter syntax ++++++++++++++++++++++++ +The kernel parameter is optional. The default defines the whole expanded +storage to be one partition. + +xpram_parts=[,[,...]] + +where defines how many partitions the expanded storage +is split into. The i-th defines the size of the i-th +partition. + +The syntax for sizes is: + +[0x][k|K|m|M|g|G] + +If the 0x prefix is used the subsequent number is interpreted as a hexadecimal +value, otherwise it is interpreted as a decimal value (default). The +non-negative_integer value may be followed by a magnitude: + +- k or K for kilo (1024) is the default +- m or M for Mega (1024*1024) +- g or G for Giga (1024*1024*1024) + +The value multiplied by its magnitude defines the +partition's size in bytes. The default size is 0. + +Any partition defined with a non-zero size is allocated the amount of memory +specified by its non-negative_integer parameter. + +You can automatically allocate the remaining memory between a set of partitions +by specifying zero for the size of each partition in the set. The following +formula is used to calculate the size for each of these partitions: + + (available exp. storage - sum of all non-zero sizes specified) +computed size = -------------------------------------------------------------- + number of partitions with zero sizes + +This formula is only a good approximation of the actual size allocated to each +partition. Because of the requirement to assign blocks in multiples of 4K, +partitions can be larger or smaller than the estimate produced by the +calculation. In addition, there might be an amount of memory left as a "guard +space" between two partitions. + +Example +------- + +xpram_parts=4,0x800M,0,0,0x1000M + +This allocates the extended storage into four partitions. Partition 1 has 2 GB, +partition 4 has x 4 GB, and partitions 2 and 3 use equal parts of the remaining +storage. If the total amount of extended storage was 16 GB, then partitions 3 +and 4 would each have approximately 5 GB. + +Module parameter syntax ++++++++++++++++++++++++ +XPRAM may be used as module. The syntax of the module parameters passed to +insmod differs from the kernel parameter syntax: + +[devs= [sizes=[,,...]]] + +where: +- number_of_devices is used to define the number of partitions. +- size is a non-negative integer that defines the partition's size. + Only decimal values are allowed and no magnitudes are accepted. + The size will be interpretedin KB. + +Example +------- + +devs=4 sizes=2097152,8388608,4194304,2097152 + +This allocates a total of 16 GB of extended storage into four partitions, of +(respectively) size 2 GB, 8 GB, 4 GB, and 2 GB. + +Usage ++++++ + +XPRAM is a block device driver with major 35. +Using the standard naming scheme (see devices.txt) the partitions of XPRAM +can be accessed through /dev/slram0, ... , /dev/slram31. + +XPRAM does not require any formatting. Partitioning is only possible during +device initialization by kernel or module parameters. Note that if both the +expanded storage and the partitioning parameters are left unchanged between +two device initializations (even if LINUX was IPLed in the meantime) then +XPRAM behaves like a persistent storage. This is not true if the system is +IMLed. + +You can make a files system on a XPRAM partition (e.g. mke2fs) with a block +size that is a multiple of 4096 byte and mount this file system. + +Alternativly an XPRAM partition can be used as a swap device (mkswap, swapon). \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/sound/ESS linux/Documentation/sound/ESS --- v2.2.17/Documentation/sound/ESS Fri Apr 21 12:45:49 2000 +++ linux/Documentation/sound/ESS Sun Oct 15 21:39:02 2000 @@ -12,7 +12,7 @@ master volume control. Every chip that's detected as a ES1887 now has Full Duplex support. Made a -little testprogram that showes that is works, haven't seen a real program that +little test program that shows that is works, haven't seen a real program that needs this however. For ESS chips an additional parameter "esstype" can be specified. This controls diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/sound/Introduction linux/Documentation/sound/Introduction --- v2.2.17/Documentation/sound/Introduction Fri Apr 21 12:45:49 2000 +++ linux/Documentation/sound/Introduction Sun Oct 15 21:39:02 2000 @@ -322,7 +322,7 @@ 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 +8) If the system reports insufficient DMA memory then you may want to load sound with the "dmabufs=1" option. Or in /etc/conf.modules add preinstall sound dmabufs=1 @@ -356,7 +356,7 @@ 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 +the driver for the sound system is loaded. It then will ask for sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and so on). Thus you can do diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/sound/Maestro linux/Documentation/sound/Maestro --- v2.2.17/Documentation/sound/Maestro Fri Apr 21 12:45:49 2000 +++ linux/Documentation/sound/Maestro Sun Oct 15 21:39:02 2000 @@ -70,7 +70,7 @@ 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 +system. Sometimes, 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 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/sound/PSS linux/Documentation/sound/PSS --- v2.2.17/Documentation/sound/PSS Fri Apr 21 12:45:49 2000 +++ linux/Documentation/sound/PSS Sun Oct 15 21:39:02 2000 @@ -3,7 +3,7 @@ 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 +If you build this driver as a module then the driver takes the following parameters pss_io. The I/O base the PSS card is configured at (normally 0x220 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/sound/README.OSS linux/Documentation/sound/README.OSS --- v2.2.17/Documentation/sound/README.OSS Fri Apr 21 12:45:49 2000 +++ linux/Documentation/sound/README.OSS Sun Oct 15 21:39:02 2000 @@ -81,7 +81,7 @@ Gregor Hoffleit Mozart support (initial version) Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support James Hightower Spotting a tiny but important bug in CS423x support. - Denis Sablic OPTi 82C924 spesific enhancements (non PnP mode) + Denis Sablic OPTi 82C924 specific enhancements (non PnP mode) Tim MacKenzie Full duplex support for OPTi 82C930. Please look at lowlevel/README for more contributors. @@ -542,7 +542,7 @@ There are also chips called OPL3-SA2, OPL3-SA3, ..., OPL3SA-N. They are PnP chips and will not work with the OPL3-SA1 driver. You should - use the standard MSS, MPU401 and OPL3 options with thses chips and to + use the standard MSS, MPU401 and OPL3 options with these chips and to activate the card using isapnptools. 4Front Technologies SoftOSS @@ -1309,7 +1309,7 @@ NOTE! ESS cards are not compatible with MSS/WSS so don't worry if MSS support of OSS doesn't work with it. -There are some ES1688/688 based sound cards and (particularily) motherboards +There are some ES1688/688 based sound cards and (particularly) motherboards which use software configurable I/O port relocation feature of the chip. This ESS proprietary feature is supported only by OSS/Linux. @@ -1319,7 +1319,7 @@ work. ES1868 is a PnP chip which is (supposed to be) compatible with ESS1688 -brobably works with OSS/Free after initialization using isapnptools. +probably works with OSS/Free after initialization using isapnptools. Reveal cards ------------ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/sound/README.modules linux/Documentation/sound/README.modules --- v2.2.17/Documentation/sound/README.modules Fri Apr 21 12:45:49 2000 +++ linux/Documentation/sound/README.modules Sun Oct 15 21:39:02 2000 @@ -71,7 +71,7 @@ The sound modules normally allocate DMA buffers during open() and deallocate them during close(). Linux can often have problems allocating DMA buffers for ISA cards on machines with more than 16MB RAM. This is -because ISA DMA buffers must exist below the 16MB boundry and it is quite +because ISA DMA buffers must exist below the 16MB boundary and it is quite possible that we can't find a large enough free block in this region after the machine has been running for any amount of time. The way to avoid this problem is to allocate the DMA buffers during module load and deallocate diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/stallion.txt linux/Documentation/stallion.txt --- v2.2.17/Documentation/stallion.txt Fri Apr 21 12:45:49 2000 +++ linux/Documentation/stallion.txt Sun Oct 15 21:39:02 2000 @@ -62,7 +62,7 @@ boards. There are two methods of configuring ISA, EISA and MCA boards into the drivers. -If using the driver as a loadable module then the simplist method is to pass +If using the driver as a loadable module then the simplest method is to pass the driver configuration as module arguments. The other method is to modify the driver source to add configuration lines for each board in use. @@ -108,7 +108,7 @@ where: - board? -- specifies the arbitary board number of this board, + board? -- specifies the arbitrary board number of this board, can be in the range 0 to 3. name -- textual name of this board. The board name is the comman diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt --- v2.2.17/Documentation/sysctl/vm.txt Sat Sep 9 18:42:32 2000 +++ linux/Documentation/sysctl/vm.txt Sun Oct 15 21:39:02 2000 @@ -118,11 +118,11 @@ reaches this number, only the kernel can allocate more memory. freepages.low If the number of free pages gets below this - point, the kernel starts swapping agressively. + point, the kernel starts swapping aggressively. freepages.high The kernel tries to keep up to this amount of memory free; if memory comes below this point, the kernel gently starts swapping in the hopes - that it never has to do real agressive swapping. + that it never has to do real aggressive swapping. ============================================================== @@ -198,7 +198,7 @@ - swap cache When your system is both deep in swap and high on cache, -it probably means that a lot of the swaped data is being +it probably means that a lot of the swapped data is being cached, making for more efficient swapping than possible with the 2.0 kernel. @@ -213,7 +213,7 @@ On a low-memory, single CPU system you can safely set these values to 0 so you don't waste the memory. On SMP systems it is used so that the system can do fast pagetable allocations -without having to aquire the kernel memory lock. +without having to acquire the kernel memory lock. For large systems, the settings are probably OK. For normal systems they won't hurt a bit. For small systems (<16MB ram) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/CREDITS linux/Documentation/usb/CREDITS --- v2.2.17/Documentation/usb/CREDITS Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/CREDITS Thu Sep 14 15:35:24 2000 @@ -0,0 +1,169 @@ +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 + Pavel Machek + Paul Mackerras + David E. Nelson + Vojtech Pavlik + Bill Ryder + 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 compliance 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 impossible to get a PC backplate USB connector + for the motherboard here at Europe (mine, home-made, was + quite lousy :). Now I know where to acquire 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 (competing 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 uncovering 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 advises! + + - 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/URB.txt linux/Documentation/usb/URB.txt --- v2.2.17/Documentation/usb/URB.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/URB.txt Thu Sep 14 15:35:24 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 continuous 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 implicit 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 (implicitly 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 continuous +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 continuous 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/acm.txt linux/Documentation/usb/acm.txt --- v2.2.17/Documentation/usb/acm.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/acm.txt Fri Sep 1 13:51:28 2000 @@ -0,0 +1,138 @@ + Linux ACM driver v0.16 + (c) 1999 Vojtech Pavlik + 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. Usage +~~~~~~~~ + The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal +adapters that conform to the Universal Serial Bus Communication Device Class +Abstract Control Model (USB CDC ACM) specification. + + Many modems do, here is a list of those I know of: + + 3Com OfficeConnect 56k + 3Com Voice FaxModem Pro + 3Com Sportster + MultiTech MultiModem 56k + Zoom 2986L FaxModem + Compaq 56k FaxModem + ELSA Microlink 56k + + I know of one ISDN TA that does work with the acm driver: + + 3Com USR ISDN Pro TA + + Unfortunately many modems and most ISDN TAs use proprietary interfaces and +thus won't work with this drivers. Check for ACM compliance before buying. + + The driver (with devfs) creates these devices in /dev/usb/acm: + + crw-r--r-- 1 root root 166, 0 Apr 1 10:49 0 + crw-r--r-- 1 root root 166, 1 Apr 1 10:49 1 + crw-r--r-- 1 root root 166, 2 Apr 1 10:49 2 + + And so on, up to 31, with the limit being possible to change in acm.c to up +to 256, so you can use up to 256 USB modems with one computer (you'll need +three USB cards for that, though). + + If you don't use devfs, then you can create device nodes with the same +minor/major numbers anywhere you want, but either the above location or +/dev/usb/ttyACM0 is preferred. + + To use the modems you need these modules loaded: + + usbcore.o + usb-[uo]hci.o or uhci.o + acm.o + + After that, the modem[s] should be accessible. You should be able to use +minicom, ppp and mgetty with them. + +2. Verifying that it works +~~~~~~~~~~~~~~~~~~~~~~~~~~ + The first step would be to check /proc/bus/usb/devices, it should look +like this: + +T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2 +B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0 +D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=0000 ProdID=0000 Rev= 0.00 +S: Product=USB UHCI Root Hub +S: SerialNumber=6800 +C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA +I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub +E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms +T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 +D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2 +P: Vendor=04c1 ProdID=008f Rev= 2.07 +S: Manufacturer=3Com Inc. +S: Product=3Com U.S. Robotics Pro ISDN TA +S: SerialNumber=UFT53A49BVT7 +C: #Ifs= 1 Cfg#= 1 Atr=60 MxPwr= 0mA +I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm +E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms +E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms +C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr= 0mA +I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms +I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm +E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms +E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms + +The presence of these three lines (and the Cls= 'comm' and 'data' classes) +is important, it means it's an ACM device. The Driver=acm means the acm +driver is used for the device. If you see only Cls=ff(vend.) then you're out +of luck, you have a device with vendor specific-interface. + +D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2 +I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm +I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm + +In the system log you should see: + +usb.c: USB new device connect, assigned device number 2 +usb.c: kmalloc IF c7691fa0, numif 1 +usb.c: kmalloc IF c7b5f3e0, numif 2 +usb.c: skipped 4 class/vendor specific interface descriptors +usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3 +usb.c: USB device number 2 default language ID 0x409 +Manufacturer: 3Com Inc. +Product: 3Com U.S. Robotics Pro ISDN TA +SerialNumber: UFT53A49BVT7 +acm.c: probing config 1 +acm.c: probing config 2 +ttyACM0: USB ACM device +acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0 +acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7 +usb.c: acm driver claimed interface c7b5f3e0 +usb.c: acm driver claimed interface c7b5f3f8 +usb.c: acm driver claimed interface c7691fa0 + +If all this seems to be OK, fire up minicom and set it to talk to the ttyACM +device and try typing 'at'. If it responds with 'OK', then everything is +working. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/bluetooth.txt linux/Documentation/usb/bluetooth.txt --- v2.2.17/Documentation/usb/bluetooth.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/bluetooth.txt Sat Oct 14 00:31:47 2000 @@ -0,0 +1,44 @@ +INTRODUCTION + + The USB Bluetooth driver supports any USB Bluetooth device. + It currently works well with the Linux USB Bluetooth stack from Axis + (available at http://developer.axis.com/software/bluetooth/ ) and + has been rumored to work with other Linux USB Bluetooth stacks. + + +CONFIGURATION + + Currently the driver can handle up to 256 different USB Bluetooth + devices at once. + + If you are not using devfs: + The major number that the driver uses is 216 so to use the driver, + create the following nodes: + mknod /dev/ttyUB0 c 216 0 + mknod /dev/ttyUB1 c 216 1 + mknod /dev/ttyUB2 c 216 2 + mknod /dev/ttyUB3 c 216 3 + . + . + . + mknod /dev/ttyUB254 c 216 254 + mknod /dev/ttyUB255 c 216 255 + + If you are using devfs: + The devices supported by this driver will show up as + /dev/usb/ttub/{0,1,...} + + When the device is connected and recognized by the driver, the driver + will print to the system log, which node the device has been bound to. + + +CONTACT: + + If anyone has any problems using this driver, 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/dc2xx.txt linux/Documentation/usb/dc2xx.txt --- v2.2.17/Documentation/usb/dc2xx.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/dc2xx.txt Fri Sep 1 13:51:28 2000 @@ -0,0 +1,111 @@ +14 April 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. There is a python script +for accessing these cameras (see archives of the linux-usb mailing list) +and a "Digita Services" library that can also use this driver. + +The HP PhotoSmart C500 should also work, since it's another Digita camera +with USB support. + + +USB HARDWARE + +Recent kernels have had no particular problems using this driver with +either OHCI or UHCI chipsets, and have worked on the PowerMac 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, and some old hardware may not handle USB correctly. + + +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 0660 /dev/usb/dc2xx0 c 180 80 + # mknod -m 0660 /dev/usb/dc2xx1 c 180 81 + ... + +NOTE: you would normally configure PAM so that the user logged in at +the console is granted ownership of these devices. console.perms(5) +explains how to do this. + +The driver supports multiple device nodes. The USB framework supports +a maximum of sixteen device nodes (up to minor device number 96). + +When you plug in one camera, it will use the first device node (dc2xx0 +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 and correctly mounted the + usbdevfs on /proc/bus/usb. + +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, as may the strings presented, but "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 + S: Manufacturer=Eastman Kodak Company + S: Product=KODAK DC240 Zoom Digital Camera + 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 + 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/usb/dc2xx0" + (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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/error-codes.txt linux/Documentation/usb/error-codes.txt --- v2.2.17/Documentation/usb/error-codes.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/error-codes.txt Fri Sep 1 13:51:28 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/ibmcam.txt linux/Documentation/usb/ibmcam.txt --- v2.2.17/Documentation/usb/ibmcam.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/ibmcam.txt Fri Sep 1 13:51:28 2000 @@ -0,0 +1,288 @@ +README for Linux device driver for the IBM "C-It" USB video camera + +INTRODUCTION: + +This driver does not use all features known to exist in +the IBM camera. However most of needed features work well. + +This driver was developed using logs of observed USB traffic +which was produced by standard Windows driver (c-it98.sys). +I did not have data sheets from Xirlink. + +Video formats: + 128x96 [model 1] + 176x144 + 320x240 [model 2] + 352x240 [model 2] + 352x288 +Frame rate: 3 - 30 frames per second (FPS) +External interface: USB +Internal interface: Video For Linux (V4L) +Supported controls: +- by V4L: Contrast, Brightness, Color, Hue +- by driver options: frame rate, lighting conditions, video format, + default picture settings, sharpness. + +SUPPORTED CAMERAS: + +IBM "C-It" camera, also known as "Xirlink PC Camera" +The device uses proprietary ASIC (and compression method); +it is manufactured by Xirlink. See http://www.xirlink.com/ +http://www.ibmpccamera.com or http://www.c-itnow.com/ for +details and pictures. + +The Linux driver was developed with camera with following +model number (or FCC ID): KSX-XVP510. This camera has three +interfaces, each with one endpoint (control, iso, iso). This +type of cameras is referred to as "model 1". These cameras are +no longer manufactured. + +Xirlink now manufactures new cameras which are somewhat different. +In particular, following models [FCC ID] belong to that category: + +XVP300 [KSX-X9903] +XVP600 [KSX-X9902] +XVP610 [KSX-X9902] + +(see http://www.xirlink.com/ibmpccamera/ for updates, they refer +to these new cameras by Windows driver dated 12-27-99, v3005 BETA) +These cameras have two interfaces, one endpoint in each (iso, bulk). +Such type of cameras is referred to as "model 2". They are supported +(with exception of 352x288 native mode). + +Quirks of Model 2 cameras: +------------------------- + +Model 2 does not have hardware contrast control. Corresponding V4L +control is not used at the moment. It may be possible to implement +contrast control in software, at cost of extra processor cycles. + +This driver provides 352x288 mode by switching the camera into +quasi-352x288 RGB mode (800 Kbits per frame) essentially limiting +this mode to 10 frames per second or less, in ideal conditions on +the bus (USB is shared, after all). The frame rate +has to be programmed very conservatively. Additional concern is that +frame rate depends on brightness setting; therefore the picture can +be good at one brightness and broken at another! I did not want to fix +the frame rate at slowest setting, but I had to move it pretty much down +the scale (so that framerate option barely matters). I also noticed that +camera after first powering up produces frames slightly faster than during +consecutive uses. All this means that if you use videosize=2 (which is +default), be warned - you may encounter broken picture on first connect; +try to adjust brightness - brighter image is slower, so USB will be able +to send all data. However if you regularly use Model 2 cameras you may +prefer videosize=1 which makes perfectly good I420, with no scaling and +lesser demands on USB (300 Kbits per second, or 26 frames per second). + +The camera that I had also has a hardware quirk: if disconnected, +it needs few minutes to "relax" before it can be plugged in again +(poorly designed USB processor reset circuit?) + +Model 2 camera can be programmed for very high sensitivity (even starlight +may be enough), this makes it convenient for tinkering with. The driver +code has enough comments to help a programmer to tweak the camera +as s/he feels necessary. + +WHAT YOU NEED: + +- A supported IBM PC (C-it) camera (model 1 or 2) + +- A Linux box with USB support (2.3/2.4; 2.2 w/backport may work) + +- A Video4Linux compatible frame grabber program such as xawtv. + +HOW TO COMPILE THE DRIVER: + +You need to compile the driver only if you are a developer +or if you want to make changes to the code. Most distributions +precompile all modules, so you can go directly to the next +section "HOW TO USE THE DRIVER". + +The driver consists of two files in usb/ directory: +ibmcam.c and ibmcam.h These files are included into the +Linux kernel build process if you configure the kernel +for CONFIG_USB_IBMCAM. Run "make xconfig" and in USB section +you will find the IBM camera driver. Select it, save the +configuration and recompile. + +HOW TO USE THE DRIVER: + +I recommend to compile driver as a module. This gives you an +easier access to its configuration. The camera has many more +settings than V4L can operate, so some settings are done using +module options. + +Typically module is installed with command 'modprobe', like this: + +# modprobe ibmcam framerate=1 + +Alternatively you can use 'insmod' in similar fashion: + +# insmod /lib/modules/2.x.y/usb/ibmcam.o framerate=1 + +Module can be inserted with camera connected or disconnected. + +The driver can have options, though some defaults are provided. + +Driver options: (* indicates that option is model-dependent) + +Name Type Range [default] Example +-------------- -------------- -------------- ------------------ +debug Integer 0-9 [0] debug=1 +flags Integer 0-0xFF [0] flags=0x0d +framerate Integer 0-6 [2] framerate=1 +hue_correction Integer 0-255 [128] hue_correction=115 +init_brightness Integer 0-255 [128] init_brightness=100 +init_contrast Integer 0-255 [192] init_contrast=200 +init_color Integer 0-255 [128] init_color=130 +init_hue Integer 0-255 [128] init_hue=115 +lighting Integer 0-2* [1] lighting=2 +sharpness Integer 0-6* [4] sharpness=3 +videosize Integer 0-2* [2] videosize=1 + +Options for Model 2 only: + +Name Type Range [default] Example +-------------- -------------- -------------- ------------------ +init_model2_rg Integer 0..255 [0x70] init_model2_rg=128 +init_model2_rg2 Integer 0..255 [0x2f] init_model2_rg2=50 +init_model2_sat Integer 0..255 [0x34] init_model2_sat=65 +init_model2_yb Integer 0..255 [0xa0] init_model2_yb=200 + +debug You don't need this option unless you are a developer. + If you are a developer then you will see in the code + what values do what. 0=off. + +flags This is a bit mask, and you can combine any number of + bits to produce what you want. Usually you don't want + any of extra features this option provides: + + FLAGS_RETRY_VIDIOCSYNC 1 This bit allows to retry failed + VIDIOCSYNC ioctls without failing. + Will work with xawtv, will not + with xrealproducer. Default is + not set. + FLAGS_MONOCHROME 2 Activates monochrome (b/w) mode. + FLAGS_DISPLAY_HINTS 4 Shows colored pixels which have + magic meaning to developers. + FLAGS_OVERLAY_STATS 8 Shows tiny numbers on screen, + useful only for debugging. + FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers. + FLAGS_SEPARATE_FRAMES 32 Shows each frame separately, as + it was received from the camera. + Default (not set) is to mix the + preceding frame in to compensate + for occasional loss of Isoc data + on high frame rates. + FLAGS_CLEAN_FRAMES 64 Forces "cleanup" of each frame + prior to use; relevant only if + FLAGS_SEPARATE_FRAMES is set. + Default is not to clean frames, + this is a little faster but may + produce flicker if frame rate is + too high and Isoc data gets lost. + +framerate This setting controls frame rate of the camera. This is + an approximate setting (in terms of "worst" ... "best") + because camera changes frame rate depending on amount + of light available. Setting 0 is slowest, 6 is fastest. + Beware - fast settings are very demanding and may not + work well with all video sizes. Be conservative. + +hue_correction This highly optional setting allows to adjust the + hue of the image in a way slightly different from + what usual "hue" control does. Both controls affect + YUV colorspace: regular "hue" control adjusts only + U component, and this "hue_correction" option similarly + adjusts only V component. However usually it is enough + to tweak only U or V to compensate for colored light or + color temperature; this option simply allows more + complicated correction when and if it is necessary. + +init_brightness These settings specify _initial_ values which will be +init_contrast used to set up the camera. If your V4L application has +init_color its own controls to adjust the picture then these +init_hue controls will be used too. These options allow you to + preconfigure the camera when it gets connected, before + any V4L application connects to it. Good for webcams. + +init_model2_rg These initial settings alter color balance of the +init_model2_rg2 camera on hardware level. All four settings may be used +init_model2_sat to tune the camera to specific lighting conditions. These +init_model2_yb settings only apply to Model 2 cameras. + +lighting This option selects one of three hardware-defined + photosensitivity settings of the camera. 0=bright light, + 1=Medium (default), 2=Low light. This setting affects + frame rate: the dimmer the lighting the lower the frame + rate (because longer exposition time is needed). The + Model 2 cameras allow values more than 2 for this option, + thus enabling extremely high sensitivity at cost of frame + rate, color saturation and imaging sensor noise. + +sharpness This option controls smoothing (noise reduction) + made by camera. Setting 0 is most smooth, setting 6 + is most sharp. Be aware that CMOS sensor used in the + camera is pretty noisy, so if you choose 6 you will + be greeted with "snowy" image. Default is 4. Model 2 + cameras do not support this feature. + +videosize This setting chooses one if three image sizes that are + supported by this driver. Camera supports more, but + it's difficult to reverse-engineer all formats. + Following video sizes are supported: + + videosize=0 128x96 (Model 1 only) + videosize=1 176x144 + videosize=2 352x288 + videosize=3 320x240 (Model 2 only) + videosize=4 352x240 (Model 2 only) + + The last one (352x288) is the native size of the sensor + array, so it's the best resolution camera (Model 1) can + yield. The best resolution of Model 2 is 176x144, and + larger images are produced by stretching the bitmap. + Choose the image size you need. The smaller image can + support faster frame rate. Default is 352x288. + +WHAT NEEDS TO BE DONE: + +- The box freezes if camera is unplugged after being used (OHCI). + Workaround: remove usb-ohci module first. +- On occasion camera (model 1) does not start properly (xawtv reports + errors), or camera produces negative image (funny colors.) + Workaround: reload the driver module. Reason: [1]. +- The button on the camera is not used. I don't know how to get to it. + I know now how to read button on Model 2, but what to do with it? + +[1] +- Camera reports its status back to the driver; however I don't know + what returned data means. If camera fails at some initialization + stage then something should be done, and I don't do that because + I don't even know that some command failed. This is mostly Model 1 + concern because Model 2 uses different commands which do not return + status (and seem to complete successfully every time). + +VIDEO SIZE AND IMAGE SIZE + +Camera produces picture X by Y pixels. This is camera-specific and can be +altered by programming the camera accordingly. This image is placed onto +larger (or equal) area W by H, this is V4L image. At this time the driver +uses V4L image size (W by H) 352x288 pixels because many programs (such +as xawtv) expect quite specific sizes and don't want to deal with arbitrary, +camera-specific sizes. However this approach "hides" real image size, and +application always sees the camera as producing only 352x288 image. It is +possible to change the V4L image size to 128x96, and then if camera is +switched to 128x96 mode then xawtv will correctly accept this image size. But +many other popular sizes (such as 176x144) will not be welcomed. This is the +reason why all camera images are at this time placed onto 352x288 "canvas", +and size of that canvas (V4L) is reported to applications. It will be easy +to add options to control the canvas size, but it will be application- +specific because not all applications are ready to work with variety of +camera-specific sizes. + +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. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/input.txt linux/Documentation/usb/input.txt --- v2.2.17/Documentation/usb/input.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/input.txt Thu Sep 14 15:35:24 2000 @@ -0,0 +1,306 @@ + Linux Input drivers v1.0 + (c) 1999-2000 Vojtech Pavlik + Sponsored by SuSE + $Id: input.txt,v 1.4 2000/05/28 17:57:22 vojtech Exp $ +---------------------------------------------------------------------------- + +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 collection of drivers that is designed to support all input +devices under Linux. However, in the current kernels, although it's +possibilities are much bigger, it's limited to USB devices only. This is +also why it resides in the drivers/usb subdirectory. + + The center of the input drivers is the input.o module, which must be +loaded before any other of the input modules - it serves as a way of +communication between two groups of modules: + +1.1 Device drivers +~~~~~~~~~~~~~~~~~~ + These modules talk to the hardware (for example via USB), and provide +events (keystrokes, mouse movements) to the input.o module. + +1.2 Event handlers +~~~~~~~~~~~~~~~~~~ + These modules get events from input.o and pass them where needed via +various interfaces - keystrokes to the kernel, mouse movements via a +simulated PS/2 interface to GPM and X and so on. + +2. Simple Usage +~~~~~~~~~~~~~~~ + For the most usual configuration, with one USB mouse and one USB keyboard, +you'll have to load the following modules (or have them built in to the +kernel): + + input.o + mousedev.o + keybdev.o + usbcore.o + usb-[uo]hci.o + hid.o + + After this, the USB keyboard will work straight away, and the USB mouse +will be available as a character device on major 13, minor 63: + + crw-r--r-- 1 root root 13, 63 Mar 28 22:45 mice + + This device, has to be created, unless you use devfs, in which case it's +created automatically. The commands to do that are: + + cd /dev + mkdir input + mknod input/mice c 13 63 + + After that you have to point GPM (the textmode mouse cut&paste tool) and +XFree to this device to use it - GPM should be called like: + + gpm -t ps2 -m /dev/input/mice + + And in X: + + Section "Pointer" + Protocol "ImPS/2" + Device "/dev/input/mice" + ZAxisMapping 4 5 + EndSection + + When you do all of the above, you can use your USB mouse and keyboard. + +3. Detailed Description +~~~~~~~~~~~~~~~~~~~~~~~ +3.1 Device drivers +~~~~~~~~~~~~~~~~~~ + Device drivers are the modules that generate events. The events are +however not useful without being handled, so you also will need to use some +of the modules from section 3.2. + +3.1.1 hid.c +~~~~~~~~~~~ + Hid.c is the largest and most complex driver of the whole suite. It +handles all HID devices, and because there is a very wide variety of them, +and because the USB HID specification isn't simple, it needs to be this big. + + Currently, it handles USB mice, joysticks, gamepads, steering wheels +keyboards, trackballs and digitizers. + + However, USB uses HID also for monitor controls, speaker controls, UPSs, +LCDs and many other purposes. + + The monitor and speaker controls should be easy to add to the hid/input +interface, but for the UPSs and LCDs it doesn't make much sense. The driver +doesn't support these yet, and a new, non-event interface should be designed +for them. If you have any of these devices (I don't), feel free to design +something and if it's good, it'll get into the driver. + + The usage of the hid.o module is very simple, it takes no parameters, +detects everything automatically and when a HID device is inserted, it +detects it appropriately. + + However, because the devices vary wildly, you might happen to have a +device that doesn't work well. In that case #define DEBUG at the beginning +of hid.c and send me the syslog traces. + +3.1.2 usbmouse.c +~~~~~~~~~~~~~~~~ + For embedded systems, for mice with broken HID descriptors and just any +other use when the big hid.c wouldn't be a good choice, there is the +usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP +protocol. This also means the mice must support this simpler protocol. Not +all do. If you don't have any strong reason to use this module, use hid.c +instead. + +3.1.3 usbkbd.c +~~~~~~~~~~~~~~ + Much like usbmouse.c, this module talks to keyboards with a simplified +HIDBP protocol. It's smaller, but doesn't support any extra special keys. +Use hid.c instead if there isn't any special reason to use this. + +3.1.4 wacom.c +~~~~~~~~~~~~~ + This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom +PenPartner, that one is handled by the HID driver. Although the Intuos and +Graphire tablets claim that they are HID tablets as well, they are not and +thus need this specific driver. + +3.1.5 wmforce.c +~~~~~~~~~~~~~~~ + A driver for the Logitech WingMan Force joysticks, when connected via the +USB port. It works quite well, but there is no force feedback support yet, +because the interface to do that is a trade secret of Immersion Corp, and +even Logitech can't disclose it. + + Support for Logitech WingMan Force Wheel isn't present in this driver, but +if someone has the device, and is willing to cooperate, it should be a +matter of a couple days to add it. + +3.2 Event handlers +~~~~~~~~~~~~~~~~~~ + Event handlers distribute the events from the devices to userland and +kernel, as needed. + +3.2.1 keybdev.c +~~~~~~~~~~~~~~~ + Keybdev is currently a rather ugly hack that translates the input events +into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and +passes them into the handle_scancode function of the keyboard.c module. This +works well enough on all architectures that keybdev can generate rawmode on, +other architectures can be added to it. + + The right way would be to pass the events to keyboard.c directly, best if +keyboard.c would itself be an event handler. This is done in the input +patch, available on the webpage mentioned below. + +3.2.2 mousedev.c +~~~~~~~~~~~~~~~~ + Mousedev is also a hack to make programs that use mouse input work. It +takes events from either mice or digitizers/tablets and makes a PS/2-style +(a la /dev/psaux) mouse device available to the userland. Ideally, the +programs could use a more reasonable interface, for example evdev.c + + Mousedev devices in /dev/input (as shown above) are: + + crw-r--r-- 1 root root 13, 32 Mar 28 22:45 mouse0 + crw-r--r-- 1 root root 13, 33 Mar 29 00:41 mouse1 + crw-r--r-- 1 root root 13, 34 Mar 29 00:41 mouse2 + crw-r--r-- 1 root root 13, 35 Apr 1 10:50 mouse3 + ... + ... + crw-r--r-- 1 root root 13, 62 Apr 1 10:50 mouse30 + crw-r--r-- 1 root root 13, 63 Apr 1 10:50 mice + +Each 'mouse' device is assigned to a single mouse or digitizer, except the last +one - 'mice'. This single character device is shared by all mice and +digitizers, and even if none are connected, the device is present. This is +useful for hotplugging USB mice, so that programs can open the device even when +no mice are present. + + CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size +of your screen (in pixels) in XFree86. This is needed if you want to use +your digitizer in X, because it's movement is sent to X via a virtual PS/2 +mouse and thus needs to be scaled accordingly. These values won't be used if +you use a mouse only. + + Mousedev will generate either PS/2, ImPS/2 (Microsoft IntelliMouse) or +GenPS/2 (Genius NetMouse/NetScroll) protocols, depending on what the program +reading the data wishes. You can set GPM and X to any of these. You'll need +ImPS/2 if you want to make use of a wheel on a USB mouse and GenPS/2 if you +want to use extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported +in X, though. + +3.2.3 joydev.c +~~~~~~~~~~~~~~ + Joydev implements v0.x and v1.x Linux joystick api, much like +drivers/char/joystick/joystick.c. See joystick-api.txt in the Documentation +subdirectory for details. Joydev does it on top of the input subsystem, +though. As soon as any USB joystick is connected, it can be accessed in +/dev/input on: + + crw-r--r-- 1 root root 13, 0 Apr 1 10:50 js0 + crw-r--r-- 1 root root 13, 1 Apr 1 10:50 js1 + crw-r--r-- 1 root root 13, 2 Apr 1 10:50 js2 + crw-r--r-- 1 root root 13, 3 Apr 1 10:50 js3 + ... + +And so on up to js31. + +3.2.4 evdev.c +~~~~~~~~~~~~~ + Evdev is the generic input event interface. It passes the events generated +in the kernel straight to the program, with timestamps. The API is still +evolving, but should be usable now. It's described in section 5. + + This should be the way for GPM and X to get keyboard and mouse mouse +events. It allows for multihead in X without any specific multihead kernel +support. The event codes are the same on all architectures and are hardware +independent. + + The devices are in /dev/input: + + crw-r--r-- 1 root root 13, 64 Apr 1 10:49 event0 + crw-r--r-- 1 root root 13, 65 Apr 1 10:50 event1 + crw-r--r-- 1 root root 13, 66 Apr 1 10:50 event2 + crw-r--r-- 1 root root 13, 67 Apr 1 10:50 event3 + ... + +3. Contacts +~~~~~~~~~~~ + 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 +as well as information how to access the CVS repository for latest revisions +of the drivers. + + + There is also a mailing list for this: + + majordomo@atrey.karlin.mff.cuni.cz + +Send "subscribe linux-input" to subscribe to it. + +4. 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/input/mouse0 (c, 13, 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' utility available on the +input driver homepage (see the URL above). + +5. Event interface +~~~~~~~~~~~~~~~~~~ + Should you want to add event device support into any application (X, gpm, +svgalib ...) I 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/input/eventX 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 movement, 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. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/ohci.txt linux/Documentation/usb/ohci.txt --- v2.2.17/Documentation/usb/ohci.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/ohci.txt Thu Sep 14 15:35:24 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 coming 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 + +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 chosen. + 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 busy. + + 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt --- v2.2.17/Documentation/usb/ov511.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/ov511.txt Fri Sep 15 12:49:09 2000 @@ -0,0 +1,254 @@ +------------------------------------------------------------------------------- +Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC +------------------------------------------------------------------------------- + +Author: Mark McClelland +Homepage: http://alpha.dyndns.org/ov511 + +NEW IN THIS VERSION: + o Stability improvements + o Support for hue control + o 160x120 mostly working + o OV6620 color problems fixed + o MoreWebCam 3 detection improvements + +INTRODUCTION: + +This is a driver for the OV511, a USB-only chip used in many "webcam" devices. +Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It +supports streaming and capture of color or monochrome video via the Video4Linux +API. Most V4L apps are compatible with it, but a few videoconferencing programs +do not work yet. The following resolutions are supported: 640x480, 448x336, +384x288, 352x288, and 320x240. + +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) + vidcat is part of the w3cam package: http://www.hdk-berlin.de/~rasca/w3cam/ + xawtv is available at: http://www.in-berlin.de/User/kraxel/xawtv.html + +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 + +Sometimes /dev/video is a symlink to /dev/video0 + +You will have to set permissions on this device to allow you to read/write +from it: + + chmod 666 /dev/video + chmod 666 /dev/video0 (if necessary) + +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. If +you get a scrambled image it is likely that you made a mistake in Xawtv.ad. +Try setting the size to 320x240 if all else fails. + +FAQ: +Q: "Why does the picture have noise and look grainy" +A: This is a problem at low light levels, and may be also due to subtle bugs in + the code. The cause is most likely the OV7610 settings we are currently + using. I am looking into this problem. + +Q: "The driver sometimes says `Failed to read OV7610 ID.' What is the deal?" +A: The I2C code that allows the OV511 to communicate with the camera chip is a + bit flaky right now. This message means that the I2C bus never got + initialized properly, and the camera will most likely not work even if you + disable this warning. Try unloading/reloading the driver or unplugging/re- + plugging the camera if this happens. Also try increasing the i2c_detect_tries + parameter (see below). + +Q: "Why do you bother with this phony camera detection crap? It doesn't do + anything useful!" +A: The main purpose of only supporting known camera models is to force people + with new camera models to tell me about them, so I can assemble the list + above, and so the code can know what CCD chip you have. Right now, nearly all + of the cameras use the OV7610 and consequently I have not put support for + other ones in, so the value of the detection code is questionable. Eventually + though, new CCDs might appear and we will be fortunate to have the detection. + +MODULE PARAMETERS: + + You can set these with: insmod ov511 NAME=VALUE + There is currently no way to set these on a per-camera basis. + + NAME: autoadjust + TYPE: integer (boolean) + DEFAULT: 1 + DESC: The camera normally adjusts exposure, gain, and hue automatically. This + can be set to 0 to disable this automatic adjustment. Note that there is + currently no way to set these parameters manually once autoadjust is + disabled. + + NAME: debug + TYPE: integer (0-6) + DEFAULT: 3 + DESC: Sets the threshold for printing debug messages. The higher the value, + the more is printed. The levels are cumulative, and are as follows: + 0=no debug messages + 1=init/detection/unload and other significant messages + 2=some warning messages + 3=config/control function calls + 4=most function calls and data parsing messages + 5=highly repetitive mesgs + + NAME: fix_rgb_offset + TYPE: integer (boolean) + DEFAULT: 0 + DESC: Some people have reported that the blue component of the image is one + or so lines higher than the red component. This is only apparent in + images with white objects on black backgrounds at 640x480. Setting this + to 1 will realign the color planes correctly. NOTE: This is still + experimental and very buggy. You will likely need a fast (500 Mhz) CPU. + + NAME: snapshot + TYPE: integer (boolean) + DEFAULT: 0 + DESC: Set to 1 to enable snapshot mode. read() will block until the snapshot + button is pressed. Note that this does not yet work with most apps, + including xawtv and vidcat. NOTE: See the section "TODO" for more info. + + NAME: sensor + TYPE: integer ([0, 1, 3]) + DEFAULT: [varies] + DESC: If you know that your camera sensor is not detected correctly, set this + parameter. This is a global option for all attached OV511 cameras. You + will probably never need to set this, but if you do, valid values are: + 0 for OV7620 + 1 for OV7620AE + 3 for OV7610 + + NAME: i2c_detect_tries + TYPE: integer (don't set it insanely high!) + DEFAULT: 5 + DESC: This is the number of times the driver will try to sync and detect the + internal i2c bus (which connects the OV511 and sensor). If you are + getting intermittent detection failures ("Failed to read sensor ID...") + you should increase this by a modest amount. If setting it to 20 or so + doesn't fix things, look elsewhere for the cause of the problem. + + NAME: aperture + TYPE: integer (0 - 15) + DEFAULT: [varies by sensor] + DESC: For legal values, see the OV7610/7620 specs under register Common F. + This setting affects the upper nybble of that reg (bits 4-7). This is + for if you want to play with the camera's pixel saturation. + + NAME: force_rgb + TYPE: integer (boolean) + DEFAULT: 0 + DESC: Force image to be read in RGB instead of BGR. This option allow + programs that expect RGB data (e.g. gqcam) to work with this driver. If + your colors look VERY wrong, you may want to change this. + + NAME: buf_timeout + TYPE: integer + DEFAULT: 5 (seconds) + DESC: Number of seconds before unused frame buffers are deallocated. + Previously, memory was allocated upon open() and deallocated upon + close(). Deallocation now occurs only if the driver is closed and this + timeout is reached. If you are capturing frames less frequently than + the default timeout, increase this. This will not make any difference + with programs that capture multiple frames during an open/close cycle. + + NAME: cams + TYPE: integer (1-4 for OV511, 1-31 for OV511+) + DEFAULT: 1 + DESC: Number of cameras allowed to stream simultaneously on a single bus. + Values higher than 1 reduce the data rate of each camera, allowing two + or more to be used at once. If you have a complicated setup involving + both OV511 and OV511+ cameras, trial-and-error may be necessary for + finding the optimum setting. + + NAME: retry_sync + TYPE: boolean + DEFAULT: 0 + DESC: Prevent apps from timing out if frame is not done in time. This is + useful if you are having problems with Xawtv getting "stuck" on a frame + when your system is under heavy load. + +WORKING FEATURES: + o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, 320x240, and + 160x120 + o RGB24, YUV420, YUV422, YUYV, and YUV422P color + o Monochrome + o Setting/getting of saturation, contrast, brightness, and hue (only some of + them work the OV7620 and OV7620AE) + o proc status reporting + +EXPERIMENTAL FEATURES: + o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and + corrupted frames. If you have a very fast CPU, you can try it. + o Snapshot mode (only works with some read() based apps; see below for more) + o OV6620 sensor support + o GBR422 parsing + +TODO: + o Fix the noise / grainy image problem. + o Get compression working. It would be a nice addition as it improves + frame rate 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. + o YUV422 + o Get snapshot mode working with mmap(). + o Fix fixFrameRGBoffset(). It is not stable yet with streaming video. + o Get autoadjust disable working + o V4L2 support (Probably not until it goes into the kernel) + o Creative WebCam III has problems initializing its sensor. This should be + fixed now, but if you still have problems let me know. + o Get rid of the memory management functions (put them in videodev.c??) + o Setting of contrast and brightness not working with 7620/7620AE + o Driver/camera state save/restore for when USB supports suspend/resume + o Unstable on SMP systems + o OV7620/OV6620 experience frame corruption with moving objects + o OV6620 is too dark + +HOW TO CONTACT ME: + +You can email me at mwm@i.am . 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. Thanks to Orion Sky Lawlor, Kevin Moore, and Claudio +Matsuoka for their work as well. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/proc_usb_info.txt linux/Documentation/usb/proc_usb_info.txt --- v2.2.17/Documentation/usb/proc_usb_info.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/proc_usb_info.txt Thu Sep 14 15:35:24 2000 @@ -0,0 +1,273 @@ +/proc/bus/usb filesystem output +=============================== +(version 2000.08.15) + + +The /proc filesystem for USB devices generates +/proc/bus/usb/drivers and /proc/bus/usb/devices. + +/proc/bus/usb/drivers lists the registered drivers, +one per line, with each driver's USB minor dev node +number range if applicable. + +**NOTE**: If /proc/bus/usb appears empty, you need + to mount the filesystem, issue the command (as root): + + mount -t usbdevfs none /proc/bus/usb + + An alternative and more permanent method would be to add + + none /proc/bus/usb usbdevfs defaults 0 0 + + to /etc/fstab. This will mount usbdevfs at each reboot. + You can then issue `cat /proc/bus/usb/devices` to extract + USB device information. + +For more information on mounting the usbdevfs file system, see the +"USB Device Filesystem" section of the USB Guide. The latest copy +of the USB Guide can be found at http://www.linux-usb.org/ + +In /proc/bus/usb/devices, each device's output has multiple +lines 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 (applies only to USB host controllers, which are + virtualized as root hubs) +D = Device descriptor info. +P = Product ID info. (from Device descriptor, but they won't fit + together on one line) +S = String descriptors. +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, +| except that it is a generated string for USB host controllers +| (virtual root hubs), in the form "USB *HCI Root Hub". +|__String info tag + +S: SerialNumber=ssss +| |__Serial Number of this device as read from the device, +| except that it is a generated string for USB host controllers +| (virtual root hubs), and represents the host controller's +| unique identification in the system (currently I/O or +| memory-mapped base address). +|__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 TBDPSCIE] 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 +D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=0000 ProdID=0000 Rev= 0.00 +S: Product=USB UHCI Root Hub +S: SerialNumber=dce0 +C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA +I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub +E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms +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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/rio.txt linux/Documentation/usb/rio.txt --- v2.2.17/Documentation/usb/rio.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/rio.txt Fri Sep 1 13:51:28 2000 @@ -0,0 +1,138 @@ +Copyright (C) 1999, 2000 Bruce Tenison +Portions Copyright (C) 1999, 2000 David Nelson +Thanks to David Nelson for guidance and the usage of the scanner.txt +and scanner.c files to model our driver and this informative file. + +Mar. 2, 2000 + +CHANGES + +- Initial Revision + + +OVERVIEW + +This README will address issues regarding how to configure the kernel +to access a RIO 500 mp3 player. +Before I explain how to use this to access the Rio500 please be warned: + +W A R N I N G: +-------------- + +Please note that this software is still under development. The authors +are in no way responsible for any damage that may occur, no matter how +inconsequential. + +It seems that the Rio has a problem when sending .mp3 with low batteries. +I suggest when the batteries are low and want to transfer stuff that you +replace it with a fresh one. In my case, what happened is I lost two 16kb +blocks (they are no longer usable to store information to it). But I don't +know if thats normal or not. It could simply be a problem with the flash +memory. + +In an extreme case, I left my Rio playing overnight and the batteries wore +down to nothing and appear to have corrupted the flash memory. My RIO +needed to be replaced as a result. Diamond tech support is aware of the +problem. Do NOT allow your batteries to wear down to nothing before +changing them. It appears RIO 500 firmware does not handle low battery +power well at all. + +On systems with OHCI controllers, the kernel OHCI code appears to have +power on problems with some chipsets. If you are having problems +connecting to your RIO 500, try turning it on first and then plugging it +into the USB cable. + +Contact information: +-------------------- + + The main page for the project is hosted at sourceforge.net in the following + address: http://rio500.sourceforge.net You can also go to the sourceforge + project page at: http://sourceforge.net/project/?group_id=1944 There is + also a mailing list: rio500-users@lists.sourceforge.net + +Authors: +------- + +Most of the code was written by Cesar Miquel . Keith +Clayton is incharge of the PPC port and making sure +things work there. Bruce Tenison is adding support +for .fon files and also does testing. The program will mostly sure be +re-written and Pete Ikusz along with the rest will re-design it. I would +also like to thank Tri Nguyen who provided use +with some important information regarding the communication with the Rio. + +ADDITIONAL INFORMATION and Userspace tools + +http://rio500.sourceforge.net/ + + +REQUIREMENTS + +A host with a USB port. Ideally, either a UHCI (Intel) or OHCI +(Compaq and others) hardware port should work. + +A Linux development kernel (2.3.x) with USB support enabled or a +backported version to linux-2.2.x. See http://www.linux-usb.org for +more information on accomplishing this. + +A Linux kernel with RIO 500 support enabled. + +'lspci' which is only needed to determine the type of USB hardware +available in your machine. + +CONFIGURATION + +Using `lspci -v`, determine the type of USB hardware available. + + If you see something like: + + USB Controller: ...... + Flags: ..... + I/O ports at .... + + Then you have a UHCI based controller. + + If you see something like: + + USB Controller: ..... + Flags: .... + Memory at ..... + + Then you have a OHCI based controller. + +Using `make menuconfig` or your preferred method for configuring the +kernel, select 'Support for USB', 'OHCI/UHCI' depending on your +hardware (determined from the steps above), 'USB Diamond Rio500 support', and +'Preliminary USB device filesystem'. Compile and install the modules +(you may need to execute `depmod -a` to update the module +dependencies). + +Add a device for the USB rio500: + `mknod /dev/usb/rio500 c 180 64` + +Set appropriate permissions for /dev/usb/rio500 (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 usbcore + modprobe usb-ohci + modprobe rio500 + + UHCI: + modprobe usbcore + modprobe usb-uhci (or uhci) + modprobe rio500 + +That's it. The Rio500 Utils at: http://rio500.sourceforge.net should +be able to access the rio500. + +BUGS + +If you encounter any problems feel free to drop me an email. + +Bruce Tenison +btenison@dibbs.net + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/scanner-hp-sane.txt linux/Documentation/usb/scanner-hp-sane.txt --- v2.2.17/Documentation/usb/scanner-hp-sane.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/scanner-hp-sane.txt Fri Sep 1 13:51:28 2000 @@ -0,0 +1,81 @@ +Copyright (C) 1999, 2000 David E. Nelson + +April 26, 2000 + +CHANGES + +- Amended for Linux-2.3.99-pre6-3 +- Updated for multiple scanner support + +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 Scanners that I'm aware of that do not support SCL are the +4200C ,3300C, and the PhotoSmart S20. All other HP scanners with USB +interfaces should work (4100C, 5200C, 6200C, and 6300C) as do models +that are derived from the models above. ie the 6350C which is a 6300C +with a transparency adaptor included with the scanner at time of +purchase. 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 scanner.txt 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. + +The latest SANE HP backend is available from http://www.kirchgessner.net. +At the time of this writing, version 0.83 was available. + + +OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW? + +NOTE: $INSTALL_DIR is the location where SANE is 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 + +NOTE: If you are using multiple scanners, make sure to have the correct +device, ie /dev/usbscanner0. See scanner.txt for more info. + +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 to work. If you are dealing with a RedHat system, this +means that you'll also need to install the gimp-devel rpm package +prior to compiling SANE. + +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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/scanner.txt linux/Documentation/usb/scanner.txt --- v2.2.17/Documentation/usb/scanner.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/scanner.txt Thu Sep 14 15:35:24 2000 @@ -0,0 +1,362 @@ +Copyright (C) 1999, 2000 David E. Nelson + +April 26, 2000 + +CHANGES + +- Amended for linux-2.3.99-pre6-3 +- Appended hp_scan.c to end of this README +- Removed most references to HP +- Updated uhci/ohci host controller info +- Updated support for multiple scanner support +- Updated supported scanners list +- Updated usbdevfs info +- Spellcheck + +OVERVIEW + +This README addresses 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 scanner-hp-sane.txt for guidance on how to configure SANE to +use a USB HP Scanner. + + +ADDITIONAL INFORMATION + +http://www.linux-usb.org/ + + +REQUIREMENTS + +A host with a USB port. Ideally, either a UHCI (Intel) or OHCI +(Compaq and others) hardware port should work. At the time of this +writing, there are two UHCI drivers and one OHCI. + +A Linux development kernel (2.3.x) with USB support enabled or a +backported version to linux-2.2.x. See http://www.linux-usb.org for +more information on accomplishing this. + +A Linux kernel with USB Scanner support enabled. + +'lspci' which is only needed to determine the type of USB hardware +available/installed in your machine. + +CONFIGURATION + +Using `lspci -v`, determine the type of USB hardware available/installed. + + If you see something like: + + USB Controller: ...... + Flags: ..... + I/O ports at .... + + Then you have a UHCI based controller. + + If you see something like: + + USB Controller: ..... + Flags: .... + Memory at ..... + + Then you have a OHCI based controller. + +Using `make menuconfig` or your preferred method for configuring the +kernel, select 'Support for USB', 'OHCI/UHCI' depending on your +hardware (determined from the steps above), 'USB Scanner support', and +'Preliminary USB device filesystem'. Compile and install the modules +(you may need to execute `depmod -a` to update the module +dependencies). If any of the USB sections were compiled into the +kernel, a reboot is necessary. NOTE: Updating the boot disk with +'lilo' may also be required. Testing was performed only as modules, +YMMV. + +Beginning with version 0.4 of the driver, up to 16 scanners can be +connected/used simultaneously. If you intend to use more than +one scanner at a time: + + Add a device for the USB scanner: + `mknod /dev/usbscanner0 c 180 48` + `mknod /dev/usbscanner1 c 180 49` + . + . + `mknod /dev/usb/scanner15 180 63` + + +If you foresee using only one scanner it is best to: + `mknod /dev/usbscanner0 c 180 48` + `ln -s /dev/usbscanner0 /dev/usbscanner` + + +Set appropriate permissions for /dev/usbscanner[0-15] (don't forget +about group and world permissions). Both read and write permissions +are required for proper operation. For example: + `chmod 666 /dev/usbscanner0` + +Load the appropriate modules (if compiled as modules): + + OHCI: + modprobe usb-ohci + modprobe scanner + + UHCI: + modprobe usb-uhci + 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 (Scanner Control Language). Known HP scanner that support SCL are +the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not* +supported since it does not understand SCL; it's also strongly +suspected that the 3300 and the PhotoSmart S20 are not SCL compliant. +Hp_scan.c's 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. + +MESSAGES + +On occasions the message 'usb_control/bulk_msg: timeout' or something +similar will appear in '/var/adm/messages' or on the console or both, +depending on how your system is configured. This is a side effect +that scanners are sometimes very slow at warming up and/or +initializing. In most cases, however, only several of these messages +should appear and is generally considered to be normal. If you see +a message of the type 'excessive NAK's received' then this should +be considered abnormal and generally indicates that the USB system is +unable to communicate with the scanner for some particular reason. + +SUPPORTED SCANNERS + +NOTE: Just because a product is listed here does not mean that +applications exist that support the product. It's in the hopes that +this will allow developers a means to produce applications that will +support the listed USB products. + +At the time of this writing, the following scanners were supported by +scanner.c: + + Acer + Prisa Acerscan 620U & 640U (!) + Prisa AcerScan 620U (!) + Agfa + SnapScan 1212U + Another SnapScan 1212U (?) + SnapScan Touch + Colorado -- See Primax/Colorado below + Epson -- See Seiko/Epson below + Genius + ColorPage-Vivid Pro + Hewlett Packard + 3300C + 4100C + 4200C + PhotoSmart S20 + 5200C + 6200C + 6300C + Microtek + ScanMaker X6 - X6U + Phantom 336CX - C3 + Phantom 336CX - C3 #2 + Phantom C6 + ScanMaker V6USL + ScanMaker V6USL #2 + ScanMaker V6UL - SpicyU + Mustek + 1200 CU + Primax/Colorado + G2-300 #1 + G2-600 #1 + G2E-300 #1 + ReadyScan 636i + G2-300 #2 + G2-600 #2 + G2E-300 #2 + G2E-600 + Colorado USB 9600 + Colorado USB 19200 + Colorado 600u + Colorado 1200u + Seiko/Epson Corp. + Perfection 636U and 636Photo + Perfection 610 + Perfection 1200U and 1200Photo + Umax + Astra 1220U + Astra 1236U + Astra 2000U + Astra 2200U + Visioneer + OneTouch 5300 + OneTouch 7600 duplicate ID (!) + 6100 + + +MODULE PARAMETERS + +If you have a device that you 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 /etc/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`. Note that USB /proc support must be +enabled during kernel configuration. If the 'scanner' module is +already loaded into memory, it must be reloaded for the module +parameters to take effect. In essence, `rmmod scanner; modprobe +scanner` must be performed. + +**NOTE**: In later kernels (2.3.38+), a new filesystem was introduced, +usbdevfs. To mount the filesystem, issue the command (as root): + + mount -t usbdevfs /proc/bus/usb /proc/bus/usb + +An alternative and more permanent method would be to add + + none /proc/bus/usb usbdevfs defaults 0 0 + +to /etc/fstab. This will mount usbdevfs at each reboot. You can then +issue `cat /proc/bus/usb/devices` to extract USB device information. + + +BUGS + +Just look at the list of fixes in the source files. So, 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/uhci.txt linux/Documentation/usb/uhci.txt --- v2.2.17/Documentation/usb/uhci.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/uhci.txt Thu Sep 14 15:35:24 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 dependent, 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 and 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 appropriate +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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/usb-help.txt linux/Documentation/usb/usb-help.txt --- v2.2.17/Documentation/usb/usb-help.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/usb-help.txt Thu Sep 14 15:35:24 2000 @@ -0,0 +1,18 @@ +usb-help.txt +2000-July-12 + +For USB help other than the readme files that are located in +linux/Documentation/usb/*, see the following: + +Linux-USB project: http://www.linux-usb.org + mirrors at http://www.suse.cz/development/linux-usb/ + and http://usb.in.tum.de/linux-usb/ +Linux USB Guide: http://linux-usb.sourceforge.net +Linux-USB device overview (working devices and drivers): + http://www.qbik.ch/usb/devices/ + +The Linux-USB mailing lists are: + linux-usb-users@lists.sourceforge.net for general user help + linux-usb-devel@lists.sourceforge.net for developer discussions + +### diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt --- v2.2.17/Documentation/usb/usb-serial.txt Thu Jan 1 01:00:00 1970 +++ linux/Documentation/usb/usb-serial.txt Thu Dec 7 14:52:03 2000 @@ -0,0 +1,217 @@ +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 256 different serial interfaces at + one time. + + If you are not using devfs: + 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/ttyUSB254 c 188 254 + mknod /dev/ttyUSB255 c 188 255 + + If you are using devfs: + The devices supported by this driver will show up as + /dev/usb/tts/{0,1,...} + + When the device is connected and recognized by the driver, the driver + will print to the system log, which node(s) the device has been bound + to. + + +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, the new firmware + runs properly and all four ports are successfully recognized and connected. + Data can be sent and received through the device on all ports. + Hardware flow control needs to be implemented. + + +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. + + NOTE: + This means that in order to talk to the Visor, the sync button must be + pressed BEFORE trying to get any program to communicate to the Visor. + This goes against the current documentation for pilot-xfer and other + packages, but is the only way that it will work due to the hardware + in the Visor. + + When the device is connected, try talking to it on the second port + (this is usually /dev/ttyUSB1 if you do not have any other usb-serial + devices in the system.) The system log should tell you which port is + the port to use for the HotSync transfer. The "Generic" port can be used + for other device communication, such as a PPP link. + + There is a webpage and mailing lists for this portion of the driver at: + http://usbvisor.sourceforge.net/ + + +Keyspan PDA Serial Adapter + + Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly + sold in Macintosh catalogs, comes in a translucent white/green dongle). + Fairly simple device. Firmware is homebrew. + +Current status: + Things that work: + basic input/output (tested with 'cu') + blocking write when serial line can't keep up + changing baud rates (up to 115200) + getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC}) + sending break (although duration looks suspect) + Things that don't: + device strings (as logged by kernel) have trailing binary garbage + device ID isn't right, might collide with other Keyspan products + changing baud rates ought to flush tx/rx to avoid mangled half characters + Big Things on the todo list: + parity, 7 vs 8 bits per char, 1 or 2 stop bits + HW flow control + not all of the standard USB descriptors are handled: Get_Status, Set_Feature + O_NONBLOCK, select() + + +Keyspan USA-series Serial Adapters + + Single and Dual port adapters - driver uses Keyspan supplied + firmware and is being developed with their support. + + Driver isn't as far advanced as Keyspan PDA driver mentioned above. + +Current status: + Things that work: + Firmware upload for USA-18X, USA-28, USA-28X, USA-19 and USA-19W + Simple character I/O fixed at 9600 baud on USA-19 only + + Things that don't: + Everything else. (for now...) + + Big Things on the todo list: + Driver is in infancy, much functionality remains to be added + + +FTDI Single Port Serial Driver + + This is a single port DB-25 serial adapter. More information about this + device and the Linux driver can be found at: + http://reality.sgi.com/bryder_wellington/ftdi_sio/ + + +ZyXEL omni.net lcd plus ISDN TA + + This is an ISDN TA. Please report both successes and troubles to the + author at omninet@kroah.com + + +Digi AccelePort Driver + + This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port + (plus a parallel port) and 4 port USB serial converters. The driver + does NOT yet support the Digi AccelePort USB 8. + + This driver works under SMP with the usb-uhci driver. It does not work + under SMP with the uhci driver. + + The driver is generally working, though we still have a few more ioctls + to implement and final testing and debugging to do. The paralled port + on the USB 2 is supported as a serial to parallel converter; in other + words, it appears as another USB serial port on Linux, even though + physically it is really a parallel port. The Digi Acceleport USB 8 + is not yet supported. + + Please contact Peter Berger (pberger@brimson.com) or Al Borchers + (alborchers@steinerpoint.com) for questions or problems with this + driver. + + +Belkin USB Serial Adapter F5U103 + + Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs. + +Current status: + The following have been tested and work: + Baud rate 300-230400 + Data bits 5-8 + Stop bits 1-2 + Parity N,E,O,M,S + Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)* + Break Set and clear + Line contrl Input/Output query and control ** + + * Hardware input flow control is only enabled for firmware + levels above 2.06. Read source code comments describing Belkin + firmware errata. Hardware output flow control is working for all + firmware versions. + ** Queries of inputs (CTS,DSR,CD,RI) show the last + reported state. Queries of outputs (DTR,RTS) show the last + requested state and may not reflect current state as set by + automatic hardware flow control. + +TO DO List: + -- Add true modem contol line query capability. Currently tracks the + states reported by the interrupt and the states requested. + -- Add error reporting back to application for UART error conditions. + -- Add support for flush ioctls. + -- Add everything else that is missing :) + + +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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/video4linux/CQcam.txt linux/Documentation/video4linux/CQcam.txt --- v2.2.17/Documentation/video4linux/CQcam.txt Fri Apr 21 12:45:50 2000 +++ linux/Documentation/video4linux/CQcam.txt Sun Oct 15 21:39:02 2000 @@ -127,7 +127,7 @@ The c-qcam is IEEE1284 compatible, so if you are using the proc file system (CONFIG_PROC_FS), the parallel printer support -(CONFIG_PRINTER), the IEEE 1284 sytem,(CONFIG_PRINTER_READBACK), you +(CONFIG_PRINTER), the IEEE 1284 system,(CONFIG_PRINTER_READBACK), you should be able to read some identification from your quickcam with modprobe -v parport diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/video4linux/README.cpia linux/Documentation/video4linux/README.cpia --- v2.2.17/Documentation/video4linux/README.cpia Sun Jun 11 21:44:08 2000 +++ linux/Documentation/video4linux/README.cpia Sun Oct 15 21:39:02 2000 @@ -173,7 +173,7 @@ The camera can act in two modes, streaming or grabbing. Right now a polling grab-scheme is used. Maybe interrupt driven streaming will be -used for a ansychronous mmap interface in the next major release of the +used for a asynchronous mmap interface in the next major release of the driver. This might give a better frame rate. --------------------------------------------------------------------------- diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Documentation/video4linux/radiotrack.txt linux/Documentation/video4linux/radiotrack.txt --- v2.2.17/Documentation/video4linux/radiotrack.txt Fri Apr 21 12:45:50 2000 +++ linux/Documentation/video4linux/radiotrack.txt Sun Oct 15 21:39:02 2000 @@ -35,7 +35,7 @@ -------------------- The RadioTrack card is an ISA 8-bit FM radio card. The radio frequency (RF) input is simply an antenna lead, and the output is a power audio signal -available through a miniature phono plug. Its RF frequencies of operation are +available through a miniature phone plug. Its RF frequencies of operation are more or less limited from 87.0 to 109.0 MHz (the commercial FM broadcast band). Although the registers can be programmed to request frequencies beyond these limits, experiments did not give promising results. The variable diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/MAINTAINERS linux/MAINTAINERS --- v2.2.17/MAINTAINERS Sat Sep 9 18:42:32 2000 +++ linux/MAINTAINERS Thu Dec 7 14:52:03 2000 @@ -93,6 +93,12 @@ L: linux-net@vger.kernel.org S: Maintained +AACRAID ADAPTEC RAID DRIVER +P: Brian M. Boerner +M: aacraid@ntc.adaptec.com +L: To Be Announced +S: Maintained + AD1816 SOUND DRIVER P: Thorsten Knabe M: Thorsten Knabe @@ -103,8 +109,10 @@ ADVANSYS SCSI DRIVER P: Bob Frey -M: linux@advansys.com +M: bfrey@turbolinux.com.cn +M: linux@connectcom.net W: http://www.advansys.com/linux.html +W: http://www.connectcom.net/downloads/software/os/linux.html L: linux-scsi@vger.kernel.org S: Maintained @@ -177,6 +185,13 @@ L: linux-fbdev@vuser.vu.union.edu S: Maintained +COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA +P: Amy Vanzant-Hodge +M: Amy Vanzant-Hodge (fibrechannel@compaq.com) +L: compaqandlinux@cpqlin.van-dijk.net +W: ftp.compaq.com/pub/products/drivers/linux +S: Supported + COMPUTONE INTELLIPORT MULTIPORT CARD P: Doug McNash P: Michael H. Warfield @@ -228,9 +243,9 @@ DAMA SLAVE for AX.25 P: Joerg Reuter -M: jreuter@poboxes.com -W: http://poboxes.com/jreuter/ -W: http://qsl.net/dl1bke/ +M: jreuter@yaina.de +W: http://yaina.de/jreuter +W: http://www.qsl.net/dl1bke/ L: linux-hams@vger.kernel.org S: Maintained @@ -254,6 +269,12 @@ L: linux-kernel@vger.kernel.org S: Maintained +DEVICE FILESYSTEM +P: Richard Gooch +M: rgooch@atnf.csiro.au +L: linux-kernel@vger.rutgers.edu +S: Maintained + DIGI INTL. EPCA DRIVER P: Daniel Taylor M: support@digi.com @@ -301,6 +322,13 @@ W: ftp.compaq.com/pub/products/drivers/linux S: Supported +COMPAQ SMART CISS RAID DRIVER +P: Charles White +M: Charles White +L: compaqandlinux@cpqlin.van-dijk.net +W: ftp.compaq.com/pub/products/drivers/linux +S: Supported + DAC960 RAID DRIVER P: Leonard N. Zubkoff M: Leonard N. Zubkoff @@ -360,6 +388,12 @@ W: http://suburbia.net/~billm/floating-point/emulator/ S: Maintained +FRAME DIVERTER +P: Benoit Locher +M: Benoit.Locher@skf.com +W: http://perso.wanadoo.fr/magpie/EtherDivert.html +S: Maintained + FRAME RELAY DLCI/FRAD (Sangoma drivers too) P: Mike McLagan M: mike.mclagan@linux.org @@ -442,16 +476,23 @@ IDE/ATAPI CDROM DRIVER P: Jens Axboe -M: axboe@image.dk +M: axboe@suse.de L: linux-kernel@vger.kernel.org S: Maintained -IDE/ATAPI TAPE/FLOPPY DRIVERS +IDE/ATAPI TAPE DRIVERS P: Gadi Oxman M: Gadi Oxman L: linux-kernel@vger.kernel.org S: Maintained +IDE/ATAPI FLOPPY DRIVERS +P: Paul Bristow +M: Paul Bristow +W: http://paulbristow.net/linux +L: linux-kernel@vger.kernel.org +S: Maintained + IP FIREWALL P: Paul Russell M: Paul.Russell@rustcorp.com.au @@ -780,6 +821,14 @@ W: www.rtlinux.org S: Maintained +S390 +P: Martin Schwidefsky +M: schwidefsky@de.ibm.com +M: linux390@de.ibm.com +L: linux-390@vm.marist.edu +W: http://oss.software.ibm.com/developerworks/opensource/linux390 +S: Supported + SBPCD CDROM DRIVER P: Eberhard Moenkeberg M: emoenke@gwdg.de @@ -917,24 +966,118 @@ UNIFORM CDROM DRIVER P: Jens Axboe -M: axboe@image.dk +M: axboe@suse.de L: linux-kernel@vger.kernel.org S: Maintained -USB HUB AND UHCI DRIVERS +USB SUBSYSTEM +P: Johannes Erdfelt +M jerdfelt@valinux.com +M: johannes@erdfelt.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +W: http://www.linux-usb.org +S: Supported + +USB ACM DRIVER +P: Vojtech Pavlik +M: vojtech@suse.cz +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Supported + +USB BLUETOOTH DRIVER +P: Greg Kroah-Hartman +M: greg@kroah.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained +W: http://www.kroah.com/linux-usb/ + +USB HID/HIDBP/INPUT DRIVERS +P: Vojtech Pavlik +M: vojtech@suse.cz +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +W: http://www.suse.cz/development/input/ +S: Supported + +USB HUB P: Johannes Erdfelt M: jerdfelt@sventech.com -L: linux-usb@suse.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net S: Maintained USB OHCI DRIVER -P: Gregory P. Smith -M: greg@electricrain.com -M: greg@suitenine.com -L: linux-usb@suse.com -S: Maintained (not yet usable) -W: http://suitenine.com/usb/ +P: Roman Weissgaerber +M: weissg@vienna.at +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + +USB OV511 DRIVER +P: Mark McClelland +M: mmcclelland@delphi.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +W: http://alpha.dyndns.org/ov511/ +S: Maintained + +USB PEGASUS DRIVER +P: Petko Manolov +M: petkan@dce.bg +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained +USB PRINTER DRIVER +P: Vojtech Pavlik +M: vojtech@suse.cz +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Supported + +USB SERIAL DIGI ACCELEPORT DRIVER +P: Peter Berger and Al Borchers +M: pberger@brimson.com +M: alborchers@steinerpoint.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained + +USB SERIAL KEYSPAN DRIVER +P: Hugh Blemings +M: hugh@linuxcare.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained +W: http://www.linuxcare.com.au/hugh/keyspan.html + +USB SERIAL DRIVER +P: Greg Kroah-Hartman +M: greg@kroah.com +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained +W: http://www.kroah.com/linux-usb/ + +USB MASS STORAGE DRIVER +P: Matthew Dharm +M: mdharm-usb@one-eyed-alien.net +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +S: Maintained +W: http://www.one-eyed-alien.net/~mdharm/linux-usb/ + +USB UHCI DRIVER +P: Georg Acher +M: usb@in.tum.de +L: linux-usb-users@lists.sourceforge.net +L: linux-usb-devel@lists.sourceforge.net +W: http://usb.in.tum.de +S: Maintained + VFAT FILESYSTEM: P: Gordon Chaffee M: chaffee@cs.berkeley.edu @@ -992,9 +1135,9 @@ Z8530 DRIVER FOR AX.25 P: Joerg Reuter -M: jreuter@poboxes.com -W: http://poboxes.com/jreuter/ -W: http://qsl.net/dl1bke/ +M: jreuter@yaina.de +W: http://yaina.de/jreuter +W: http://www.qsl.net/dl1bke/ L: linux-hams@vger.kernel.org S: Maintained diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Makefile linux/Makefile --- v2.2.17/Makefile Sat Sep 9 18:42:32 2000 +++ linux/Makefile Sat Dec 9 21:53:12 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 2 -SUBLEVEL = 17 +SUBLEVEL = 18 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,15 @@ AS =$(CROSS_COMPILE)as LD =$(CROSS_COMPILE)ld -CC =$(CROSS_COMPILE)cc -D__KERNEL__ -I$(HPATH) +# +# foo-bar-gcc for cross builds +# gcc272 for Debian's old compiler for kernels +# kgcc for Conectiva and Red Hat 7 +# otherwise 'cc' +# +CC =$(shell if [ -n "$(CROSS_COMPILE)" ]; then echo $(CROSS_COMPILE)gcc; else \ + $(CONFIG_SHELL) scripts/kwhich gcc272 2>/dev/null || $(CONFIG_SHELL) scripts/kwhich kgcc 2>/dev/null || echo cc; fi) \ + -D__KERNEL__ -I$(HPATH) CPP =$(CC) -E AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm @@ -111,7 +119,7 @@ FILESYSTEMS =fs/filesystems.a NETWORKS =net/network.a DRIVERS =drivers/block/block.a \ - drivers/char/char.a \ + drivers/char/char.o \ drivers/misc/misc.a LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib @@ -135,7 +143,7 @@ endif ifeq ($(CONFIG_SOUND),y) -DRIVERS := $(DRIVERS) drivers/sound/sound.a +DRIVERS := $(DRIVERS) drivers/sound/sounddrivers.o endif ifdef CONFIG_PCI @@ -162,8 +170,8 @@ DRIVERS := $(DRIVERS) drivers/net/fc/fc.a endif -ifdef CONFIG_PPC -DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a +ifdef CONFIG_POWERMAC +DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.o endif ifdef CONFIG_PNP @@ -191,7 +199,7 @@ endif ifeq ($(CONFIG_USB),y) -DRIVERS := $(DRIVERS) drivers/usb/usb.a +DRIVERS := $(DRIVERS) drivers/usb/usbdrv.o endif ifeq ($(CONFIG_I2O),y) @@ -327,6 +335,7 @@ MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE); \ mkdir -p $$MODLIB; \ rm -f $$MODLIB/build; \ + [ `/sbin/insmod -V 2>&1 | head -1 | awk '/^insmod version /{split($$3, a, /\./); printf "%d%03d%03d\n", a[1], a[2], a[3];}'`0 -ge 20030140 ] && \ ln -s `pwd` $$MODLIB/build; \ cd modules; \ MODULES=""; \ @@ -348,7 +357,10 @@ 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 USB_MODULES ]; then inst_mod USB_MODULES usb; fi; \ + if [ -f USB_SERIAL_MODULES ]; then inst_mod USB_SERIAL_MODULES usb; fi; \ if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES net; fi; \ + if [ -f SKFP_MODULES ]; then inst_mod SKFP_MODULES net; fi; \ \ for f in *.o; do [ -r $$f ] && echo $$f; done | sort > $$MODLIB/.allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/Rules.make linux/Rules.make --- v2.2.17/Rules.make Sat Sep 9 18:42:32 2000 +++ linux/Rules.make Sat Oct 28 15:08:05 2000 @@ -77,7 +77,7 @@ $(O_TARGET): $(ALL_O) rm -f $@ ifneq "$(strip $(ALL_O))" "" - $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(ALL_O) + $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(ALL_O), $^) else $(AR) rcs $@ endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile --- v2.2.17/arch/alpha/boot/Makefile Fri Apr 21 12:45:44 2000 +++ linux/arch/alpha/boot/Makefile Tue Nov 28 20:13:55 2000 @@ -80,7 +80,7 @@ $(OBJSTRIP) -vb bootpheader tools/bootph $(OBJSTRIP): $(OBJSTRIP).c - $(HOSTCC) $(OBJSTRIP).c -o $(OBJSTRIP) + $(HOSTCC) -I$(HPATH) $(OBJSTRIP).c -o $(OBJSTRIP) tools/mkbb: tools/mkbb.c $(HOSTCC) tools/mkbb.c -o tools/mkbb diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/config.in linux/arch/alpha/config.in --- v2.2.17/arch/alpha/config.in Sat Sep 9 18:42:32 2000 +++ linux/arch/alpha/config.in Fri Sep 1 13:51:28 2000 @@ -268,7 +268,7 @@ endmenu source drivers/char/Config.in - +source drivers/usb/Config.in source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.2.17/arch/alpha/kernel/alpha_ksyms.c Sun Jun 11 21:44:08 2000 +++ linux/arch/alpha/kernel/alpha_ksyms.c Tue Nov 28 22:20:17 2000 @@ -37,6 +37,7 @@ 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 spinlock_t rtc_lock; /* these are C runtime functions with special calling conventions: */ extern void __divl (void); @@ -188,6 +189,8 @@ EXPORT_SYMBOL(local_irq_count); #endif /* __SMP__ */ +EXPORT_SYMBOL(rtc_lock); + /* * The following are special because they're not called * explicitly (the C compiler or assembler generates them in @@ -207,5 +210,6 @@ EXPORT_SYMBOL_NOVERS(__remqu); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memscan); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.2.17/arch/alpha/kernel/bios32.c Sun Jun 11 21:44:08 2000 +++ linux/arch/alpha/kernel/bios32.c Fri Sep 15 12:43:11 2000 @@ -828,6 +828,7 @@ for (dev = bus->devices; dev; dev = dev->sibling) { if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || + (dev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) { disable_dev(dev); } @@ -840,6 +841,7 @@ for (dev = bus->devices; dev; dev = dev->sibling) { if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || + (dev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) { layout_dev(dev); } @@ -1081,6 +1083,7 @@ */ for (dev = pci_devices; dev; dev = dev->next) { if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && + (dev->class >> 8 != PCI_CLASS_BRIDGE_OTHER) && (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) continue; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.2.17/arch/alpha/kernel/core_mcpcia.c Sun Jun 11 21:44:08 2000 +++ linux/arch/alpha/kernel/core_mcpcia.c Sat Oct 14 00:46:52 2000 @@ -190,7 +190,7 @@ { unsigned long addr; - if (!pci_probe_enabled) + if (!pci_probe_enabled || !hose->pci_config_space) return -1; DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.2.17/arch/alpha/kernel/core_tsunami.c Fri Apr 21 12:45:44 2000 +++ linux/arch/alpha/kernel/core_tsunami.c Sat Oct 14 00:46:52 2000 @@ -91,7 +91,7 @@ { unsigned long addr; - if (!pci_probe_enabled) + if (!pci_probe_enabled || !hose->pci_config_space) return -1; DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.2.17/arch/alpha/kernel/setup.c Sat Sep 9 18:42:32 2000 +++ linux/arch/alpha/kernel/setup.c Mon Oct 2 16:44:31 2000 @@ -841,7 +841,7 @@ hwrpb->pagesize, hwrpb->pa_bits, hwrpb->max_asn, - loops_per_sec / 500000, (loops_per_sec / 5000) % 100, + loops_per_jiffy * HZ / 500000, (loops_per_jiffy * HZ / 5000) % 100, unaligned[0].count, unaligned[0].pc, unaligned[0].va, unaligned[1].count, unaligned[1].pc, unaligned[1].va, platform_string(), nr_processors); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.2.17/arch/alpha/kernel/smp.c Sun Jun 11 21:44:09 2000 +++ linux/arch/alpha/kernel/smp.c Sat Oct 14 00:46:52 2000 @@ -94,7 +94,7 @@ static inline void __init smp_store_cpu_info(int cpuid) { - cpu_data[cpuid].loops_per_sec = loops_per_sec; + cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy; cpu_data[cpuid].last_asn = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION; @@ -543,12 +543,12 @@ bogosum = 0; for (i = 0; i < NR_CPUS; i++) { if (cpu_present_mask & (1L << i)) - bogosum += cpu_data[i].loops_per_sec; + bogosum += cpu_data[i].loops_per_jiffy; } printk(KERN_INFO "SMP: Total of %d processors activated " "(%lu.%02lu BogoMIPS).\n", - cpu_count, (bogosum + 2500) / 500000, - ((bogosum + 2500) / 5000) % 100); + cpu_count, (bogosum + 2500) / (500000 / HZ), + ((bogosum + 2500) / (5000 / HZ)) % 100); smp_num_cpus = cpu_count; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.2.17/arch/alpha/kernel/time.c Sun Jun 11 21:44:09 2000 +++ linux/arch/alpha/kernel/time.c Tue Sep 12 13:14:57 2000 @@ -47,6 +47,7 @@ static int set_rtc_mmss(unsigned long); +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; /* * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting @@ -455,6 +456,8 @@ int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* irq are locally disabled here */ + spin_lock(&rtc_lock); /* Tell the clock it's being set */ save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -504,6 +507,7 @@ */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/lib/csum_partial_copy.c linux/arch/alpha/lib/csum_partial_copy.c --- v2.2.17/arch/alpha/lib/csum_partial_copy.c Fri Apr 21 12:45:44 2000 +++ linux/arch/alpha/lib/csum_partial_copy.c Sat Sep 2 23:17:03 2000 @@ -173,11 +173,11 @@ { unsigned long carry = 0; unsigned long word; + unsigned long second_dest; int err = 0; mskql(partial_dest, doff, partial_dest); while (len >= 0) { - unsigned long second_dest; err |= __get_user(word, src); len -= 8; insql(word, doff, second_dest); @@ -189,35 +189,30 @@ carry = checksum < word; dst++; } - len += doff; - checksum += carry; - if (len >= 0) { - unsigned long second_dest; + len += 8; + if (len) { + checksum += carry; err |= __get_user(word, src); - mskql(word, len-doff, word); + mskql(word, len, word); + len -= 8; checksum += word; insql(word, doff, second_dest); - stq_u(partial_dest | second_dest, dst); + len += doff; carry = checksum < word; - if (len) { - ldq_u(second_dest, dst+1); + partial_dest |= second_dest; + if (len >= 0) { + stq_u(partial_dest, dst); + if (!len) goto out; + dst++; insqh(word, doff, partial_dest); - mskqh(second_dest, len, second_dest); - stq_u(partial_dest | second_dest, dst+1); } - checksum += carry; - } else if (len & 7) { - unsigned long second_dest; - err |= __get_user(word, src); - ldq_u(second_dest, dst); - mskql(word, len-doff, word); - checksum += word; - mskqh(second_dest, len, second_dest); - carry = checksum < word; - insql(word, doff, word); - stq_u(partial_dest | word | second_dest, dst); - checksum += carry; + doff = len; } + ldq_u(second_dest, dst); + mskqh(second_dest, doff, second_dest); + stq_u(partial_dest | second_dest, dst); +out: + checksum += carry; if (err) *errp = err; return checksum; } @@ -283,7 +278,7 @@ stq_u(partial_dest | second_dest, dst+1); } checksum += carry; - } else if (len & 7) { + } else { unsigned long second, word; unsigned long second_dest; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/math-emu/Makefile linux/arch/alpha/math-emu/Makefile --- v2.2.17/arch/alpha/math-emu/Makefile Fri Apr 21 12:45:45 2000 +++ linux/arch/alpha/math-emu/Makefile Sun Oct 1 19:12:21 2000 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := math-emu.o -O_OBJS := math.o +O_OBJS := math.o qrnnd.o CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w ifeq ($(CONFIG_MATHEMU),m) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/math-emu/math.c linux/arch/alpha/math-emu/math.c --- v2.2.17/arch/alpha/math-emu/math.c Fri Apr 21 12:45:45 2000 +++ linux/arch/alpha/math-emu/math.c Sun Oct 1 19:12:21 2000 @@ -84,66 +84,6 @@ #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 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/math-emu/qrnnd.S linux/arch/alpha/math-emu/qrnnd.S --- v2.2.17/arch/alpha/math-emu/qrnnd.S Thu Jan 1 01:00:00 1970 +++ linux/arch/alpha/math-emu/qrnnd.S Sun Oct 1 19:12:21 2000 @@ -0,0 +1,163 @@ + # Alpha 21064 __udiv_qrnnd + # Copyright (C) 1992, 1994, 1995, 2000 Free Software Foundation, Inc. + + # This file is part of GCC. + + # The GNU MP Library 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. + + # In addition to the permissions in the GNU General Public License, the + # Free Software Foundation gives you unlimited permission to link the + # compiled version of this file with other programs, and to distribute + # those programs without any restriction coming from the use of this + # file. (The General Public License restrictions do apply in other + # respects; for example, they cover modification of the file, and + # distribution when not linked into another program.) + + # This file 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 General Public License + # along with GCC; see the file COPYING. If not, write to the + # Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + # MA 02111-1307, USA. + + .set noreorder + .set noat + + .text + + .globl __udiv_qrnnd + .ent __udiv_qrnnd +__udiv_qrnnd: + .frame $30,0,$26,0 + .prologue 0 + +#define cnt $2 +#define tmp $3 +#define rem_ptr $16 +#define n1 $17 +#define n0 $18 +#define d $19 +#define qb $20 +#define AT $at + + ldiq cnt,16 + blt d,$largedivisor + +$loop1: cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + subq cnt,1,cnt + bgt cnt,$loop1 + stq n1,0(rem_ptr) + bis $31,n0,$0 + ret $31,($26),1 + +$largedivisor: + and n0,1,$4 + + srl n0,1,n0 + sll n1,63,tmp + or tmp,n0,n0 + srl n1,1,n1 + + and d,1,$6 + srl d,1,$5 + addq $5,$6,$5 + +$loop2: cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + subq cnt,1,cnt + bgt cnt,$loop2 + + addq n1,n1,n1 + addq $4,n1,n1 + bne $6,$Odd + stq n1,0(rem_ptr) + bis $31,n0,$0 + ret $31,($26),1 + +$Odd: + /* q' in n0. r' in n1 */ + addq n1,n0,n1 + + cmpult n1,n0,tmp # tmp := carry from addq + subq n1,d,AT + addq n0,tmp,n0 + cmovne tmp,AT,n1 + + cmpult n1,d,tmp + addq n0,1,AT + cmoveq tmp,AT,n0 + subq n1,d,AT + cmoveq tmp,AT,n1 + + stq n1,0(rem_ptr) + bis $31,n0,$0 + ret $31,($26),1 + + .end __udiv_qrnnd diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/math-emu/sfp-util.h linux/arch/alpha/math-emu/sfp-util.h --- v2.2.17/arch/alpha/math-emu/sfp-util.h Fri Apr 21 12:45:45 2000 +++ linux/arch/alpha/math-emu/sfp-util.h Sun Oct 1 19:12:21 2000 @@ -17,18 +17,13 @@ : "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; \ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { unsigned long __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ } while (0) +extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long, + unsigned long , unsigned long); #define UDIV_NEEDS_NORMALIZATION 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds --- v2.2.17/arch/alpha/vmlinux.lds Sun Jun 11 21:44:09 2000 +++ linux/arch/alpha/vmlinux.lds Fri Sep 15 12:46:07 2000 @@ -27,11 +27,22 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + + . = ALIGN(8); + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(2*8192); /* Align double page for init_task_union */ __init_end = .; /* The initial task and kernel stack */ init_task : { *(init_task) } + /* Global data */ _data = .; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/Makefile linux/arch/arm/Makefile --- v2.2.17/arch/arm/Makefile Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/Makefile Fri Sep 15 23:28:37 2000 @@ -10,217 +10,172 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1995, 1996 by Russell King +# Copyright (C) 1995-1999 by Russell King -CFLAGS_PROC := -ASFLAGS_PROC := +LD := $(CROSS_COMPILE)ld +OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S +OBJDUMP = $(CROSS_COMPILE)objdump +CPP := $(CC) -E +PERL := perl +LINKFLAGS := -p -X -T arch/arm/vmlinux.lds +ARCHCC := $(word 1,$(CC)) + +AFLAGS += -mno-fpu +CFLAGS_PIPE := -pipe +CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) + +ifdef CONFIG_FRAME_POINTER +CFLAGS := $(CFLAGS:-fomit-frame-pointer=) +endif + +ifdef CONFIG_DEBUG_INFO +CFLAGS += -g +endif -# All processors get `-mshort-load-bytes' for now, to work around alignment -# problems. This is more of a hack that just happens to work than a real fix -# but it will do for now. +# Ensure this is ld "2.9.4" or later +NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) + +ifneq ($(NEW_LINKER),y) +dummy:; @echo '*** 2.2 kernels no longer build correctly with old versions of binutils.' + @echo '*** Please upgrade your binutils to 2.9.5.' + @false +endif + + +# GCC 2.7 uses different options to later compilers; sort out which we have +NEW_GCC := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi) + +# +# select flags depending on the compiler +# +ifeq ($(NEW_GCC),y) +CFLAGS += -mshort-load-bytes -msoft-float +CFLAGS_PROC_CPU_26 := -mcpu=arm3 -Os +CFLAGS_PROC_CPU_32v3 := -march=armv3 +CFLAGS_PROC_CPU_32v4 := -march=armv4 +CFLAGS_ARM6 := -mtune=arm6 +CFLAGS_ARM7 := -mtune=arm7 +CFLAGS_SA110 := -mtune=strongarm110 +else +CFLAGS_PROC_CPU_26 := -m3 +CFLAGS_PROC_CPU_32v3 := +CFLAGS_PROC_CPU_32v4 := +CFLAGS_ARM6 := -m6 +CFLAGS_ARM7 := -m6 +CFLAGS_SA110 := -m6 +endif +# +# Select CPU dependent flags +# ifeq ($(CONFIG_CPU_26),y) - PROCESSOR = armo - TEXTADDR = 0x02080000 - ZTEXTADDR = 0x01800000 - ZRELADDR = 0x02080000 - ifeq ($(CONFIG_BINUTILS_NEW),y) - CFLAGS_PROC += -mapcs-26 -mshort-load-bytes - ifeq ($(CONFIG_CPU_ARM2),y) - CFLAGS_PROC += -mcpu=arm2 - ASFLAGS_PROC += -m2 - endif - ifeq ($(CONFIG_CPU_ARM3),y) - CFLAGS_PROC += -mcpu=arm3 - ASFLAGS_PROC += -m3 - endif - else - ifeq ($(CONFIG_CPU_ARM2),y) - CFLAGS_PROC += -m2 - ASFLAGS_PROC += -m2 - endif - ifeq ($(CONFIG_CPU_ARM3),y) - CFLAGS_PROC += -m3 - ASFLAGS_PROC += -m3 - endif - endif + PROCESSOR = armo + TEXTADDR = 0x02080000 + CFLAGS += $(CFLAGS_PROC_CPU_26) + AFLAGS += -mapcs-26 endif ifeq ($(CONFIG_CPU_32),y) - PROCESSOR = armv - TEXTADDR = 0xC0008000 - ifeq ($(CONFIG_BINUTILS_NEW),y) - CFLAGS_PROC += -mapcs-32 -mshort-load-bytes - ifeq ($(CONFIG_CPU_ARM6),y) - CFLAGS_PROC += -mcpu=arm6 - endif - ifeq ($(CONFIG_CPU_ARM7),y) - CFLAGS_PROC += -mcpu=arm7 - endif - ifeq ($(CONFIG_CPU_SA110),y) - CFLAGS_PROC += -mcpu=strongarm110 - endif - else - CFLAGS_PROC += -m6 - endif - ASFLAGS_PROC += -m6 -endif - -# Processor Architecture -# CFLAGS_PROC - processor dependent CFLAGS -# PROCESSOR - processor type -# TEXTADDR - Uncompressed kernel link text address -# ZTEXTADDR - Compressed kernel link text address -# ZRELADDR - Compressed kernel relocating address (point at which uncompressed kernel is loaded). -# + PROCESSOR = armv + TEXTADDR = 0xC0008000 + ifeq ($(CONFIG_CPU_32v4),y) + CFLAGS += $(CFLAGS_PROC_CPU_32v4) + AFLAGS += -mapcs-32 -marmv4 + else + CFLAGS += $(CFLAGS_PROC_CPU_32v3) + AFLAGS += -mapcs-32 -marmv3m + endif + # + # Exactly one of the following must be selected + # + ifeq ($(CONFIG_CPU_ARM6),y) + CFLAGS += $(CFLAGS_ARM6) + else + ifeq ($(CONFIG_CPU_ARM7),y) + CFLAGS += $(CFLAGS_ARM7) + else + ifeq ($(CONFIG_CPU_SA110),y) + CFLAGS += $(CFLAGS_SA110) + endif + endif + endif +endif -COMPRESSED_HEAD = head.o +GCCLIB := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) ifeq ($(CONFIG_ARCH_A5K),y) MACHINE = a5k ARCHDIR = arc -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o endif ifeq ($(CONFIG_ARCH_ARC),y) MACHINE = arc ARCHDIR = arc -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o endif ifeq ($(CONFIG_ARCH_RPC),y) MACHINE = rpc ARCHDIR = rpc -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o -ZTEXTADDR = 0x10008000 -ZRELADDR = 0x10008000 endif ifeq ($(CONFIG_ARCH_EBSA110),y) MACHINE = ebsa110 ARCHDIR = ebsa110 -ZTEXTADDR = 0x00008000 -ZRELADDR = 0x00008000 endif -ifeq ($(CONFIG_ARCH_EBSA285),y) -MACHINE = ebsa285 +ifeq ($(CONFIG_FOOTBRIDGE),y) +MACHINE = footbridge ARCHDIR = ebsa285 -ZTEXTADDR = 0x00008000 -ZRELADDR = 0x00008000 +endif + +ifeq ($(CONFIG_ARCH_CO285),y) +TEXTADDR = 0x60008000 endif ifeq ($(CONFIG_ARCH_NEXUSPCI),y) MACHINE = nexuspci ARCHDIR = nexuspci -ZTEXTADDR = 0x40200000 -ZRELADDR = 0x40008000 -COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o -COMPRESSED_HEAD = head-nexuspci.o -endif - -ifeq ($(CONFIG_ARCH_VNC),y) -TEXTADDR = 0xC000C000 -MACHINE = vnc -ARCHDIR = vnc -endif - -ifeq ($(CONFIG_ARCH_TBOX),y) -MACHINE = tbox -ARCHDIR = tbox -ZTEXTADDR = 0x80008000 -ZRELDIR = 0x80008000 endif -PERL = perl -ifeq ($(CONFIG_BINUTILS_NEW),y) -LD = $(CROSS_COMPILE)ld -m elf32arm -else -LD = $(CROSS_COMPILE)ld -m elf_arm -endif -OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S -OBJDUMP = $(CROSS_COMPILE)objdump -CPP = $(CC) -E -ARCHCC := $(word 1,$(CC)) -GCCLIB := `$(CC) $(CFLAGS_PROC) --print-libgcc-file-name` -#GCCARCH := -B/usr/bin/arm-linuxelf- -HOSTCFLAGS := $(CFLAGS:-fomit-frame-pointer=) -ifeq ($(CONFIG_FRAME_POINTER),y) -CFLAGS := $(CFLAGS:-fomit-frame-pointer=) -endif -CFLAGS := $(CFLAGS_PROC) $(CFLAGS) -pipe -ASFLAGS := $(ASFLAGS_PROC) $(ASFLAGS) -LINKFLAGS = -T $(TOPDIR)/arch/arm/vmlinux-$(PROCESSOR).lds -e stext -Ttext $(TEXTADDR) -ZLINKFLAGS = -Ttext $(ZTEXTADDR) - -SUBDIRS := $(SUBDIRS:drivers=arch/arm/drivers) arch/arm/lib arch/arm/kernel arch/arm/mm -HEAD := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o +HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ + arch/arm/kernel/init_task.o +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 -BLOCK_DRIVERS := drivers/block/block.a -CDROM_DRIVERS := drivers/cdrom/cdrom.a -ifeq ($(CONFIG_FB),y) -CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a -else -ifeq ($(CONFIG_VGA_CONSOLE),y) -CHAR_DRIVERS := arch/arm/drivers/char1/char1.a drivers/char/char.a arch/arm/drivers/char1/char1.a -else -CHAR_DRIVERS := arch/arm/drivers/char/char.a +ifeq ($(CONFIG_NWFPE),y) +LIBS := arch/arm/nwfpe/math-emu.a $(LIBS) endif -endif -MISC_DRIVERS := drivers/misc/misc.a -NET_DRIVERS := drivers/net/net.a -PARIDE_DRIVERS := drivers/block/paride/paride.a -PCI_DRIVERS := drivers/pci/pci.a -SCSI_DRIVERS := drivers/scsi/scsi.a -SOUND_DRIVERS := drivers/sound/sound.a -VIDEO_DRIVERS := drivers/video/video.a -PNP_DRIVERS := drivers/pnp/pnp.a ifeq ($(CONFIG_ARCH_ACORN),y) -BLOCK_DRIVERS += drivers/acorn/block/acorn-block.a -CHAR_DRIVERS += drivers/acorn/char/acorn-char.a -NET_DRIVERS += drivers/acorn/net/acorn-net.a drivers/net/net.a -SCSI_DRIVERS += drivers/acorn/scsi/acorn-scsi.a +SUBDIRS += drivers/acorn +DRIVERS += drivers/acorn/block/acorn-block.a +DRIVERS += drivers/acorn/char/acorn-char.a +DRIVERS += drivers/acorn/net/acorn-net.a +DRIVERS += drivers/acorn/scsi/acorn-scsi.a endif -DRIVERS := $(BLOCK_DRIVERS) $(CHAR_DRIVERS) $(MISC_DRIVERS) $(NET_DRIVERS) +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -ifeq ($(CONFIG_FB),y) -DRIVERS := $(DRIVERS) $(VIDEO_DRIVERS) -else -ifeq ($(CONFIG_VGA_CONSOLE),y) -DRIVERS := $(DRIVERS) $(VIDEO_DRIVERS) -endif -endif -ifeq ($(CONFIG_SCSI),y) -DRIVERS := $(DRIVERS) $(SCSI_DRIVERS) -endif -ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),) -DRIVERS := $(DRIVERS) $(CDROM_DRIVERS) -endif -ifdef CONFIG_PCI -DRIVERS := $(DRIVERS) $(PCI_DRIVERS) -endif -ifeq ($(CONFIG_SOUND),y) -DRIVERS := $(DRIVERS) $(SOUND_DRIVERS) -endif -ifeq ($(CONFIG_PARIDE),y) -DRIVERS := $(DRIVERS) $(PARIDE_DRIVERS) -endif -ifdef CONFIG_PNP -DRIVERS := $(DRIVERS) $(PNP_DRIVERS) -endif +# The following is a hack to get 'constants.h' up +# to date before starting compilation +CONSTANTS := constants + +constants: $(TOPDIR)/include/asm-arm/proc-fns.h dummy + @$(MAKE) -C arch/arm/lib constants.h + +symlinks: archsymlinks -symlinks:: +archsymlinks: $(RM) include/asm-arm/arch include/asm-arm/proc (cd include/asm-arm; ln -sf arch-$(ARCHDIR) arch; ln -sf proc-$(PROCESSOR) proc) -# Once we've finished integrating the sources, the @$(MAKE) will disappear -archmrproper: - rm -f include/asm-arm/arch include/asm-arm/proc - @$(MAKE) -C arch/$(ARCH)/drivers mrproper +vmlinux: arch/arm/vmlinux.lds + +arch/arm/vmlinux.lds: arch/arm/vmlinux-$(PROCESSOR).lds.in dummy + @sed 's/TEXTADDR/$(TEXTADDR)/' <$< >$@ arch/arm/kernel: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel @@ -231,19 +186,19 @@ arch/arm/lib: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/arm/lib -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +zImage zinstall Image install: vmlinux + @$(MAKEBOOT) $@ -zImage: vmlinux - @$(MAKEBOOT) zImage - -zinstall: vmlinux - @$(MAKEBOOT) zinstall +archmrproper: + @$(MAKE) -C arch/$(ARCH)/special mrproper + $(RM) include/asm-arm/arch include/asm-arm/proc -Image: vmlinux - @$(MAKEBOOT) Image +archclean: + @$(MAKEBOOT) clean + $(RM) arch/arm/lib/constants.h arch/arm/vmlinux.lds -install: vmlinux - @$(MAKEBOOT) install +archdep: + @$(MAKEBOOT) dep # My testing targets (that short circuit a few dependencies) zImg:; @$(MAKEBOOT) zImage @@ -251,10 +206,23 @@ i:; @$(MAKEBOOT) install zi:; @$(MAKEBOOT) zinstall -archclean: - @$(MAKEBOOT) clean - $(RM) arch/arm/lib/constants.h +# +# Configuration targets. Use these to select a +# configuration for your architecture +# +a5k_config: + $(RM) arch/arm/defconfig + cp arch/arm/def-configs/a5k arch/arm/defconfig + +ebsa110_config: + $(RM) arch/arm/defconfig + cp arch/arm/def-configs/ebsa110 arch/arm/defconfig + +footbridge_config: + $(RM) arch/arm/defconfig + cp arch/arm/def-configs/footbridge arch/arm/defconfig + +rpc_config: + $(RM) arch/arm/defconfig + cp arch/arm/def-configs/rpc arch/arm/defconfig -archdep: - @$(MAKEBOOT) dep -sed -e /^MACHINE..*=/s,= .*,= rpc,;/^PROCESSOR..*=/s,= .*,= armv, linux/arch/arm/Makefile.normal diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile --- v2.2.17/arch/arm/boot/Makefile Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/boot/Makefile Mon Oct 2 10:12:51 2000 @@ -20,10 +20,10 @@ @$(MAKE) -C compressed vmlinux install: $(CONFIGURE) Image - sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" zinstall: $(CONFIGURE) zImage - sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" clean: rm -f Image zImage diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.2.17/arch/arm/boot/compressed/Makefile Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/boot/compressed/Makefile Fri Sep 15 23:28:37 2000 @@ -2,32 +2,97 @@ # linux/arch/arm/boot/compressed/Makefile # # create a compressed vmlinuz image from the original vmlinux + +HEAD = head.o +OBJS = misc.o +SYSTEM = $(TOPDIR)/vmlinux +CFLAGS = -O2 -DSTDC_HEADERS $(CFLAGS_PROC) +FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c +ZLDFLAGS = -p -X -T vmlinux.lds + # -# With this config, max compressed image size = 640k -# Uncompressed image size = 1.3M (text+data) +# Architecture dependencies +# +ifeq ($(CONFIG_ARCH_ACORN),y) +OBJS += ll_char_wr.o font.o +endif + +ifeq ($(CONFIG_CPU_26),y) +ZTEXTADDR = 0x02080000 +endif + +ifeq ($(CONFIG_ARCH_RPC),y) +ZTEXTADDR = 0x10008000 +endif + +ifeq ($(CONFIG_ARCH_EBSA110),y) +ZTEXTADDR = 0x00008000 +endif + +ifeq ($(CONFIG_FOOTBRIDGE),y) +ZTEXTADDR = 0x00008000 +endif + +ifeq ($(CONFIG_ARCH_NETWINDER),y) +OBJS += head-netwinder.o +endif + +ifeq ($(CONFIG_ARCH_NEXUSPCI),y) +HEAD = head-nexuspci.o +OBJS += $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o +ZTEXTADDR = 0x40200000 +ZRELADDR = 0x40008000 +endif + +ifeq ($(CONFIG_ARCH_SA1100),y) +OBJS += head-sa1100.o +ifeq ($(CONFIG_SA1100_VICTOR),y) +ZTEXTADDR = 0x00002000 +ZBSSADDR = 0xc0100000 +else +ZTEXTADDR = 0xc0008000 +endif +ZRELADDR = 0xc0008000 +endif -SYSTEM =$(TOPDIR)/vmlinux -HEAD =$(COMPRESSED_HEAD) -OBJS =$(HEAD) misc.o $(COMPRESSED_EXTRA) -CFLAGS =-O2 -DSTDC_HEADERS $(CFLAGS_PROC) -ARFLAGS =rc +# +# If you don't define ZRELADDR above, +# then it defaults to ZTEXTADDR +# +ifeq ($(ZRELADDR),) +ZRELADDR = $(ZTEXTADDR) +endif + +SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/; + +ifneq ($(ZBSSADDR),) +SEDFLAGS += s/BSS_START/$(ZBSSADDR)/ +else +SEDFLAGS += s/BSS_START/ALIGN(4)/ +endif all: vmlinux -vmlinux: piggy.o $(OBJS) - $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJS) piggy.o +vmlinux: $(HEAD) $(OBJS) piggy.o vmlinux.lds + $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux $(HEAD): $(HEAD:.o=.S) - $(CC) -traditional -DLOADADDR=$(ZRELADDR) -c $(HEAD:.o=.S) + $(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S) piggy.o: $(SYSTEM) - tmppiggy=_tmp_$$$$piggy; \ - rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ - $(OBJCOPY) $(SYSTEM) $$tmppiggy; \ - gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ - echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ - $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \ - rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; + $(OBJCOPY) $(SYSTEM) piggy + gzip -9 < piggy > piggy.gz + $(LD) -r -o $@ -b binary piggy.gz + rm -f piggy piggy.gz + +font.o: $(FONTC) + $(CC) $(CFLAGS) -Dstatic= -c -o $@ $(FONTC) + +vmlinux.lds: vmlinux.lds.in + @sed "$(SEDFLAGS)" < vmlinux.lds.in > $@ + +clean:; rm -f vmlinux core piggy* vmlinux.lds -clean:; rm -f vmlinux core +.PHONY: vmlinux.lds clean +misc.o: misc.c $(TOPDIR)/include/asm/arch/uncompress.h $(TOPDIR)/lib/inflate.c diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/compressed/head-netwinder.S linux/arch/arm/boot/compressed/head-netwinder.S --- v2.2.17/arch/arm/boot/compressed/head-netwinder.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/boot/compressed/head-netwinder.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,31 @@ + .section ".start", #alloc, #execinstr + + adr r2, 1f + ldmdb r2, {r7, r8} + and r3, r2, #0xc000 + teq r3, #0x8000 + beq 2f + bic r3, r2, #0xc000 + orr r3, r3, #0x8000 + mov r0, r3 + mov r4, #64 + sub r5, r8, r7 + b 1f + + .word _start + .word __bss_start + +1: + .rept 4 + ldmia r2!, {r6, r7, r8, r9} + stmia r3!, {r6, r7, r8, r9} + .endr + subs r4, r4, #64 + 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 +2: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/compressed/head-sa1100.S linux/arch/arm/boot/compressed/head-sa1100.S --- v2.2.17/arch/arm/boot/compressed/head-sa1100.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/boot/compressed/head-sa1100.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.2.17/arch/arm/boot/compressed/head.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/boot/compressed/head.S Fri Sep 15 23:28:37 2000 @@ -1,129 +1,253 @@ /* * linux/arch/arm/boot/compressed/head.S * - * Copyright (C) 1996,1997,1998 Russell King + * Copyright (C) 1996-1999 Russell King */ #include - .text + .section ".start", #alloc, #execinstr /* * sort out different calling conventions */ .align - .globl _start -_start: -start: mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 +start: + .type start,#function + .rept 8 mov r0, r0 + .endr + b 1f - .word 0x016f2818 @ Magic numbers to help the loader - .word _start + .word 0x016f2818 @ Magic numbers to help the loader + .word start +1: + + /* + * some architecture specific code can + * be inserted by the linker here + */ + + .text 1: teq r0, #0 - beq 2f - mov r4, #0x02000000 - add r4, r4, #0x7C000 - mov r3, #0x4000 - sub r3, r3, #4 -1: ldmia r0!, {r5 - r12} - stmia r4!, {r5 - r12} - subs r3, r3, #32 - bpl 1b -2: adr r2, LC0 - ldmia r2, {r2, r3, r4, r5, r6, sp} - add r2, r2, #3 - add r3, r3, #3 - add sp, sp, #3 - bic r2, r2, #3 - bic r3, r3, #3 - bic sp, sp, #3 - adr r7, start - sub r6, r7, r6 -/* - * Relocate pointers - */ - add r2, r2, r6 - add r3, r3, r6 - add r5, r5, r6 - add sp, sp, r6 -/* - * Clear zero-init - */ - mov r6, #0 -1: str r6, [r2], #4 + bne 1b + mov r7, r1 @ save architecture ID + mrc p15, 0, r6, c0, c0 @ get processor ID + adr r2, LC0 + ldmia r2, {r2, r3, r4, r5, sp} + + mov r0, #0 +1: str r0, [r2], #4 @ clear bss + str r0, [r2], #4 + str r0, [r2], #4 + str r0, [r2], #4 cmp r2, r3 blt 1b - str r1, [r5] @ save architecture -/* - * Uncompress the kernel - */ - mov r1, #0x8000 - add r3, r2, r1, lsl #1 @ Add 64k for malloc - sub r1, r1, #1 - add r3, r3, r1 - bic r5, r3, r1 @ decompress kernel to after end of the compressed + + mov r1, sp @ malloc space above stack + add r2, sp, #0x10000 @ 64k max + + teq r4, r5 @ will we overwrite ourselves? + moveq r5, r2 + movne r5, r4 + mov r0, r5 - mov r1, r2 - mov r2, r0 + mov r3, r7 bl SYMBOL_NAME(decompress_kernel) - add r0, r0, #7 - bic r2, r0, #7 + + teq r4, r5 @ do we need to relocate + beq call_kernel @ the kernel? + + add r0, r0, #127 + bic r0, r0, #127 @ align the kernel length /* - * Now move the kernel to the correct location (r5 -> r4, len r0) - */ - mov r0, r4 @ r0 = start of real kernel - mov r1, r5 @ r1 = start of kernel image - add r3, r5, r2 @ r3 = end of kernel - adr r4, movecode - adr r5, movecodeend -1: ldmia r4!, {r6 - r12, lr} - stmia r3!, {r6 - r12, lr} - cmp r4, r5 + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + add r1, r5, r0 @ end of decompressed kernel + adr r2, reloc_start + adr r3, reloc_end +1: ldmia r2!, {r8 - r13} @ copy relocation code + stmia r1!, {r8 - r13} + ldmia r2!, {r8 - r13} + stmia r1!, {r8 - r13} + cmp r2, r3 blt 1b - mrc p15, 0, r5, c0, c0 - eor r5, r5, #0x44 << 24 - eor r5, r5, #0x01 << 16 - eor r5, r5, #0xa1 << 8 - movs r5, r5, lsr #4 - mov r5, #0 - mcreq p15, 0, r5, c7, c5, 0 @ flush I cache - ldr r5, LC0 + 12 @ get architecture - ldr r5, [r5] - add pc, r1, r2 @ Call move code + + eor r1, r6, #0x44 << 24 @ SA-110? + eor r1, r1, #0x01 << 16 + eor r1, r1, #0xa1 << 8 + movs r1, r1, lsr #4 + 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 /* - * r0 = length, r1 = to, r2 = from - */ -movecode: add r3, r1, r2 - mov r4, r0 -1: ldmia r1!, {r6 - r12, lr} - stmia r0!, {r6 - r12, lr} - cmp r1, r3 + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ +reloc_start: add r8, r5, r0 +#if 0 + mov r0, #'\n' + bl putc + mov r0, r6 + mov r1, #8 + bl phex + mov r0, #':' + bl putc + mov r0, r5 + mov r1, #8 + bl phex + mov r0, #'-' + bl putc + mov r0, r8 + mov r1, #8 + bl phex + mov r0, #'>' + bl putc + mov r0, r4 + mov r1, #8 + bl phex + mov r0, #'\n' + bl putc +#endif + mov r0, r8 + mov r1, r4 +1: + .rept 4 + ldmia r5!, {r2, r3, r8 - r13} @ relocate kernel + stmia r1!, {r2, r3, r8 - r13} + .endr + + cmp r5, r0 blt 1b - mrc p15, 0, r0, c0, c0 - eor r0, r0, #0x44 << 24 +#if 0 + mov r8, r0 + mov r0, r5 + mov r1, #8 + bl phex + mov r0, #'-' + bl putc + mov r0, r8 + mov r1, #8 + bl phex + mov r0, #'\n' + bl putc + mov r0, r4 + bl memdump +#endif + eor r0, r6, #0x44 << 24 @ SA-110? eor r0, r0, #0x01 << 16 eor r0, r0, #0xa1 << 8 movs r0, r0, lsr #4 + mcreq p15, 0, r0, c7, c7, 0 @ flush I cache + mcreq p15, 0, r1, c7, c10, 4 @ drain WB + +call_kernel: mov r0, #0 + mov r1, r7 @ restore architecture number + mov pc, r4 @ call kernel + +phexbuf: .space 12 + +#if 0 + .macro loadsp, rb + mov \rb, #0x7c000000 + .endm + + .macro writeb, rb + strb \rb, [r3, #0x3f8] + .endm +#else + .macro loadsp, rb + mov \rb, #0x03000000 + orr \rb, \rb, #0x00010000 + .endm + + .macro writeb, rb + strb \rb, [r3, #0x3f8 << 2] + .endm +#endif + +phex: adr r3, phexbuf + mov r2, #0 + strb r2, [r3, r1] +1: subs r1, r1, #1 + movmi r0, r3 + bmi puts + and r2, r0, #15 + mov r0, r0, lsr #4 + cmp r2, #10 + addge r2, r2, #7 + add r2, r2, #'0' + strb r2, [r3, r1] + b 1b + +puts: loadsp r3 +1: ldrb r2, [r0], #1 + teq r2, #0 + moveq pc, lr +2: writeb r2 + mov r1, #0x00020000 +3: subs r1, r1, #1 + bne 3b + teq r2, #'\n' + moveq r2, #'\r' + beq 2b + teq r0, #0 + bne 1b + mov pc, lr +putc: + mov r2, r0 mov r0, #0 - mcreq p15, 0, r0, c7, c5, 0 @ flush I cache - mov r1, r5 @ call kernel correctly - mov pc, r4 @ call via EXEC entry -movecodeend: - -LC0: .word SYMBOL_NAME(_edata) - .word SYMBOL_NAME(_end) - .word LOADADDR - .word SYMBOL_NAME(architecture) - .word start - .word SYMBOL_NAME(user_stack)+4096 - .align + loadsp r3 + b 2b - .bss -SYMBOL_NAME(architecture): - .space 4 +memdump: mov r12, r0 + mov r10, lr + mov r1, #8 + bl phex + mov r0, #'\n' + bl putc + mov r11, #0 +2: mov r0, r11, lsl #2 + mov r1, #4 + bl phex + mov r0, #':' + bl putc +1: mov r0, #' ' + bl putc + ldr r0, [r12, r11, lsl #2] + mov r1, #8 + bl phex + and r0, r11, #7 + teq r0, #3 + moveq r0, #' ' + bleq putc + and r0, r11, #7 + add r11, r11, #1 + teq r0, #7 + bne 1b + mov r0, #'\n' + bl putc + cmp r11, #64 + blt 2b + mov pc, r10 +reloc_end: + +LC0: .word __bss_start + .word _end + .word _load_addr + .word _start + .word user_stack+4096 .align + + .section ".stack" +user_stack: .space 4096 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/compressed/ll_char_wr.S linux/arch/arm/boot/compressed/ll_char_wr.S --- v2.2.17/arch/arm/boot/compressed/ll_char_wr.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/boot/compressed/ll_char_wr.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,158 @@ +/* + * linux/arch/arm/lib/ll_char_wr.S + * + * Copyright (C) 1995, 1996 Russell King. + * + * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King. + * + * 10-04-96 RMK Various cleanups & reduced register usage. + * 08-04-98 RMK Shifts re-ordered + */ + +@ Regs: [] = corruptible +@ {} = used +@ () = do not use +#define __ASSEMBLY__ +#include +#include + .text + +#define BOLD 0x01 +#define ITALIC 0x02 +#define UNDERLINE 0x04 +#define FLASH 0x08 +#define INVERSE 0x10 + +LC0: .word SYMBOL_NAME(bytes_per_char_h) + .word SYMBOL_NAME(video_size_row) + .word SYMBOL_NAME(acorndata_8x8) + .word SYMBOL_NAME(con_charconvtable) + +ENTRY(ll_write_char) + stmfd sp!, {r4 - r7, lr} +@ +@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ + eor ip, r1, #UNDERLINE << 9 +/* + * calculate colours + */ + tst r1, #INVERSE << 9 + moveq r2, r1, lsr #16 + moveq r3, r1, lsr #24 + movne r2, r1, lsr #24 + movne r3, r1, lsr #16 + and r3, r3, #255 + and r2, r2, #255 +/* + * calculate offset into character table + */ + mov r1, r1, lsl #23 + mov r1, r1, lsr #20 +/* + * calculate offset required for each row [maybe I should make this an argument to this fn. + * Have to see what the register usage is like in the calling routines. + */ + adr r4, LC0 + ldmia r4, {r4, r5, r6, lr} + ldr r4, [r4] + ldr r5, [r5] +/* + * Go to resolution-dependent routine... + */ + cmp r4, #4 + blt Lrow1bpp + eor r2, r3, r2 @ Create eor mask to change colour from bg + orr r3, r3, r3, lsl #8 @ to fg. + orr r3, r3, r3, lsl #16 + add r0, r0, r5, lsl #3 @ Move to bottom of character + add r1, r1, #7 + ldrb r7, [r6, r1] + tst ip, #UNDERLINE << 9 + eoreq r7, r7, #255 + teq r4, #8 + beq Lrow8bpplp +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ + orr r3, r3, r3, lsl #4 +Lrow4bpplp: ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow4bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ +Lrow8bpplp: mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + eor r4, r3, r4 @ avoid ip + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + eor ip, r3, ip + stmia r0, {r4, ip} + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + eor r4, r3, r4 @ avoid ip + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + eor ip, r3, ip + stmia r0, {r4, ip} + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow8bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ +Lrow1bpp: add r6, r6, r1 + ldmia r6, {r4, r7} + tst ip, #INVERSE << 9 + mvnne r4, r4 + mvnne r7, r7 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + tst ip, #UNDERLINE << 9 + mvneq r7, r7 + strb r7, [r0], r5 + LOADREGS(fd, sp!, {r4 - r7, pc}) + + .bss +ENTRY(con_charconvtable) + .space 1024 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/compressed/misc.c linux/arch/arm/boot/compressed/misc.c --- v2.2.17/arch/arm/boot/compressed/misc.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/boot/compressed/misc.c Fri Sep 15 23:28:37 2000 @@ -7,8 +7,17 @@ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 * * Modified for ARM Linux by Russell King + * + * Nicolas Pitre 1999/04/14 : + * For this code to run directly from Flash, all constant variables must + * be marked with 'const' and all other variables initialized at run-time + * only. This way all non constant variables will end up in the bss segment, + * which should point to addresses in RAM and cleared to 0 on start. + * This allows for a much quicker boot time. */ +unsigned int __machine_arch_type; + #include #include #include @@ -22,7 +31,7 @@ /* * Optimised C version of memzero for the ARM. */ -extern __inline__ __ptr_t __memzero (__ptr_t s, size_t n) +void __memzero (__ptr_t s, __kernel_size_t n) { union { void *vp; unsigned long *ulp; unsigned char *ucp; } u; int i; @@ -62,11 +71,8 @@ if (n & 1) *u.ucp++ = 0; - return s; } -#define memzero(s,n) __memzero(s,n) - extern __inline__ __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src, size_t __n) { @@ -157,11 +163,11 @@ static void gzip_release(void **); extern char input_data[]; -extern int input_len; +extern char input_data_end[]; static uch *output_data; static ulg output_ptr; -static ulg bytes_out = 0; +static ulg bytes_out; static void *malloc(int size); static void free(void *where); @@ -226,13 +232,14 @@ * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed. */ -int fill_inbuf() +int fill_inbuf(void) { if (insize != 0) error("ran out of input data\n"); inbuf = input_data; - insize = input_len; + insize = &input_data_end[0] - &input_data[0]; + inptr = 1; return inbuf[0]; } @@ -241,7 +248,7 @@ * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ -void flush_window() +void flush_window(void) { ulg c = crc; unsigned n; @@ -257,6 +264,7 @@ bytes_out += (ulg)outcnt; output_ptr += (ulg)outcnt; outcnt = 0; + puts("."); } static void error(char *x) @@ -270,26 +278,24 @@ while(1); /* Halt */ } -#define STACK_SIZE (4096) - -ulg user_stack [STACK_SIZE]; - #ifndef STANDALONE_DEBUG -ulg decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p) -{ - free_mem_ptr = free_mem_ptr_p; - free_mem_ptr_end = free_mem_ptr_end_p; - - proc_decomp_setup (); - arch_decomp_setup (); +ulg +decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, + int arch_id) +{ + output_data = (uch *)output_start; /* Points to kernel start */ + free_mem_ptr = free_mem_ptr_p; + free_mem_ptr_end = free_mem_ptr_end_p; + __machine_arch_type = arch_id; - output_data = (uch *)output_start; /* Points to kernel start */ + proc_decomp_setup(); + arch_decomp_setup(); makecrc(); puts("Uncompressing Linux..."); gunzip(); - puts("done.\nNow booting the kernel\n"); + puts(" done, booting the kernel.\n"); return output_ptr; } #else diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/boot/compressed/vmlinux.lds.in linux/arch/arm/boot/compressed/vmlinux.lds.in --- v2.2.17/arch/arm/boot/compressed/vmlinux.lds.in Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/boot/compressed/vmlinux.lds.in Fri Sep 15 23:28:37 2000 @@ -0,0 +1,52 @@ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = LOAD_ADDR; + _load_addr = .; + + . = TEXT_START; + _text = .; + + .text : { + _start = .; + head.o(.start) + *(.start) + head.o(.text) + *(.text) + *(.fixup) + *(.gnu.warning) + input_data = .; + piggy.o + input_data_end = .; + . = ALIGN(4); + } + + _etext = .; + + .data : { + *(.data) + } + + _edata = .; + + . = BSS_START; + __bss_start = .; + .bss : { + *(.bss) + } + _end = .; + + .stack : { + *(.stack) + } + + .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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/config.in linux/arch/arm/config.in --- v2.2.17/arch/arm/config.in Sun Jun 11 21:44:09 2000 +++ linux/arch/arm/config.in Fri Sep 15 23:28:37 2000 @@ -7,6 +7,11 @@ define_bool CONFIG_ARM y mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment comment 'System and processor type' choice 'ARM system type' \ @@ -14,96 +19,111 @@ A5000 CONFIG_ARCH_A5K \ RiscPC CONFIG_ARCH_RPC \ EBSA-110 CONFIG_ARCH_EBSA110 \ - EBSA-285 CONFIG_ARCH_EBSA285 \ - NexusPCI CONFIG_ARCH_NEXUSPCI \ - Corel-VNC CONFIG_ARCH_VNC \ - Tbox CONFIG_ARCH_TBOX" RiscPC + FootBridge-based CONFIG_FOOTBRIDGE" RiscPC -if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then - bool ' Include support for CATS boards' CONFIG_CATS +if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE + if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then + define_bool CONFIG_ADDIN_FOOTBRIDGE n + else + define_bool CONFIG_ADDIN_FOOTBRIDGE y + fi +fi + +if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then + bool ' Include support for Intel EBSA285' CONFIG_ARCH_EBSA285 + bool ' Include support for Chalice CATS boards' CONFIG_CATS + bool ' Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER +fi + +if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then + # If we get any other footbridge-based plug-in boards, then + # add your architecture options here + define_bool CONFIG_ARCH_CO285 y fi +# # Select various configuration options depending on the machine type # Easy check for Acorn-style architectures - +# if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then - define_bool CONFIG_ARCH_ACORN y -else - define_bool CONFIG_ARCH_ACORN n -fi - -if [ "$CONFIG_ARCH_TBOX" = "y" ]; then - define_bool CONFIG_BUS_I2C y -fi - -# These machines always have PCI - -if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ - "$CONFIG_ARCH_VNC" = "y" ]; then - define_bool CONFIG_PCI y -fi -if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then - bool "PCI support" CONFIG_PCI -fi - -# These machines have ISA-DMA -if [ "$CONFIG_CATS" = "y" -o \ - "$CONFIG_ARCH_VNC" = "y" ]; then - define_bool CONFIG_ISA_DMA y + define_bool CONFIG_ARCH_ACORN y else - define_bool CONFIG_ISA_DMA n + define_bool CONFIG_ARCH_ACORN n fi +# # Figure out whether this system uses 26-bit or 32-bit CPUs. Nobody has # ever built a machine that can take both, and now that ARM3 is obsolete # nobody is likely to either. - +# if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" ]; then - define_bool CONFIG_CPU_32 n - define_bool CONFIG_CPU_26 y -else - define_bool CONFIG_CPU_32 y - define_bool CONFIG_CPU_26 n -fi - -# Now allow the user to choose a more precise CPU. This is only used to set -# the flags we pass to GCC, not in any code. + define_bool CONFIG_CPU_32 n + define_bool CONFIG_CPU_26 y -choice 'Optimise for CPU' \ - "ARM2 CONFIG_CPU_ARM2 \ - ARM3 CONFIG_CPU_ARM3 \ - ARM6 CONFIG_CPU_ARM6 \ - ARM7 CONFIG_CPU_ARM7 \ - SA110 CONFIG_CPU_SA110" ARM6 + # + # Select memory size + # + bool '2MB physical memory' CONFIG_PAGESIZE_16 +else + define_bool CONFIG_CPU_32 y + define_bool CONFIG_CPU_26 n -if [ "$CONFIG_CPU_26" = "y" ]; then + # + # Select CPU and optimisation dependent on architecture + # + if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then + define_bool CONFIG_CPU_32v4 y + define_bool CONFIG_CPU_SA110 y + else + if [ "$CONFIG_ARCH_RPC" = "y" ]; then + define_bool CONFIG_CPU_32v3 y + bool 'Support ARM610' CONFIG_CPU_ARM6 + bool 'Support ARM710' CONFIG_CPU_ARM7 + bool 'Support StrongARM110' CONFIG_CPU_SA110 + fi + fi +fi + +#if [ "$CONFIG_ARCH_TBOX" = "y" ]; then +# define_bool CONFIG_BUS_I2C y +#fi -# For 26-bit CPUs, the page size changes with the amount of physical RAM! -# The default is 4MB but if the user has less they have to own up to it here. +# +# These machines always have PCI +# +if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ + "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then + define_bool CONFIG_PCI y +fi - choice 'Physical memory size' \ - "4MB+ CONFIG_PAGESIZE_32 \ - 2MB CONFIG_PAGESIZE_16 \ - 1MB/512K CONFIG_PAGESIZE_8" 4MB+ +# +# These machines have ISA-DMA +# +if [ "$CONFIG_CATS" = "y" -o \ + "$CONFIG_ARCH_NETWINDER" = "y" ]; then + define_bool CONFIG_ISA_DMA y +else + define_bool CONFIG_ISA_DMA n fi -endmenu -mainmenu_option next_comment -comment 'Code maturity level options' -bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL -bool 'Use new compilation options (for GCC 2.8)' CONFIG_BINUTILS_NEW -bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER +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 mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD + bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD fi endmenu @@ -113,13 +133,19 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +tristate 'Math emulation' CONFIG_NWFPE 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 +if [ "$CONFIG_CPU_32" = "y" ]; then + tristate 'RISC OS personality' CONFIG_ARTHUR +fi tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT + if [ "$CONFIG_ARCH_ARC" = "y" ]; then + dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT + fi dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT # If exactly one hardware type is selected then parport will optimise away # support for loading any others. Defeat this if the user is keen. @@ -129,10 +155,24 @@ fi fi fi -if [ "$CONFIG_ARCH_EBSA285" = "y" -o \ - "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_ARCH_VNC" = "y" ]; then - string 'Initial kernel command string' CONFIG_CMDLINE "" +if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_CATS" = "y" ]; then + string 'Initial kernel command string' CONFIG_CMDLINE "" +fi +if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" ]; then + bool 'Timer and CPU usage LEDs' CONFIG_LEDS + if [ "$CONFIG_LEDS" = "y" ]; then + if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" ]; then + bool ' Timer LED' CONFIG_LEDS_TIMER + bool ' CPU usage LED' CONFIG_LEDS_CPU + fi + fi fi endmenu @@ -141,80 +181,100 @@ source drivers/block/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - source drivers/acorn/block/Config.in + source drivers/acorn/block/Config.in fi -if [ "$CONFIG_VGA_CONSOLE" = "n" -a "$CONFIG_FB" = "n" ]; then - source arch/arm/drivers/char/Config.in -else - source drivers/char/Config.in -fi +source drivers/char/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - source drivers/acorn/char/Config.in + if [ "$CONFIG_BUSMOUSE" = "y" ]; then + if [ "$CONFIG_ARCH_RPC" != "y" ]; then + define_bool CONFIG_KBDMOUSE y + else + define_bool CONFIG_RPCMOUSE y + fi + fi fi if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then - bool 'VGA text console' CONFIG_VGA_CONSOLE - fi - bool 'Support Frame buffer devices' CONFIG_FB - source drivers/video/Config.in - endmenu + mainmenu_option next_comment + comment 'Console drivers' + if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then + bool 'VGA text console' CONFIG_VGA_CONSOLE + fi + bool 'Support Frame buffer devices' CONFIG_FB + source drivers/video/Config.in + endmenu fi if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in -fi + source net/Config.in -if [ "$CONFIG_NET" = "y" ]; then - mainmenu_option next_comment - comment 'Network device support' + source net/ax25/Config.in - bool 'Network device support?' CONFIG_NETDEVICES - if [ "$CONFIG_NETDEVICES" = "y" ]; then - source drivers/net/Config.in - fi - endmenu + source net/irda/Config.in + + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support?' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + fi + endmenu fi +# mainmenu_option next_comment +# comment 'ISDN subsystem' +# +# tristate 'ISDN support' CONFIG_ISDN +# if [ "$CONFIG_ISDN" != "n" ]; then +# source drivers/isdn/Config.in +# fi +# endmenu + mainmenu_option next_comment comment 'SCSI support' tristate 'SCSI support?' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then - source drivers/scsi/Config.in + source drivers/scsi/Config.in fi endmenu if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_PCI" = "y" ]; then - mainmenu_option next_comment - comment 'Sound' + mainmenu_option next_comment + comment 'Sound' - tristate 'Sound support' CONFIG_SOUND - if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in - fi - endmenu + tristate 'Sound support' CONFIG_SOUND + if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in + fi + endmenu fi -# mainmenu_option next_comment -# comment 'ISDN subsystem' -# -# tristate 'ISDN support' CONFIG_ISDN -# if [ "$CONFIG_ISDN" != "n" ]; then -# source drivers/isdn/Config.in -# fi -# endmenu - source fs/Config.in mainmenu_option next_comment comment 'Kernel hacking' -bool 'Debug kernel errors' CONFIG_DEBUG_ERRORS +bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER +bool 'Verbose kernel error messages' CONFIG_DEBUG_ERRORS +bool 'Verbose user fault messages' CONFIG_DEBUG_USER +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 + # These options are only for real kernel hackers + # who want to get their hands dirty. + bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL + if [ "$CONFIG_DEBUG_LL" = "y" ]; then + if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then + bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT + fi + fi +fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/def-configs/a5k linux/arch/arm/def-configs/a5k --- v2.2.17/arch/arm/def-configs/a5k Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/def-configs/a5k Fri Sep 15 23:28:37 2000 @@ -0,0 +1,425 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +CONFIG_ARCH_A5K=y +# CONFIG_ARCH_RPC is not set +# 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 + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_NWFPE is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=m +# CONFIG_BINFMT_MISC is not set +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y + +# +# Plug and Play support +# +# 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_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_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=m +# 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 + +# +# 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_ATOMWIDE_SERIAL=y +CONFIG_DUALSP_SERIAL=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +CONFIG_PRINTER=y +CONFIG_PRINTER_READBACK=y +CONFIG_MOUSE=y + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +# CONFIG_PSMOUSE is not set +# 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 + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_KBDMOUSE=y + +# +# Console drivers +# +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_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_MFB=y +CONFIG_FBCON_CFB2=y +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_FONT_ACORN_8x8=y + +# +# 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 is not set + +# +# (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_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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA subsystem support +# +# CONFIG_IRDA 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_ARM_ETHER1=y +CONFIG_ARM_ETHER3=y +# CONFIG_ARM_ETHERH 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_PLIP 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 + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_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 + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_ADFS_FS=y +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_ISO9660_FS=y +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_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_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION 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 +CONFIG_ACORN_PARTITION_POWERTEC=y +CONFIG_ACORN_PARTITION_RISCIX=y +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_15 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_NO_PGT_CACHE=y +# CONFIG_DEBUG_LL is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/def-configs/ebsa110 linux/arch/arm/def-configs/ebsa110 --- v2.2.17/arch/arm/def-configs/ebsa110 Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/def-configs/ebsa110 Fri Sep 15 23:28:37 2000 @@ -0,0 +1,340 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_EBSA110=y +# CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_ACORN is not set +# 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_SA110=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_TEXT_SECTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_NWFPE 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_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8" +CONFIG_LEDS=y + +# +# Plug and Play support +# +# 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 + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SERIAL_EXTENDED=y +# CONFIG_SERIAL_MANY_PORTS is not set +# CONFIG_SERIAL_SHARE_IRQ is not set +# CONFIG_SERIAL_DETECT_IRQ is not set +# CONFIG_SERIAL_MULTIPORT is not set +# CONFIG_HUB6 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 + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_QIC02_TAPE is not set +CONFIG_WATCHDOG=y + +# +# Watchdog Cards +# +# 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_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 + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set +CONFIG_FIREWALL=y +# 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_FIREWALL=y +# CONFIG_IP_FIREWALL_NETLINK is not set +CONFIG_IP_ALWAYS_DEFRAG=y +# CONFIG_IP_TRANSPARENT_PROXY is not set +CONFIG_IP_MASQUERADE=y + +# +# Protocol-specific masquerading support will be built as modules. +# +CONFIG_IP_MASQUERADE_ICMP=y + +# +# Protocol-specific masquerading support will be built as modules. +# +# CONFIG_IP_MASQUERADE_MOD 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_ARPD is not set +CONFIG_SYN_COOKIES=y + +# +# (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_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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA subsystem support +# +# CONFIG_IRDA 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_ARM_AM79C961A=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_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_PLIP 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 + +# +# 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 + +# +# SCSI support +# +# CONFIG_SCSI 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_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 is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EFS_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=y +# CONFIG_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SGI_DISKLABEL 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 + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_LL is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge --- v2.2.17/arch/arm/def-configs/footbridge Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/def-configs/footbridge Fri Sep 15 23:28:37 2000 @@ -0,0 +1,549 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +CONFIG_FOOTBRIDGE=y +CONFIG_HOST_FOOTBRIDGE=y +# CONFIG_ADDIN_FOOTBRIDGE is not set +CONFIG_ARCH_EBSA285=y +# 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_SA110=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_TEXT_SECTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_NWFPE=y +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_CMDLINE="root=/dev/hda2 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 +# +# 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 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=y +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_CMD646 is not set +CONFIG_BLK_DEV_SL82C105=y +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_STRIPED=m +CONFIG_MD_MIRRORING=m +CONFIG_MD_RAID5=m +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 + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_HD is not set + +# +# 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 is not set +CONFIG_PRINTER=m +CONFIG_PRINTER_READBACK=y +CONFIG_MOUSE=y + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_QIC02_TAPE is not set +CONFIG_WATCHDOG=y + +# +# Watchdog Cards +# +# 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_DS1620=y +CONFIG_NWBUTTON=y +CONFIG_NWBUTTON_REBOOT=y +CONFIG_NWFLASH=m +# CONFIG_NVRAM is not set +CONFIG_RTC=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set +CONFIG_FB_CYBER2000=y +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +CONFIG_FBCON_VGA=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# 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 + +# +# Networking options +# +CONFIG_PACKET=y +# 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=y +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +# CONFIG_INET_RARP 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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA subsystem support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRCOMM=m +CONFIG_IRLPT=m +CONFIG_IRLPT_CLIENT=m +CONFIG_IRLPT_SERVER=m +# CONFIG_IRDA_OPTIONS is not set +CONFIG_IRDA_COMPRESSION=y + +# +# IrDA compressors +# +CONFIG_IRDA_DEFLATE=m + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# FIR device drivers +# +# CONFIG_NSC_FIR is not set +CONFIG_WINBOND_FIR=m +# CONFIG_SHARP_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set + +# +# Dongle support +# +# CONFIG_DONGLE 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_ARM_AM79C961A is not set +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_EL3 is not set +# CONFIG_3C515 is not set +CONFIG_VORTEX=y +# 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_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 is not set +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=y +# 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_PLIP is not set +CONFIG_PPP=m + +# +# CCP compressors for PPP are only built as modules. +# +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +# 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 + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_SONICVIBES 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_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_VIDC is not set +CONFIG_SOUND_WAVEARTIST=m +CONFIG_WAVEARTIST_BASE=250 +CONFIG_WAVEARTIST_IRQ=12 +CONFIG_WAVEARTIST_DMA=3 +CONFIG_WAVEARTIST_DMA2=7 + +# +# Additional low level sound drivers +# +# CONFIG_LOWLEVEL_SOUND is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_ADFS_FS=y +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# 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 +# CONFIG_EFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFSD=m +# 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_MSDOS_PARTITION=y +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SGI_DISKLABEL is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +# 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=m +CONFIG_NLS_ISO8859_2=m +# 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=m +# CONFIG_NLS_KOI8_R is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_LL is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/def-configs/netwinder linux/arch/arm/def-configs/netwinder --- v2.2.17/arch/arm/def-configs/netwinder Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/def-configs/netwinder Fri Sep 15 23:28:37 2000 @@ -0,0 +1,677 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +CONFIG_FOOTBRIDGE=y +CONFIG_HOST_FOOTBRIDGE=y +# CONFIG_ADDIN_FOOTBRIDGE is not set +# CONFIG_ARCH_EBSA285 is not set +# 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_ARMV4=y +CONFIG_TUNE_SA110=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_TEXT_SECTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_NWFPE=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_CMDLINE="mem=32M root=/dev/hda1 ide0=autotune ide1=autotune" +CONFIG_LEDS=y +# CONFIG_LEDS_TIMER is not set +# CONFIG_LEDS_CPU 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 is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_CMD646 is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +CONFIG_BLK_DEV_SL82C105=y +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=m +# CONFIG_BLK_DEV_XD is not set +CONFIG_BLK_DEV_DAC960=m +CONFIG_PARIDE_PARPORT=m +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m +CONFIG_BLK_CPQ_DA=m +# CONFIG_BLK_DEV_HD is not set + +# +# USB drivers - not for the faint of heart +# +# CONFIG_USB 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_PRINTER=m +# CONFIG_PRINTER_READBACK is not set +CONFIG_MOUSE=y + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_QIC02_TAPE is not set +CONFIG_WATCHDOG=y + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_WDT is not set +CONFIG_SOFT_WATCHDOG=m +# CONFIG_PCWATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +CONFIG_21285_WATCHDOG=m +CONFIG_977_WATCHDOG=m +CONFIG_DS1620=y +CONFIG_NWBUTTON=y +CONFIG_NWBUTTON_REBOOT=y +CONFIG_NWFLASH=m +# CONFIG_21285_FLASH is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_BUZ is not set +CONFIG_NVRAM=m +CONFIG_RTC=y + +# +# Video For Linux +# +CONFIG_VIDEO_DEV=m +CONFIG_RADIO_RTRACK=m +CONFIG_RADIO_RTRACK2=m +CONFIG_RADIO_AZTECH=m +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_MIROPCM20 is not set +CONFIG_RADIO_GEMTEK=m +CONFIG_VIDEO_BT848=m +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_PMS=m +CONFIG_VIDEO_SAA5249=m +CONFIG_RADIO_SF16FMI=m +CONFIG_RADIO_TYPHOON=m +# CONFIG_RADIO_TYPHOON_PROC_FS is not set +CONFIG_RADIO_ZOLTRIX=m +CONFIG_TUNER_3036=m + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set +CONFIG_FB_CYBER2000=y +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +CONFIG_FBCON_VGA=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set +CONFIG_FIREWALL=y +CONFIG_FILTER=y +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 is not set +# CONFIG_IP_PNP_RARP is not set +CONFIG_IP_FIREWALL=y +# CONFIG_IP_FIREWALL_NETLINK is not set +CONFIG_IP_ALWAYS_DEFRAG=y +CONFIG_IP_TRANSPARENT_PROXY=y +CONFIG_IP_MASQUERADE=y + +# +# Protocol-specific masquerading support will be built as modules. +# +# CONFIG_IP_MASQUERADE_ICMP is not set + +# +# Protocol-specific masquerading support will be built as modules. +# +CONFIG_IP_MASQUERADE_MOD=y +CONFIG_IP_MASQUERADE_IPAUTOFW=m +CONFIG_IP_MASQUERADE_IPPORTFW=m +CONFIG_IP_MASQUERADE_MFW=m +# CONFIG_IP_ROUTER is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_INET_RARP=m +CONFIG_SKB_LARGE=y +# CONFIG_IPV6 is not set + +# +# +# +CONFIG_IPX=m +# CONFIG_IPX_INTERN is not set +CONFIG_SPX=m +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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA subsystem support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRCOMM=m +CONFIG_IRLPT=m +CONFIG_IRLPT_CLIENT=m +CONFIG_IRLPT_SERVER=m +CONFIG_IRDA_OPTIONS=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y +# CONFIG_IRDA_COMPRESSION is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set +CONFIG_IRPORT_SIR=m + +# +# FIR device drivers +# +# CONFIG_NSC_FIR is not set +CONFIG_WINBOND_FIR=m +# CONFIG_SHARP_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_EQUALIZER=m +# CONFIG_ETHERTAP 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 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=m +# 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 is not set +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=y +# 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_PLIP=m +CONFIG_PPP=m + +# +# CCP compressors for PPP are only built as modules. +# +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 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=m + +# +# Wan interfaces +# +# CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_SEALEVEL_4021 is not set +# CONFIG_DLCI is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# 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_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_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# 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_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_SYM53C8XX=m +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 + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_SONICVIBES 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_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_AD1816 is not set +CONFIG_SOUND_OPL3SA1=m +# CONFIG_SOUND_SOFTOSS is not set +CONFIG_SOUND_YM3812=m +CONFIG_SOUND_VMIDI=m +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_VIDC is not set +CONFIG_SOUND_WAVEARTIST=m +CONFIG_WAVEARTIST_BASE=250 +CONFIG_WAVEARTIST_IRQ=12 +CONFIG_WAVEARTIST_DMA=3 +CONFIG_WAVEARTIST_DMA2=7 + +# +# Additional low level sound drivers +# +# CONFIG_LOWLEVEL_SOUND is not set + +# +# Filesystems +# +CONFIG_QUOTA=y +CONFIG_AUTOFS_FS=m +CONFIG_ADFS_FS=m +CONFIG_AFFS_FS=m +CONFIG_HFS_FS=m +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +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=m +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_EFS_FS=m +CONFIG_SGI_PARTITION=y + +# +# Network File Systems +# +CONFIG_CODA_FS=m +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=m +# CONFIG_NFSD_SUN is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_SMB_FS=m +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SGI_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SGI_DISKLABEL 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=y + +# +# Native Language Support +# +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +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=m +CONFIG_NLS_KOI8_R=m + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_LL is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/def-configs/rpc linux/arch/arm/def-configs/rpc --- v2.2.17/arch/arm/def-configs/rpc Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/def-configs/rpc Fri Sep 15 23:28:37 2000 @@ -0,0 +1,471 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +CONFIG_ARCH_RPC=y +# 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_SA110=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_TEXT_SECTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_NWFPE is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y + +# +# Plug and Play support +# +# 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_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=y +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=m +# 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 + +# +# Acorn-specific block devices +# +CONFIG_BLK_DEV_IDE_CARDS=y +CONFIG_BLK_DEV_IDE_ICSIDE=y +CONFIG_BLK_DEV_IDE_RAPIDE=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_ATOMWIDE_SERIAL=y +CONFIG_DUALSP_SERIAL=y +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +CONFIG_PRINTER=m +CONFIG_PRINTER_READBACK=y +CONFIG_MOUSE=y + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +# CONFIG_PSMOUSE is not set +# 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 + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_RPCMOUSE=y + +# +# Console drivers +# +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_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +CONFIG_FBCON_MFB=y +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +# 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 + +# +# 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 is not set + +# +# (it is safe to leave these untouched) +# +# CONFIG_INET_RARP 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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA subsystem support +# +# CONFIG_IRDA 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_ARM_ETHER1=m +CONFIG_ARM_ETHER3=m +CONFIG_ARM_ETHERH=m +# 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_PLIP is not set +CONFIG_PPP=m + +# +# CCP compressors for PPP are only built as modules. +# +# CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set +# CONFIG_TR is not set +# CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set +# CONFIG_COSA is not set +# CONFIG_RCPCI is not set + +# +# 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=y + +# +# 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=m +# 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=m +CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y +CONFIG_SCSI_ACORNSCSI_SYNC=y +CONFIG_SCSI_ARXESCSI=m +CONFIG_SCSI_CUMANA_2=m +CONFIG_SCSI_EESOXSCSI=m +CONFIG_SCSI_POWERTECSCSI=m + +# +# The following drivers are not fully supported +# +CONFIG_SCSI_CUMANA_1=m +CONFIG_SCSI_OAK1=m + +# +# Sound +# +CONFIG_SOUND=m +# 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=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_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_UART6850 is not set +CONFIG_SOUND_VIDC=m +# CONFIG_SOUND_WAVEARTIST is not set + +# +# Additional low level sound drivers +# +# CONFIG_LOWLEVEL_SOUND is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +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_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_ISO9660_FS=y +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_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 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_OSF_PARTITION is not set +# CONFIG_MAC_PARTITION 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 +CONFIG_ACORN_PARTITION_POWERTEC=y +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_ISO8859_9=m +# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_KOI8_R=m + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +# 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 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/defconfig linux/arch/arm/defconfig --- v2.2.17/arch/arm/defconfig Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/defconfig Fri Sep 15 23:28:37 2000 @@ -4,47 +4,71 @@ CONFIG_ARM=y # +# System and processor type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_EBSA110 is not set +CONFIG_FOOTBRIDGE=y +CONFIG_HOST_FOOTBRIDGE=y +# CONFIG_ADDIN_FOOTBRIDGE is not set +CONFIG_ARCH_EBSA285=y +# 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_SA110=y + +# # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_ALIGNMENT_TRAP is not set +# CONFIG_TEXT_SECTIONS is not set # # Loadable module support # CONFIG_MODULES=y -CONFIG_MODVERSIONS=y +# CONFIG_MODVERSIONS is not set CONFIG_KMOD=y # # General setup # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set -CONFIG_ARCH_RPC=y -# CONFIG_ARCH_EBSA110 is not set -# CONFIG_ARCH_NEXUSPCI is not set -CONFIG_ARCH_ACORN=y -# CONFIG_PCI is not set -# CONFIG_CPU_ARM2 is not set -# CONFIG_CPU_ARM3 is not set -# CONFIG_CPU_ARM6 is not set -CONFIG_CPU_SA110=y -CONFIG_FRAME_POINTER=y -# CONFIG_BINUTILS_NEW is not set -CONFIG_DEBUG_ERRORS=y CONFIG_NET=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +CONFIG_NWFPE=y CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=m -# CONFIG_BINFMT_JAVA is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_ARTHUR is not set CONFIG_PARPORT=y CONFIG_PARPORT_PC=y +CONFIG_CMDLINE="root=/dev/hda2 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 +# +# CONFIG_PNP is not set # -# Floppy, IDE, and other block devices +# Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y # @@ -52,32 +76,165 @@ # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y -CONFIG_BLK_DEV_IDECD=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_IDE_PCMCIA is not set -CONFIG_BLK_DEV_IDE_CARDS=y -CONFIG_BLK_DEV_IDE_ICSIDE=y -# CONFIG_BLK_DEV_IDE_RAPIDE is not set -# CONFIG_BLK_DEV_XD is not set +# 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_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_VIA82C586 is not set +# CONFIG_BLK_DEV_CMD646 is not set +CONFIG_BLK_DEV_SL82C105=y +# CONFIG_IDE_CHIPSETS is not set # # Additional Block Devices # CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_STRIPED=m +CONFIG_MD_MIRRORING=m +CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -CONFIG_BLK_DEV_PART=y +CONFIG_PARIDE=m + +# +# Parallel IDE high-level drivers +# +CONFIG_PARIDE_PD=m +CONFIG_PARIDE_PCD=m +CONFIG_PARIDE_PF=m +CONFIG_PARIDE_PT=m +CONFIG_PARIDE_PG=m + +# +# Parallel IDE protocol modules +# +CONFIG_PARIDE_ATEN=m +CONFIG_PARIDE_BPCK=m +CONFIG_PARIDE_COMM=m +CONFIG_PARIDE_DSTR=m +CONFIG_PARIDE_FIT2=m +CONFIG_PARIDE_FIT3=m +CONFIG_PARIDE_EPAT=m +CONFIG_PARIDE_EPIA=m +CONFIG_PARIDE_FRIQ=m +CONFIG_PARIDE_FRPW=m +CONFIG_PARIDE_KBIC=m +CONFIG_PARIDE_KTTI=m +CONFIG_PARIDE_ON20=m +CONFIG_PARIDE_ON26=m # CONFIG_BLK_DEV_HD is not set # +# 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 is not set +CONFIG_PRINTER=m +CONFIG_PRINTER_READBACK=y +CONFIG_MOUSE=y + +# +# Mice +# +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_QIC02_TAPE is not set +CONFIG_WATCHDOG=y + +# +# Watchdog Cards +# +# 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_DS1620=y +CONFIG_NWBUTTON=y +CONFIG_NWBUTTON_REBOOT=y +CONFIG_NWFLASH=m +# CONFIG_NVRAM is not set +CONFIG_RTC=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set + +# +# Joystick support +# +# CONFIG_JOYSTICK is not set +# CONFIG_DTLK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_PM2 is not set +CONFIG_FB_CYBER2000=y +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +CONFIG_FBCON_VGA=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# 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 + +# # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=y # CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set # CONFIG_FILTER is not set @@ -85,21 +242,20 @@ CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_IP_ACCT is not set -# CONFIG_IP_MASQUERADE is not set +CONFIG_IP_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_IP_ALIAS=y # CONFIG_SYN_COOKIES is not set # # (it is safe to leave these untouched) # # CONFIG_INET_RARP is not set -CONFIG_IP_NOSR=y -# CONFIG_SKB_LARGE is not set +CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # @@ -111,107 +267,198 @@ # 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 + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set -# CONFIG_NET_PROFILE is not set # -# SCSI support +# Amateur Radio support # -CONFIG_SCSI=y +# CONFIG_HAMRADIO is not set # -# SCSI support type (disk, tape, CD-ROM) +# IrDA subsystem 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 +# CONFIG_IRDA is not set # -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# Network device support # -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y +CONFIG_NETDEVICES=y +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +CONFIG_NET_VENDOR_3COM=y +# CONFIG_EL1 is not set +# CONFIG_EL2 is not set +# CONFIG_ELPLUS is not set +# CONFIG_EL16 is not set +# CONFIG_EL3 is not set +# CONFIG_3C515 is not set +CONFIG_VORTEX=y +# 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=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=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=y +# 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_PLIP is not set +CONFIG_PPP=m # -# SCSI low-level drivers +# CCP compressors for PPP are only built as modules. # -CONFIG_SCSI_ACORNSCSI_3=m -CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y -CONFIG_SCSI_ACORNSCSI_SYNC=y -CONFIG_SCSI_CUMANA_2=m -CONFIG_SCSI_POWERTECSCSI=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +# 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 # -# The following drives are not fully supported +# SCSI support # -CONFIG_SCSI_CUMANA_1=m -CONFIG_SCSI_OAK1=m -CONFIG_SCSI_PPA=m -CONFIG_SCSI_PPA_HAVE_PEDANTIC=2 +# CONFIG_SCSI is not set # -# Network device support +# Sound # -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -CONFIG_PPP=m +CONFIG_SOUND=m +# 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=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_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_VIDC is not set +CONFIG_SOUND_WAVEARTIST=m +CONFIG_WAVEARTIST_BASE=250 +CONFIG_WAVEARTIST_IRQ=12 +CONFIG_WAVEARTIST_DMA=3 +CONFIG_WAVEARTIST_DMA2=7 # -# CCP compressors for PPP are only built as modules. +# Additional low level sound drivers # -# CONFIG_SLIP is not set -CONFIG_ETHER1=m -CONFIG_ETHER3=m -CONFIG_ETHERH=m +# CONFIG_LOWLEVEL_SOUND 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=y -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y +# CONFIG_AUTOFS_FS is not set +CONFIG_ADFS_FS=y +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +CONFIG_VFAT_FS=m +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_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_ROOT_NFS=y +CONFIG_NFSD=m +# CONFIG_NFSD_SUN 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=y -CONFIG_ADFS_FS=y +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_OSF_PARTITION is not set # CONFIG_MAC_PARTITION 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 is not set +# CONFIG_ACORN_PARTITION_POWERTEC is not set +# CONFIG_ACORN_PARTITION_RISCIX is not set CONFIG_NLS=y # # Native Language Support # -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=m # 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_850=m +CONFIG_NLS_CODEPAGE_852=m # CONFIG_NLS_CODEPAGE_855 is not set # CONFIG_NLS_CODEPAGE_857 is not set # CONFIG_NLS_CODEPAGE_860 is not set @@ -223,8 +470,8 @@ # 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_1=m +CONFIG_NLS_ISO8859_2=m # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set # CONFIG_NLS_ISO8859_5 is not set @@ -232,34 +479,15 @@ # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +CONFIG_NLS_ISO8859_15=m # CONFIG_NLS_KOI8_R is not set # -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -CONFIG_ATOMWIDE_SERIAL=y -CONFIG_DUALSP_SERIAL=y -CONFIG_MOUSE=y -CONFIG_PRINTER=m -CONFIG_PRINTER_READBACK=y -# CONFIG_UMISC is not set -# CONFIG_WATCHDOG is not set -CONFIG_RPCMOUSE=y - -# -# Sound -# -CONFIG_SOUND=m -CONFIG_VIDC=y -CONFIG_AUDIO=y -DSP_BUFFSIZE=65536 - -# # Kernel hacking # +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_LL is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.2.17/arch/arm/kernel/Makefile Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/Makefile Fri Sep 15 23:28:37 2000 @@ -9,66 +9,73 @@ ENTRY_OBJ = entry-$(PROCESSOR).o O_TARGET := kernel.o -O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o setup.o \ - signal.o sys_arm.o time.o traps.o +O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o \ + setup.o signal.o sys_arm.o time.o traps.o -DMA_OBJS_arc = dma-arc.o -DMA_OBJS_a5k = dma-a5k.o -DMA_OBJS_rpc = dma-rpc.o -DMA_OBJS_ebsa110 = dma-dummy.o -DMA_OBJS_ebsa285 = dma-ebsa285.o -DMA_OBJS_nexuspci = -DMA_OBJS_vnc = dma-vnc.o - -O_OBJS_arc = ecard.o iic.o fiq.o oldlatches.o -O_OBJS_a5k = ecard.o iic.o fiq.o -O_OBJS_rpc = ecard.o iic.o fiq.o -O_OBJS_ebsa110 = leds-ebsa110.o -O_OBJS_ebsa285 = leds-ebsa285.o hw-ebsa285.o -O_OBJS_nexuspci = -O_OBJS_vnc = leds-ebsa285.o hw-vnc.o +ifeq ($(CONFIG_ISA_DMA),y) + ISA_DMA_OBJS += dma-isa.o +endif + +O_OBJS_arc = dma-arc.o iic.o fiq.o oldlatches.o +O_OBJS_a5k = dma-a5k.o iic.o fiq.o +O_OBJS_rpc = dma-rpc.o iic.o fiq.o +O_OBJS_ebsa110 = dma-dummy.o +O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS) isa.o +O_OBJS_nexuspci = dma-dummy.o + +OX_OBJS_arc = dma.o +OX_OBJS_a5k = dma.o +OX_OBJS_rpc = dma.o +OX_OBJS_ebsa110 = +OX_OBJS_footbridge= dma.o hw-footbridge.o +OX_OBJS_nexuspci = -all: lib kernel.o $(HEAD_OBJ) init_task.o +all: kernel.o $(HEAD_OBJ) init_task.o + +O_OBJS += $(O_OBJS_$(MACHINE)) ifeq ($(CONFIG_MODULES),y) OX_OBJS = armksyms.o -else - O_OBJS += armksyms.o endif -ifeq ($(MACHINE),nexuspci) - ifdef CONFIG_PCI +ifeq ($(CONFIG_ARCH_ACORN),y) + OX_OBJS += ecard.o +endif + +ifeq ($(CONFIG_PCI),y) + ifeq ($(MACHINE),nexuspci) O_OBJS += plx9080.o - endif -else - ifdef CONFIG_PCI + else O_OBJS += dec21285.o endif endif -ifneq ($(DMA_OBJS_$(MACHINE)),) - OX_OBJS += dma.o - O_OBJS += $(DMA_OBJS_$(MACHINE)) - ifeq ($(CONFIG_ISA_DMA),y) - O_OBJS += dma-isa.o - endif +ifeq ($(CONFIG_LEDS),y) + OX_OBJS += leds-$(MACHINE).o +endif + +ifeq ($(CONFIG_MODULES),y) + OX_OBJS += $(OX_OBJS_$(MACHINE)) else - O_OBJS += dma-dummy.o + O_OBJS += $(OX_OBJS_$(MACHINE)) endif -O_OBJS += $(O_OBJS_$(MACHINE)) +ifeq ($(CONFIG_ARTHUR),y) + O_OBJS += arthur.o +else + ifeq ($(CONFIG_ARTHUR),m) + M_OBJS += arthur.o + endif +endif $(HEAD_OBJ): $(HEAD_OBJ:.o=.S) - $(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ - -$(ENTRY_OBJ): $(ENTRY_OBJ:.o=.S) - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $(ENTRY_OBJ:.o=.S) -o $@ + $(CC) -D__ASSEMBLY__ $(AFLAGS) -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@ include $(TOPDIR)/Rules.make -$(ENTRY_OBJ): ../lib/constants.h - -.PHONY: lib +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -c -o $*.o $< -lib: - $(MAKE) -C ../lib constants.h +# Spell out some dependencies that `make dep' doesn't spot +entry-armv.o: calls.S ../lib/constants.h +entry-armo.o: calls.S ../lib/constants.h diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.2.17/arch/arm/kernel/armksyms.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/armksyms.c Fri Sep 15 23:28:37 2000 @@ -2,24 +2,49 @@ #include #include #include +#include #include #include #include #include +#include +#include -#include +#include #include #include +#include #include #include +#include +#include +#include #include #include +#include +extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, struct user_fp_struct *); extern void inswb(unsigned int port, void *to, int len); extern void outswb(unsigned int port, const void *to, int len); +extern unsigned int local_bh_count[NR_CPUS]; +extern unsigned int local_irq_count[NR_CPUS]; + +extern unsigned long system_serial_low; +extern unsigned long system_serial_high; +extern unsigned int system_rev; + +/* + * syscalls + */ +extern int sys_write(int, const char *, int); +extern int sys_read(int, char *, int); +extern int sys_lseek(int, off_t, int); +extern int sys_exit(int); +extern int sys_wait4(int, int *, int, struct rusage *); + /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that @@ -43,6 +68,8 @@ extern void __umoddi3(void); extern void __umodsi3(void); +extern void ret_from_exception(void); +extern void fpundefinstr(void); extern void fp_enter(void); #define EXPORT_SYMBOL_ALIAS(sym,orig) \ const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \ @@ -57,32 +84,47 @@ EXPORT_SYMBOL_ALIAS(fp_printk,printk); EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig); +#ifdef CONFIG_CPU_26 +EXPORT_SYMBOL(fpundefinstr); +EXPORT_SYMBOL(ret_from_exception); +#endif + +EXPORT_SYMBOL(kd_mksound); + /* platform dependent support */ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(udelay); EXPORT_SYMBOL(xchg_str); - - /* expansion card support */ -#ifdef CONFIG_ARCH_ACORN -EXPORT_SYMBOL(ecard_startfind); -EXPORT_SYMBOL(ecard_find); -EXPORT_SYMBOL(ecard_readchunk); -EXPORT_SYMBOL(ecard_address); -#endif - +EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(local_irq_count); +#if defined(CONFIG_CPU_32) && !defined(CONFIG_ARCH_EBSA110) +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(__iounmap); +#endif +EXPORT_SYMBOL(init_mm); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(system_rev); +EXPORT_SYMBOL(system_serial_low); +EXPORT_SYMBOL(system_serial_high); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); /* processor dependencies */ EXPORT_SYMBOL(processor); -EXPORT_SYMBOL(machine_type); +EXPORT_SYMBOL(__machine_arch_type); + + /* networking */ +EXPORT_SYMBOL(csum_partial_copy); +EXPORT_SYMBOL(__csum_ipv6_magic); /* io */ -EXPORT_SYMBOL(outswb); +EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); -EXPORT_SYMBOL(inswb); +EXPORT_SYMBOL(outsl); +EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); +EXPORT_SYMBOL(insl); /* address translation */ #ifndef __virt_to_phys__is_a_macro @@ -98,7 +140,9 @@ EXPORT_SYMBOL(__bus_to_virt); #endif +#ifndef CONFIG_NO_PGT_CACHE EXPORT_SYMBOL(quicklists); +#endif EXPORT_SYMBOL(__bad_pmd); EXPORT_SYMBOL(__bad_pmd_kernel); @@ -116,19 +160,20 @@ EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL_NOVERS(strstr); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memscan); -EXPORT_SYMBOL_NOVERS(memzero); +EXPORT_SYMBOL_NOVERS(__memzero); /* user mem (segment) */ #if defined(CONFIG_CPU_32) EXPORT_SYMBOL(__arch_copy_from_user); EXPORT_SYMBOL(__arch_copy_to_user); EXPORT_SYMBOL(__arch_clear_user); -EXPORT_SYMBOL(__arch_strlen_user); +EXPORT_SYMBOL(__arch_strnlen_user); #elif defined(CONFIG_CPU_26) EXPORT_SYMBOL(uaccess_kernel); EXPORT_SYMBOL(uaccess_user); @@ -164,6 +209,19 @@ EXPORT_SYMBOL(find_next_zero_bit); /* elf */ -EXPORT_SYMBOL(armidlist); -EXPORT_SYMBOL(armidindex); EXPORT_SYMBOL(elf_platform); +EXPORT_SYMBOL(elf_hwcap); + + /* syscalls */ +EXPORT_SYMBOL(sys_write); +EXPORT_SYMBOL(sys_read); +EXPORT_SYMBOL(sys_lseek); +EXPORT_SYMBOL(sys_open); +EXPORT_SYMBOL(sys_exit); +EXPORT_SYMBOL(sys_wait4); + + /* semaphores */ +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); +EXPORT_SYMBOL_NOVERS(__up_wakeup); + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/arthur.c linux/arch/arm/kernel/arthur.c --- v2.2.17/arch/arm/kernel/arthur.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/kernel/arthur.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,88 @@ +/* + * Arthur personality + * Copyright (C) 1998 Philip Blundell + */ + +#include +#include +#include +#include +#include + +#include + +/* RISC OS doesn't have many signals, and a lot of those that it does + have don't map easily to any Linux equivalent. Never mind. */ + +#define RISCOS_SIGABRT 1 +#define RISCOS_SIGFPE 2 +#define RISCOS_SIGILL 3 +#define RISCOS_SIGINT 4 +#define RISCOS_SIGSEGV 5 +#define RISCOS_SIGTERM 6 +#define RISCOS_SIGSTAK 7 +#define RISCOS_SIGUSR1 8 +#define RISCOS_SIGUSR2 9 +#define RISCOS_SIGOSERROR 10 + +static unsigned long riscos_to_linux_signals[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31 +}; + +static unsigned long linux_to_riscos_signals[32] = { + 0, -1, RISCOS_SIGINT, -1, + RISCOS_SIGILL, 5, RISCOS_SIGABRT, 7, + RISCOS_SIGFPE, 9, RISCOS_SIGUSR1, RISCOS_SIGSEGV, + RISCOS_SIGUSR2, 13, 14, RISCOS_SIGTERM, + 16, 17, 18, 19, + 20, 21, 22, 23, + 24, 25, 26, 27, + 28, 29, 30, 31 +}; + +static void arthur_lcall7(int nr, struct pt_regs *regs) +{ + struct siginfo info; + info.si_signo = SIGSWI; + info.si_code = nr; + /* Bounce it to the emulator */ + send_sig_info(SIGSWI, &info, current); +} + +static struct exec_domain riscos_exec_domain = { + "Arthur", /* name */ + (lcall7_func)arthur_lcall7, + PER_RISCOS, PER_RISCOS, + riscos_to_linux_signals, + linux_to_riscos_signals, +#ifdef MODULE + &__this_module, /* No usage counter. */ +#else + NULL, +#endif + NULL /* Nothing after this in the list. */ +}; + +/* + * We could do with some locking to stop Arthur being removed while + * processes are using it. + */ + +#ifdef MODULE +int init_module(void) +#else +int initialise_arthur(void) +#endif +{ + return register_exec_domain(&riscos_exec_domain); +} + +#ifdef MODULE +void cleanup_module(void) +{ + unregister_exec_domain(&riscos_exec_domain); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S --- v2.2.17/arch/arm/kernel/calls.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/calls.S Fri Sep 15 23:28:37 2000 @@ -31,7 +31,7 @@ .long SYMBOL_NAME(sys_lseek) /* 20 */ .long SYMBOL_NAME(sys_getpid) .long SYMBOL_NAME(sys_mount_wrapper) - .long SYMBOL_NAME(sys_umount) + .long SYMBOL_NAME(sys_oldumount) .long SYMBOL_NAME(sys_setuid) .long SYMBOL_NAME(sys_getuid) /* 25 */ .long SYMBOL_NAME(sys_stime) @@ -61,7 +61,7 @@ .long SYMBOL_NAME(sys_geteuid) /* 50 */ .long SYMBOL_NAME(sys_getegid) .long SYMBOL_NAME(sys_acct) - .long SYMBOL_NAME(sys_ni_syscall) /* was sys_phys */ + .long SYMBOL_NAME(sys_umount) .long SYMBOL_NAME(sys_ni_syscall) /* was sys_lock */ .long SYMBOL_NAME(sys_ioctl) /* 55 */ .long SYMBOL_NAME(sys_fcntl) @@ -110,7 +110,7 @@ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_profil */ .long SYMBOL_NAME(sys_statfs) /* 100 */ .long SYMBOL_NAME(sys_fstatfs) - .long SYMBOL_NAME(sys_ni_syscall) /* .long _sys_ioperm */ + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_socketcall) .long SYMBOL_NAME(sys_syslog) .long SYMBOL_NAME(sys_setitimer) @@ -129,7 +129,7 @@ .long SYMBOL_NAME(sys_ipc) .long SYMBOL_NAME(sys_fsync) .long SYMBOL_NAME(sys_sigreturn_wrapper) - .long SYMBOL_NAME(sys_clone_wapper) +/* 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) */ @@ -157,8 +157,8 @@ /* 145 */ .long SYMBOL_NAME(sys_readv) .long SYMBOL_NAME(sys_writev) .long SYMBOL_NAME(sys_getsid) - .long SYMBOL_NAME(sys_ni_syscall) - .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_fdatasync) + .long SYMBOL_NAME(sys_sysctl) /* 150 */ .long SYMBOL_NAME(sys_mlock) .long SYMBOL_NAME(sys_munlock) .long SYMBOL_NAME(sys_mlockall) @@ -196,6 +196,10 @@ .long SYMBOL_NAME(sys_capget) /* 185 */ .long SYMBOL_NAME(sys_capset) .long SYMBOL_NAME(sys_sigaltstack_wrapper) + .long SYMBOL_NAME(sys_sendfile) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) +/* 190 */ .long SYMBOL_NAME(sys_vfork_wrapper) .rept NR_syscalls-186 .long SYMBOL_NAME(sys_ni_syscall) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.2.17/arch/arm/kernel/dec21285.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dec21285.c Fri Sep 15 23:28:37 2000 @@ -8,17 +8,17 @@ #include #include #include +#include #include #include #include +#include -#define MAX_SLOTS 20 +#define MAX_SLOTS 21 extern void pcibios_fixup_ebsa285(struct pci_dev *dev); extern void pcibios_init_ebsa285(void); -extern void pcibios_fixup_vnc(struct pci_dev *dev); -extern void pcibios_init_vnc(void); int pcibios_present(void) @@ -33,11 +33,12 @@ int slot = PCI_SLOT(dev_fn); if (slot < MAX_SLOTS) - return 0xf8c00000 + (slot << 11) + (PCI_FUNC(dev_fn) << 8); + return PCICFG0_BASE + 0xc00000 + + (slot << 11) + (PCI_FUNC(dev_fn) << 8); else return 0; } else - return 0xf9000000 | (bus << 16) | (dev_fn << 8); + return PCICFG1_BASE | (bus << 16) | (dev_fn << 8); } int @@ -151,10 +152,7 @@ struct pci_dev *dev; for (dev = pci_devices; dev; dev = dev->next) { - if (machine_is_ebsa285() || machine_is_cats()) - pcibios_fixup_ebsa285(dev); - if (machine_is_netwinder()) - pcibios_fixup_vnc(dev); + pcibios_fixup_ebsa285(dev); pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq); @@ -164,18 +162,83 @@ dev->bus->number, dev->devfn, dev->vendor, dev->device, dev->irq); } - if (machine_is_netwinder()) - hw_init(); + + hw_init(); } __initfunc(void pcibios_init(void)) { - if (machine_is_ebsa285() || machine_is_cats()) - pcibios_init_ebsa285(); - if (machine_is_netwinder()) - pcibios_init_vnc(); + unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET; + unsigned long cntl; + + *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; + *CSR_SDRAMBASEOFFSET = 0; + *CSR_ROMBASEMASK = 0x80000000; + *CSR_CSRBASEMASK = 0; + *CSR_CSRBASEOFFSET = 0; + *CSR_PCIADDR_EXTN = 0; + +#ifdef CONFIG_HOST_FOOTBRIDGE + /* + * Against my better judgement, Philip Blundell still seems + * to be saying that we should initialise the PCI stuff here + * when the PCI_CFN bit is not set, dispite my comment below, + * which he decided to remove. If it is not set, then + * the card is in add-in mode, and we're in a machine where + * the bus is set up by 'others'. + * + * We should therefore not mess about with the mapping in + * anyway, and we should not be using the virt_to_bus functions + * that exist in the HOST architecture mode (since they assume + * a fixed mapping). + * + * Instead, you should be using ADDIN mode, which allows for + * this situation. This does assume that you have correctly + * initialised the PCI bus, which you must have done to get + * your PC booted. + * + * Unfortunately, he seems to be blind to this. I guess he'll + * also remove all this. + * + * And THIS COMMENT STAYS, even if this gets patched, thank + * you. + */ + + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). + * + * NOTE! If you need to chec the PCI_CFN bit in the SA110 + * control register then you've configured the kernel wrong. + * If you're not using host mode, then DO NOT set + * CONFIG_HOST_FOOTBRIDGE, but use CONFIG_ADDIN_FOOTBRIDGE + * instead. In this case, you MUST supply some firmware + * to allow your PC to boot, plus we should not modify the + * mappings that the PC BIOS has set up for us. + */ + *CSR_PCICACHELINESIZE = 0x00002008; + *CSR_PCICSRBASE = 0; + *CSR_PCICSRIOBASE = 0; + *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | + PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | + (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); +#endif + + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + cntl = *CSR_SA110_CNTL & 0xffffde07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + + pcibios_init_ebsa285(); - printk("DEC21285 PCI revision %02X\n", *(unsigned char *)0xfe000008); + printk(KERN_DEBUG"PCI: DEC21285 revision %02lX\n", *CSR_CLASSREV & 0xff); } __initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-a5k.c linux/arch/arm/kernel/dma-a5k.c --- v2.2.17/arch/arm/kernel/dma-a5k.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-a5k.c Fri Sep 15 23:28:37 2000 @@ -12,7 +12,6 @@ #include #include #include -#include #include "dma.h" @@ -37,8 +36,9 @@ if (channel != DMA_VIRTUAL_FLOPPY) printk("arch_dma_count: invalid channel %d\n", channel); else { - extern int floppy_fiqresidual(void); - return floppy_fiqresidual(); + struct pt_regs regs; + get_fiq_regs(®s); + return regs.ARM_r9; } return 0; } @@ -48,6 +48,7 @@ if (channel != DMA_VIRTUAL_FLOPPY) printk("arch_enable_dma: invalid channel %d\n", channel); else { + struct pt_regs regs; void *fiqhandler_start; unsigned int fiqhandler_length; extern void floppy_fiqsetup(unsigned long len, unsigned long addr, @@ -67,8 +68,10 @@ return; } memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); - flush_page_to_ram(0); - floppy_fiqsetup(dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE); + regs.ARM_r9 = dma->buf.length; + regs.ARM_r10 = __bus_to_virt(dma->buf.address); + regs.ARM_fp = (int)PCIO_FLOPPYDMABASE; + set_fiq_regs(®s); enable_irq(dma->dma_irq); } } @@ -83,7 +86,12 @@ } } -__initfunc(void arch_dma_init(dma_t *dma)) +int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns) +{ + return 0; +} + +void __init arch_dma_init(dma_t *dma) { dma[DMA_VIRTUAL_FLOPPY].dma_irq = 64; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c --- v2.2.17/arch/arm/kernel/dma-arc.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-arc.c Fri Sep 15 23:28:37 2000 @@ -1,10 +1,11 @@ /* * arch/arm/kernel/dma-arc.c * - * Copyright (C) 1998 Dave Gilbert / Russell King + * Copyright (C) 1998-1999 Dave Gilbert / Russell King * * DMA functions specific to Archimedes architecture */ +#include #include #include @@ -14,8 +15,11 @@ #include "dma.h" -int arch_request_dma(dmach_t channel, dma_t *dma) +#define DEBUG + +int arch_request_dma(dmach_t channel, dma_t *dma, const char * dev_id) { + printk("arch_request_dma channel=%d F0=%d F1=%d\n",channel,DMA_VIRTUAL_FLOPPY0,DMA_VIRTUAL_FLOPPY1); if (channel == DMA_VIRTUAL_FLOPPY0 || channel == DMA_VIRTUAL_FLOPPY1) return 0; @@ -25,16 +29,13 @@ void arch_free_dma(dmach_t channel, dma_t *dma) { - if (channel != DMA_VIRTUAL_FLOPPY0 && - channel != DMA_VIRTUAL_FLOPPY1) - return 0; - else - return -EINVAL; } void arch_enable_dma(dmach_t channel, dma_t *dma) { + printk("arch_enable_dma channel=%d F0=%d F1=%d\n",channel,DMA_VIRTUAL_FLOPPY0,DMA_VIRTUAL_FLOPPY1); switch (channel) { +#ifdef CONFIG_BLK_DEV_FD1772 case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */ switch (dma->dma_mode) { case DMA_MODE_READ: /* read */ @@ -96,9 +97,38 @@ restore_flags(flags); } break; +#endif } } +int arch_get_dma_residue(dmach_t channel, dma_t *dma) +{ + switch (channel) { +#ifdef CONFIG_BLK_DEV_FD1772 + case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */ + extern unsigned int fdc1772_bytestogo; + + /* 10/1/1999 DAG - I presume its the number of bytes left? */ + return fdc1772_bytestogo; + }; + break; + + case DMA_VIRTUAL_FLOPPY1: { /* Command completed */ + /* 10/1/1999 DAG - Presume whether there is an outstanding command? */ + extern unsigned int fdc1772_fdc_int_done; + + return (fdc1772_fdc_int_done==0)?1:0; /* Explicit! If the int done is 0 then 1 int to go */ + }; + break; + +#endif + + default: + printk("dma-arc.c:arch_get_dma_residue called with unknown/unconfigured DMA channel\n"); + return 0; + }; +} + void arch_disable_dma(dmach_t channel, dma_t *dma) { if (channel != DMA_VIRTUAL_FLOPPY0 && @@ -108,7 +138,12 @@ disable_irq(dma->dma_irq); } -__initfunc(void arch_dma_init(dma_t *dma)) +int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns) +{ + return 0; +} + +void __init arch_dma_init(dma_t *dma) { dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64; dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-dummy.c linux/arch/arm/kernel/dma-dummy.c --- v2.2.17/arch/arm/kernel/dma-dummy.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-dummy.c Fri Sep 15 23:28:37 2000 @@ -9,6 +9,10 @@ #include #include +#include + +spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED; + int request_dma(int channel, const char *device_id) { return -EINVAL; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-ebsa285.c linux/arch/arm/kernel/dma-ebsa285.c --- v2.2.17/arch/arm/kernel/dma-ebsa285.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-ebsa285.c Thu Jan 1 01:00:00 1970 @@ -1,101 +0,0 @@ -/* - * arch/arm/kernel/dma-ebsa285.c - * - * Copyright (C) 1998 Phil Blundell - * - * DMA functions specific to EBSA-285/CATS architectures - * - * Changelog: - * 09/11/1998 RMK Split out ISA DMA functions to dma-isa.c - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "dma.h" -#include "dma-isa.h" - -int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name) -{ - switch (channel) { - case 0: - case 1: /* 21285 internal channels */ - return 0; - - case 2 ... 9: - if (machine_is_cats()) - return isa_request_dma(channel - 2, dma, dev_name); - } - - return -EINVAL; -} - -void arch_free_dma(dmach_t channel, dma_t *dma) -{ - /* nothing to do */ -} - -int arch_get_dma_residue(dmach_t channel, dma_t *dma) -{ - int residue = 0; - - switch (channel) { - case 0: - case 1: - break; -#ifdef CONFIG_CATS - case 2 ... 9: - if (machine_is_cats()) - residue = isa_get_dma_residue(channel - 2); -#endif - } - return residue; -} - -void arch_enable_dma(dmach_t channel, dma_t *dma) -{ - switch (channel) { - case 0: - case 1: - /* - * Not yet implemented - */ - break; -#ifdef CONFIG_CATS - case 2 ... 9: - if (machine_is_cats()) - isa_enable_dma(channel - 2, dma); -#endif - } -} - -void arch_disable_dma(dmach_t channel, dma_t *dma) -{ - switch (channel) { - case 0: - case 1: - /* - * Not yet implemented - */ - break; -#ifdef CONFIG_CATS - case 2 ... 9: - if (machine_is_cats()) - isa_disable_dma(channel - 2, dma); -#endif - } -} - -__initfunc(void arch_dma_init(dma_t *dma)) -{ - /* Nothing to do */ -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-footbridge.c linux/arch/arm/kernel/dma-footbridge.c --- v2.2.17/arch/arm/kernel/dma-footbridge.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/kernel/dma-footbridge.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,109 @@ +/* + * arch/arm/kernel/dma-ebsa285.c + * + * Copyright (C) 1998 Phil Blundell + * + * DMA functions specific to EBSA-285/CATS architectures + * + * Changelog: + * 09-Nov-1998 RMK Split out ISA DMA functions to dma-isa.c + * 17-Mar-1999 RMK Allow any EBSA285-like architecture to have + * ISA DMA controllers. + */ + +#include +#include +#include +#include + +#include +#include + +#include "dma.h" +#include "dma-isa.h" + +#ifdef CONFIG_ISA_DMA +static int has_isa_dma; +#else +#define has_isa_dma 0 +#endif + +int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name) +{ + switch (channel) { + case _DC21285_DMA(0): + case _DC21285_DMA(1): /* 21285 internal channels */ + return 0; + + case _ISA_DMA(0) ... _ISA_DMA(7): + if (has_isa_dma) + return isa_request_dma(channel - _ISA_DMA(0), dma, dev_name); + } + + return -EINVAL; +} + +void arch_free_dma(dmach_t channel, dma_t *dma) +{ + /* nothing to do */ +} + +int arch_get_dma_residue(dmach_t channel, dma_t *dma) +{ + int residue = 0; + + switch (channel) { + case _DC21285_DMA(0): + case _DC21285_DMA(1): + break; + + case _ISA_DMA(0) ... _ISA_DMA(7): + if (has_isa_dma) + residue = isa_get_dma_residue(channel - _ISA_DMA(0), dma); + } + return residue; +} + +void arch_enable_dma(dmach_t channel, dma_t *dma) +{ + switch (channel) { + case _DC21285_DMA(0): + case _DC21285_DMA(1): + /* + * Not yet implemented + */ + break; + + case _ISA_DMA(0) ... _ISA_DMA(7): + if (has_isa_dma) + isa_enable_dma(channel - _ISA_DMA(0), dma); + } +} + +void arch_disable_dma(dmach_t channel, dma_t *dma) +{ + switch (channel) { + case _DC21285_DMA(0): + case _DC21285_DMA(1): + /* + * Not yet implemented + */ + break; + + case _ISA_DMA(0) ... _ISA_DMA(7): + if (has_isa_dma) + isa_disable_dma(channel - _ISA_DMA(0), dma); + } +} + +int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle_ns) +{ + return 0; +} + +void __init arch_dma_init(dma_t *dma) +{ +#ifdef CONFIG_ISA_DMA + has_isa_dma = isa_init_dma(); +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-isa.c linux/arch/arm/kernel/dma-isa.c --- v2.2.17/arch/arm/kernel/dma-isa.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-isa.c Fri Sep 15 23:28:37 2000 @@ -11,6 +11,7 @@ * Copyright (C) 1998 Phil Blundell */ #include +#include #include #include @@ -18,6 +19,11 @@ #include "dma.h" #include "dma-isa.h" +#define ISA_DMA_MODE_READ 0x44 +#define ISA_DMA_MODE_WRITE 0x48 +#define ISA_DMA_MODE_CASCADE 0xc0 +#define ISA_DMA_AUTOINIT 0x10 + #define ISA_DMA_MASK 0 #define ISA_DMA_MODE 1 #define ISA_DMA_CLRFF 2 @@ -40,10 +46,7 @@ int isa_request_dma(int channel, dma_t *dma, const char *dev_name) { - if (channel != 4) - return 0; - - return -EINVAL; + return 0; } void isa_free_dma(int channel, dma_t *dma) @@ -56,25 +59,27 @@ unsigned int io_port = isa_dma_port[channel][ISA_DMA_COUNT]; int count; - count = 1 + inb(io_port) + (inb(io_port) << 8); + count = 1 + inb(io_port); + count |= inb(io_port) << 8; return channel < 4 ? count : (count << 1); } void isa_enable_dma(int channel, dma_t *dma) { - unsigned long address, length; - if (dma->invalid) { + unsigned long address, length; + unsigned int mode; + address = dma->buf.address; length = dma->buf.length - 1; - outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); + outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); if (channel >= 4) { address >>= 1; - length = (length >> 1) & 0xfe; /* why &0xfe? */ + length >>= 1; } outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); @@ -85,17 +90,31 @@ outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); - outb(dma->dma_mode | (channel & 3), isa_dma_port[channel][ISA_DMA_MODE]); + mode = channel & 3; - switch (dma->dma_mode) { + switch (dma->dma_mode & DMA_MODE_MASK) { case DMA_MODE_READ: + mode |= ISA_DMA_MODE_READ; dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length); break; case DMA_MODE_WRITE: + mode |= ISA_DMA_MODE_WRITE; dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length); break; + + case DMA_MODE_CASCADE: + mode |= ISA_DMA_MODE_CASCADE; + break; + + default: + break; } + + if (dma->dma_mode & DMA_AUTOINIT) + mode |= ISA_DMA_AUTOINIT; + + outb(mode, isa_dma_port[channel][ISA_DMA_MODE]); dma->invalid = 0; } outb(channel & 3, isa_dma_port[channel][ISA_DMA_MASK]); @@ -104,4 +123,57 @@ void isa_disable_dma(int channel, dma_t *dma) { outb(channel | 4, isa_dma_port[channel][ISA_DMA_MASK]); +} + +__initfunc(int isa_init_dma(void)) +{ + int dmac_found; + + outb(0xff, 0x0d); + outb(0xff, 0xda); + + outb(0x55, 0x00); + outb(0xaa, 0x00); + + dmac_found = inb(0x00) == 0x55 && inb(0x00) == 0xaa; + + if (dmac_found) { + int channel; + + for (channel = 0; channel < 8; channel++) + isa_disable_dma(channel, NULL); + + outb(0x40, 0x0b); + outb(0x41, 0x0b); + outb(0x42, 0x0b); + outb(0x43, 0x0b); + + outb(0xc0, 0xd6); + outb(0x41, 0xd6); + outb(0x42, 0xd6); + outb(0x43, 0xd6); + + outb(0, 0xd4); + + outb(0x10, 0x08); + outb(0x10, 0xd0); + + /* + * Is this correct? According to + * my documentation, it doesn't + * appear to be. It should be + * outb(0x3f, 0x40b); outb(0x3f, 0x4d6); + */ + outb(0x30, 0x40b); + outb(0x31, 0x40b); + outb(0x32, 0x40b); + outb(0x33, 0x40b); + outb(0x31, 0x4d6); + outb(0x32, 0x4d6); + outb(0x33, 0x4d6); + + request_dma(DMA_ISA_CASCADE, "cascade"); + } + + return dmac_found; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-isa.h linux/arch/arm/kernel/dma-isa.h --- v2.2.17/arch/arm/kernel/dma-isa.h Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-isa.h Fri Sep 15 23:28:37 2000 @@ -23,3 +23,7 @@ */ void isa_disable_dma(int channel, dma_t *dma); +/* + * Initialise DMA + */ +int isa_init_dma(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.2.17/arch/arm/kernel/dma-rpc.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-rpc.c Fri Sep 15 23:28:37 2000 @@ -11,10 +11,10 @@ #include #include -#include #include #include #include +#include #include #include @@ -223,8 +223,9 @@ break; case DMA_VIRTUAL_FLOPPY: { - extern int floppy_fiqresidual(void); - residue = floppy_fiqresidual(); + struct pt_regs regs; + get_fiq_regs(®s); + return regs.ARM_r9; } break; } @@ -286,7 +287,6 @@ set_fiq_handler(fiqhandler_start, fiqhandler_length); set_fiq_regs(®s); enable_irq(dma->dma_irq); - } break; @@ -319,14 +319,56 @@ } } -__initfunc(void arch_dma_init(dma_t *dma)) +int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle) +{ + int tcr, speed; + + if (cycle < 188) + speed = 3; + else if (cycle <= 250) + speed = 2; + else if (cycle < 438) + speed = 1; + else + speed = 0; + + tcr = inb(IOMD_DMATCR); + speed &= 3; + + switch (channel) { + case DMA_0: + tcr = (tcr & ~0x03) | speed; + break; + + case DMA_1: + tcr = (tcr & ~0x0c) | (speed << 2); + break; + + case DMA_2: + tcr = (tcr & ~0x30) | (speed << 4); + break; + + case DMA_3: + tcr = (tcr & ~0xc0) | (speed << 6); + break; + + default: + break; + } + + outb(tcr, IOMD_DMATCR); + + return speed; +} + +void __init arch_dma_init(dma_t *dma) { outb(0, IOMD_IO0CR); outb(0, IOMD_IO1CR); outb(0, IOMD_IO2CR); outb(0, IOMD_IO3CR); -// outb(0xf0, IOMD_DMATCR); + outb(0xa0, IOMD_DMATCR); dma[0].dma_base = ioaddr(IOMD_IO0CURA); dma[0].dma_irq = IRQ_DMA0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma-vnc.c linux/arch/arm/kernel/dma-vnc.c --- v2.2.17/arch/arm/kernel/dma-vnc.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma-vnc.c Thu Jan 1 01:00:00 1970 @@ -1,51 +0,0 @@ -/* - * arch/arm/kernel/dma-vnc.c - * - * Copyright (C) 1998 Russell King - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "dma.h" -#include "dma-isa.h" - -int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name) -{ - if (channel < 8) - return isa_request_dma(channel, dma, dev_name); - return -EINVAL; -} - -void arch_free_dma(dmach_t channel, dma_t *dma) -{ - isa_free_dma(channel, dma); -} - -int arch_get_dma_residue(dmach_t channel, dma_t *dma) -{ - return isa_get_dma_residue(channel, dma); -} - -void arch_enable_dma(dmach_t channel, dma_t *dma) -{ - isa_enable_dma(channel, dma); -} - -void arch_disable_dma(dmach_t channel, dma_t *dma) -{ - isa_disable_dma(channel, dma); -} - -__initfunc(void arch_dma_init(dma_t *dma)) -{ - /* Nothing to do */ -} - diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c --- v2.2.17/arch/arm/kernel/dma.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma.c Fri Sep 15 23:28:37 2000 @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -201,6 +200,12 @@ printk (KERN_ERR "Trying to disable free DMA%d\n", channel); } +void set_dma_speed(dmach_t channel, int cycle_ns) +{ + dma_chan[channel].speed = + arch_set_dma_speed(channel, &dma_chan[channel], cycle_ns); +} + int get_dma_residue(dmach_t channel) { return arch_get_dma_residue(channel, &dma_chan[channel]); @@ -214,8 +219,9 @@ EXPORT_SYMBOL(set_dma_mode); EXPORT_SYMBOL(get_dma_residue); EXPORT_SYMBOL(set_dma_sg); +EXPORT_SYMBOL(set_dma_speed); -__initfunc(void init_dma(void)) +void __init init_dma(void) { arch_dma_init(dma_chan); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/dma.h linux/arch/arm/kernel/dma.h --- v2.2.17/arch/arm/kernel/dma.h Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/dma.h Fri Sep 15 23:28:37 2000 @@ -15,6 +15,7 @@ unsigned int active:1; /* Transfer active */ unsigned int invalid:1; /* Address/Count changed */ dmamode_t dma_mode; /* DMA mode */ + int speed; /* DMA speed */ unsigned int lock; /* Device is allocated */ const char *device_id; /* Device name */ @@ -62,6 +63,15 @@ * Returns : Number of bytes left to DMA */ int arch_get_dma_residue(dmach_t channel, dma_t *dma); + +/* Prototype: int arch_set_dma_speed(channel, dma, cycle) + * Purpose : Convert a cycle time to a register setting + * Params : channel - DMA channel number + * : dma - DMA structure for channel + * : cycle - cycle time in NS + * Returns : setting for 'dma->speed' + */ +int arch_set_dma_speed(dmach_t channel, dma_t *dma, int cycle); /* Prototype: void arch_dma_init(dma) * Purpose : Initialise architecture specific DMA diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.2.17/arch/arm/kernel/ecard.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/ecard.c Mon Oct 2 10:12:17 2000 @@ -7,32 +7,42 @@ * * Created from information from Acorns RiscOS3 PRMs * - * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether podule slot. + * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether + * podule slot. * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. - * 12-Sep-1997 RMK Created new handling of interrupt enables/disables - cards can - * now register their own routine to control interrupts (recommended). - * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled on reset from - * Linux. (Caused cards not to respond under RiscOS without hard reset). + * 12-Sep-1997 RMK Created new handling of interrupt enables/disables + * - cards can now register their own routine to control + * interrupts (recommended). + * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled + * on reset from Linux. (Caused cards not to respond + * under RiscOS without hard reset). * 15-Feb-1998 RMK Added DMA support * 12-Sep-1998 RMK Added EASI support + * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. + * 17-Apr-1999 RMK Support for EASI Type C cycles. */ #define ECARD_C +#define __KERNEL_SYSCALLS__ #include +#include #include #include #include #include #include #include +#include +#include #include -#include -#include +#include #include +#include +#include #include -#include +#include #ifdef CONFIG_ARCH_ARC #include @@ -40,45 +50,416 @@ #define oldlatch_init() #endif -#define BLACKLIST_NAME(m,p,s) { m, p, NULL, s } -#define BLACKLIST_LOADER(m,p,l) { m, p, l, NULL } -#define BLACKLIST_NOLOADER(m,p) { m, p, noloader, blacklisted_str } -#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) +enum req { + req_readbytes, + req_reset +}; -extern unsigned long atomwide_serial_loader[], oak_scsi_loader[], noloader[]; -static const char blacklisted_str[] = "*loader s/w is not 32-bit compliant*"; +struct ecard_request { + enum req req; + ecard_t *ec; + unsigned int address; + unsigned int length; + unsigned int use_loader; + void *buffer; +}; -static const struct expcard_blacklist { +struct expcard_blacklist { unsigned short manufacturer; unsigned short product; - const loader_t loader; const char *type; -} blacklist[] = { -/* Cards without names */ - BLACKLIST_NAME(MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1"), - -/* Cards with corrected loader */ - BLACKLIST_LOADER(MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, atomwide_serial_loader), - BLACKLIST_LOADER(MANU_OAK, PROD_OAK_SCSI, oak_scsi_loader), +}; -/* Supported cards with broken loader */ - { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI" }, +static ecard_t *cards; +static ecard_t *slot_to_expcard[MAX_ECARDS]; +static unsigned int ectcr; +#ifdef HAS_EXPMASK +static unsigned int have_expmask; +#endif -/* Unsupported cards with no loader */ - BLACKLIST_NOLOADER(MANU_MCS, PROD_MCS_CONNECT32) +/* List of descriptions of cards which don't have an extended + * identification, or chunk directories containing a description. + */ +static const struct expcard_blacklist __init blacklist[] = { + { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } }; +asmlinkage extern int +ecard_loader_reset(volatile unsigned char *pa, loader_t loader); +asmlinkage extern int +ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); extern int setup_arm_irq(int, struct irqaction *); +extern void do_ecard_IRQ(int, struct pt_regs *); + + +static void +ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs); + +static struct irqaction irqexpansioncard = { + ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL +}; + +static inline unsigned short +ecard_getu16(unsigned char *v) +{ + return v[0] | v[1] << 8; +} + +static inline signed long +ecard_gets24(unsigned char *v) +{ + return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); +} + +static inline ecard_t * +slot_to_ecard(unsigned int slot) +{ + return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; +} +/* ===================== Expansion card daemon ======================== */ /* - * from linux/arch/arm/kernel/irq.c + * Since the loader programs on the expansion cards need to be run + * in a specific environment, create a separate task with this + * environment up, and pass requests to this task as and when we + * need to. + * + * This should allow 99% of loaders to be called from Linux. + * + * From a security standpoint, we trust the card vendors. This + * may be a misplaced trust. */ -extern void do_ecard_IRQ(int irq, struct pt_regs *); +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) +#define POD_INT_ADDR(x) ((volatile unsigned char *)\ + ((BUS_ADDR((x)) - IO_BASE) + IO_START)) -static ecard_t expcard[MAX_ECARDS]; -static signed char irqno_to_expcard[16]; -static unsigned int ecard_numcards, ecard_numirqcards; -static unsigned int have_expmask; +static void +ecard_task_reset(struct ecard_request *req) +{ + if (req->ec == NULL) { + ecard_t *ec; + + for (ec = cards; ec; ec = ec->next) { + if (ec->loader) + ecard_loader_reset(POD_INT_ADDR(ec->podaddr), + ec->loader); + } + } else if (req->ec->loader) + ecard_loader_reset(POD_INT_ADDR(req->ec->podaddr), + req->ec->loader); +} + +static void +ecard_task_readbytes(struct ecard_request *req) +{ + unsigned char *buf = (unsigned char *)req->buffer; + volatile unsigned char *base_addr = + (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr); + unsigned int len = req->length; + + if (req->ec->slot_no == 8) { + /* + * The card maintains an index which + * increments the address into a 4096-byte + * page on each access. We need to keep + * track of the counter. + */ + static unsigned int index; + unsigned int offset, page; + unsigned char byte = 0; /* keep gcc quiet */ + + offset = req->address & 4095; + page = req->address >> 12; + + if (page > 256) + return; + + page *= 4; + + if (offset == 0 || index > offset) { + /* + * We need to reset the index counter. + */ + *base_addr = 0; + index = 0; + } + + while (index <= offset) { + byte = base_addr[page]; + index += 1; + } + + while (len--) { + *buf++ = byte; + if (len) { + byte = base_addr[page]; + index += 1; + } + } + } else { + unsigned int off = req->address; + + if (!req->use_loader || !req->ec->loader) { + off *= 4; + while (len--) { + *buf++ = base_addr[off]; + off += 4; + } + } else { + while(len--) { + /* + * The following is required by some + * expansion card loader programs. + */ + *(unsigned long *)0x108 = 0; + *buf++ = ecard_loader_read(off++, base_addr, + req->ec->loader); + } + } + } + +} + +#ifdef CONFIG_CPU_32 +static pid_t ecard_pid; +static struct wait_queue *ecard_wait; +static struct wait_queue *ecard_done; +static struct ecard_request *ecard_req; + +/* + * Set up the expansion card daemon's environment. + */ +static void +ecard_init_task(void) +{ + /* We want to set up the page tables for the following mapping: + * Virtual Physical + * 0x03000000 0x03000000 + * 0x03010000 unmapped + * 0x03210000 0x03210000 + * 0x03400000 unmapped + * 0x08000000 0x08000000 + * 0x10000000 unmapped + * + * FIXME: we don't follow this 100% yet. + */ + pgd_t *src_pgd, *dst_pgd; + unsigned int dst_addr = IO_START; + + src_pgd = pgd_offset(current->mm, IO_BASE); + dst_pgd = pgd_offset(current->mm, dst_addr); + + while (dst_addr < IO_START + IO_SIZE) { + *dst_pgd++ = *src_pgd++; + dst_addr += PGDIR_SIZE; + } + + flush_tlb_range(current->mm, IO_START, IO_START + IO_SIZE); + + dst_addr = EASI_START; + src_pgd = pgd_offset(current->mm, EASI_BASE); + dst_pgd = pgd_offset(current->mm, dst_addr); + + while (dst_addr < EASI_START + EASI_SIZE) { + *dst_pgd++ = *src_pgd++; + dst_addr += PGDIR_SIZE; + } + + flush_tlb_range(current->mm, EASI_START, EASI_START + EASI_SIZE); +} + +static int +ecard_task(void * unused) +{ + current->session = 1; + current->pgrp = 1; + + /* + * We don't want /any/ signals, not even SIGKILL + */ + sigfillset(¤t->blocked); + sigemptyset(¤t->signal); + + strcpy(current->comm, "kecardd"); + + /* + * Set up the environment + */ + ecard_init_task(); + + while (1) { + struct ecard_request *req; + + do { + req = xchg(&ecard_req, NULL); + + if (req == NULL) { + sigemptyset(¤t->signal); + interruptible_sleep_on(&ecard_wait); + } + } while (req == NULL); + + switch (req->req) { + case req_readbytes: + ecard_task_readbytes(req); + break; + + case req_reset: + ecard_task_reset(req); + break; + } + wake_up(&ecard_done); + } +} + +/* + * Wake the expansion card daemon to action our request. + * + * FIXME: The test here is not sufficient to detect if the + * kcardd is running. + */ +static inline void +ecard_call(struct ecard_request *req) +{ + /* + * If we're called from task 0, or from an + * interrupt (will be keyboard interrupt), + * we forcefully set up the memory map, and + * call the loader. We can't schedule, or + * sleep for this call. + */ + if ((current == task[0] || in_interrupt()) && + req->req == req_reset && req->ec == NULL) { + ecard_init_task(); + ecard_task_reset(req); + } else { + if (ecard_pid <= 0) + ecard_pid = kernel_thread(ecard_task, NULL, 0); + + ecard_req = req; + + wake_up(&ecard_wait); + + sleep_on(&ecard_done); + } +} +#else +/* + * On 26-bit processors, we don't need the kcardd thread to access the + * expansion card loaders. We do it directly. + */ +static inline void +ecard_call(struct ecard_request *req) +{ + if (req->req == req_reset) + ecard_task_reset(req); + else + ecard_task_readbytes(req); +} +#endif + +/* ======================= Mid-level card control ===================== */ +/* + * This is called to reset the loaders for each expansion card on reboot. + * + * This is required to make sure that the card is in the correct state + * that RiscOS expects it to be. + */ +void +ecard_reset(int slot) +{ + struct ecard_request req; + + req.req = req_reset; + + if (slot < 0) + req.ec = NULL; + else + req.ec = slot_to_ecard(slot); + + ecard_call(&req); + +#ifdef HAS_EXPMASK + if (have_expmask && slot < 0) { + have_expmask |= ~0; + EXPMASK_ENABLE = have_expmask; + } +#endif +} + +static void +ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) +{ + struct ecard_request req; + + req.req = req_readbytes; + req.ec = ec; + req.address = off; + req.length = len; + req.use_loader = useld; + req.buffer = addr; + + ecard_call(&req); +} + +int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) +{ + struct ex_chunk_dir excd; + int index = 16; + int useld = 0; + + if (!ec->cid.cd) + return 0; + + while(1) { + ecard_readbytes(&excd, ec, index, 8, useld); + index += 8; + if (c_id(&excd) == 0) { + if (!useld && ec->loader) { + useld = 1; + index = 0; + continue; + } + return 0; + } + if (c_id(&excd) == 0xf0) { /* link */ + index = c_start(&excd); + continue; + } + if (c_id(&excd) == 0x80) { /* loader */ + if (!ec->loader) { + ec->loader = (loader_t)kmalloc(c_len(&excd), + GFP_KERNEL); + if (ec->loader) + ecard_readbytes(ec->loader, ec, + (int)c_start(&excd), + c_len(&excd), useld); + else + return 0; + } + continue; + } + if (c_id(&excd) == id && num-- == 0) + break; + } + + if (c_id(&excd) & 0x80) { + switch (c_id(&excd) & 0x70) { + case 0x70: + ecard_readbytes((unsigned char *)excd.d.string, ec, + (int)c_start(&excd), c_len(&excd), + useld); + break; + case 0x00: + break; + } + } + cd->start_offset = c_start(&excd); + memcpy(cd->d.string, excd.d.string, 256); + return 1; +} + +/* ======================= Interrupt control ============================ */ static void ecard_def_irq_enable(ecard_t *ec, int irqnr) { @@ -100,6 +481,11 @@ #endif } +static int ecard_def_irq_pending(ecard_t *ec) +{ + return !ec->irqmask || ec->irqaddr[0] & ec->irqmask; +} + static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) { panic("ecard_def_fiq_enable called - impossible"); @@ -110,11 +496,18 @@ panic("ecard_def_fiq_disable called - impossible"); } +static int ecard_def_fiq_pending(ecard_t *ec) +{ + return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask; +} + static expansioncard_ops_t ecard_default_ops = { ecard_def_irq_enable, ecard_def_irq_disable, + ecard_def_irq_pending, ecard_def_fiq_enable, - ecard_def_fiq_disable + ecard_def_fiq_disable, + ecard_def_fiq_pending }; /* @@ -125,10 +518,9 @@ */ void ecard_enableirq(unsigned int irqnr) { - irqnr &= 7; - if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[irqnr]; + ecard_t *ec = slot_to_ecard(irqnr - 32); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -142,10 +534,9 @@ void ecard_disableirq(unsigned int irqnr) { - irqnr &= 7; - if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[irqnr]; + ecard_t *ec = slot_to_ecard(irqnr - 32); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -156,10 +547,9 @@ void ecard_enablefiq(unsigned int fiqnr) { - fiqnr &= 7; - if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[fiqnr]; + ecard_t *ec = slot_to_ecard(fiqnr); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -173,10 +563,9 @@ void ecard_disablefiq(unsigned int fiqnr) { - fiqnr &= 7; - if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { - ecard_t *ec = expcard + irqno_to_expcard[fiqnr]; + ecard_t *ec = slot_to_ecard(fiqnr); + if (ec) { if (!ec->ops) ec->ops = &ecard_default_ops; @@ -185,41 +574,89 @@ } } -static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) +static void +ecard_dump_irq_state(ecard_t *ec) +{ + printk(" %d: %sclaimed, ", + ec->slot_no, + ec->claimed ? "" : "not "); + + if (ec->ops && ec->ops->irqpending && + ec->ops != &ecard_default_ops) + printk("irq %spending\n", + ec->ops->irqpending(ec) ? "" : "not "); + else + printk("irqaddr %p, mask = %02X, status = %02X\n", + ec->irqaddr, ec->irqmask, *ec->irqaddr); +} + +static void +ecard_check_lockup(void) { - const int num_cards = ecard_numirqcards; - int i, called = 0; + static int last, lockup; + ecard_t *ec; - for (i = 0; i < num_cards; i++) { - if (expcard[i].claimed && expcard[i].irq && - (!expcard[i].irqmask || - expcard[i].irqaddr[0] & expcard[i].irqmask)) { - do_ecard_IRQ(expcard[i].irq, regs); - called ++; + /* + * If the timer interrupt has not run since the last million + * unrecognised expansion card interrupts, then there is + * something seriously wrong. Disable the expansion card + * interrupts so at least we can continue. + * + * Maybe we ought to start a timer to re-enable them some time + * later? + */ + if (last == jiffies) { + lockup += 1; + if (lockup > 1000000) { + printk(KERN_ERR "\nInterrupt lockup detected - " + "disabling all expansion card interrupts\n"); + + disable_irq(IRQ_EXPANSIONCARD); + + printk("Expansion card IRQ state:\n"); + + for (ec = cards; ec; ec = ec->next) + ecard_dump_irq_state(ec); } + } else + lockup = 0; + + /* + * If we did not recognise the source of this interrupt, + * warn the user, but don't flood the user with these messages. + */ + if (!last || time_after(jiffies, last + 5*HZ)) { + last = jiffies; + printk(KERN_WARNING "Unrecognised interrupt from backplane\n"); } - cli(); - if (called == 0) { - static int last, lockup; +} - if (last == jiffies) { - lockup += 1; - if (lockup > 1000000) { - printk(KERN_ERR "\nInterrupt lockup detected - disabling expansion card IRQs\n"); - disable_irq(intr_no); - printk("Expansion card IRQ state:\n"); - for (i = 0; i < num_cards; i++) - printk(" %d: %sclaimed, irqaddr = %p, irqmask = %X, status=%X\n", expcard[i].irq - 32, - expcard[i].claimed ? "" : "not", expcard[i].irqaddr, expcard[i].irqmask, *expcard[i].irqaddr); - } - } else - lockup = 0; +static void +ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) +{ + ecard_t *ec; + int called = 0; + + for (ec = cards; ec; ec = ec->next) { + int pending; + + if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8) + continue; + + if (ec->ops && ec->ops->irqpending) + pending = ec->ops->irqpending(ec); + else + pending = ecard_default_ops.irqpending(ec); - if (!last || time_after(jiffies, last + 5*HZ)) { - last = jiffies; - printk(KERN_ERR "\nUnrecognised interrupt from backplane\n"); + if (pending) { + do_ecard_IRQ(ec->irq, regs); + called ++; } } + cli(); + + if (called == 0) + ecard_check_lockup(); } #ifdef HAS_EXPMASK @@ -234,31 +671,35 @@ 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 }; -static void ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) +static void +ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs) { const unsigned int statusmask = 15; unsigned int status; status = EXPMASK_STATUS & statusmask; if (status) { - unsigned int irqno; + unsigned int slot; ecard_t *ec; again: - irqno = first_set[status]; - ec = expcard + irqno_to_expcard[irqno]; + slot = first_set[status]; + ec = slot_to_ecard(slot); if (ec->claimed) { unsigned int oldexpmask; /* - * this ugly code is so that we can operate a prioritorising system. + * this ugly code is so that we can operate a + * prioritorising system: + * * Card 0 highest priority * Card 1 * Card 2 * Card 3 lowest priority + * * Serial cards should go in 0/1, ethernet/scsi in 2/3 * otherwise you will lose serial data at high speeds! */ oldexpmask = have_expmask; - EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]); + EXPMASK_ENABLE = (have_expmask &= priority_masks[slot]); sti(); do_ecard_IRQ(ec->irq, regs); cli(); @@ -267,15 +708,18 @@ if (status) goto again; } else { - printk(KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno); - EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno)); + printk(KERN_WARNING "card%d: interrupt from unclaimed " + "card???\n", slot); + EXPMASK_ENABLE = (have_expmask &= ~(1 << slot)); } } else printk(KERN_WARNING "Wild interrupt from backplane (masks)\n"); } -static int ecard_checkirqhw(void) +__initfunc(static void +ecard_probeirqhw(void)) { + ecard_t *ec; int found; EXPMASK_ENABLE = 0x00; @@ -283,62 +727,78 @@ found = ((EXPMASK_STATUS & 15) == 0); EXPMASK_ENABLE = 0xff; - return found; + if (!found) + return; + + printk(KERN_DEBUG "Expansion card interrupt " + "management hardware found\n"); + + irqexpansioncard.handler = ecard_irq_expmask; + + /* for each card present, set a bit to '1' */ + have_expmask = 0x80000000; + + for (ec = cards; ec; ec = ec->next) + have_expmask |= 1 << ec->slot_no; + + EXPMASK_ENABLE = have_expmask; } +#else +#define ecard_probeirqhw() +#endif + +#ifndef IO_EC_MEMC8_BASE +#define IO_EC_MEMC8_BASE 0 #endif -static void ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) +unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) { - extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader); - unsigned char *a = (unsigned char *)addr; + unsigned long address = 0; + int slot = ec->slot_no; - if (ec->slot_no == 8) { - static unsigned int lowaddress; - unsigned int laddr, haddr; - unsigned char byte = 0; /* keep gcc quiet */ + if (ec->slot_no == 8) + return IO_EC_MEMC8_BASE; - laddr = off & 4095; /* number of bytes to read from offset + base addr */ - haddr = off >> 12; /* offset into card from base addr */ + ectcr &= ~(1 << slot); - if (haddr > 256) - return; + switch (type) { + case ECARD_MEMC: + if (slot < 4) + address = IO_EC_MEMC_BASE + (slot << 12); + break; - /* - * If we require a low address or address 0, then reset, and start again... - */ - if (!off || lowaddress > laddr) { - outb(0, ec->podaddr); - lowaddress = 0; - } - while (lowaddress <= laddr) { - byte = inb(ec->podaddr + haddr); - lowaddress += 1; - } - while (len--) { - *a++ = byte; - if (len) { - byte = inb(ec->podaddr + haddr); - lowaddress += 1; - } - } - } else { - if (!useld || !ec->loader) { - while(len--) - *a++ = inb(ec->podaddr + (off++)); - } else { - while(len--) { - *(unsigned long *)0x108 = 0; /* hack for some loaders!!! */ - *a++ = ecard_loader_read(off++, BUS_ADDR(ec->podaddr), ec->loader); - } - } + case ECARD_IOC: + if (slot < 4) + address = IO_EC_IOC_BASE + (slot << 12); +#ifdef IO_EC_IOC4_BASE + else + address = IO_EC_IOC4_BASE + ((slot - 4) << 12); +#endif + if (address) + address += speed << 17; + break; + +#ifdef IO_EC_EASI_BASE + case ECARD_EASI: + address = IO_EC_EASI_BASE + (slot << 22); + if (speed == ECARD_FAST) + ectcr |= 1 << slot; + break; +#endif } + +#ifdef IOMD_ECTCR + outb(ectcr, IOMD_ECTCR); +#endif + return address; } static int ecard_prints(char *buffer, ecard_t *ec) { char *start = buffer; - buffer += sprintf(buffer, "\n %d: ", ec->slot_no); + buffer += sprintf(buffer, " %d: %s ", ec->slot_no, + ec->type == ECARD_EASI ? "EASI" : " "); if (ec->cid.id == 0) { struct in_chunk_dir incd; @@ -346,63 +806,59 @@ buffer += sprintf(buffer, "[%04X:%04X] ", ec->cid.manufacturer, ec->cid.product); - if (!ec->card_desc && ec->cid.is && ec->cid.cd && + if (!ec->card_desc && ec->cid.cd && ecard_readchunk(&incd, ec, 0xf5, 0)) ec->card_desc = incd.d.string; if (!ec->card_desc) ec->card_desc = "*unknown*"; - buffer += sprintf(buffer, "%s", ec->card_desc); + buffer += sprintf(buffer, "%s\n", ec->card_desc); } else - buffer += sprintf(buffer, "Simple card %d", ec->cid.id); + buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id); return buffer - start; } -static inline unsigned short ecard_getu16(unsigned char *v) -{ - return v[0] | v[1] << 8; -} - -static inline signed long ecard_gets24(unsigned char *v) -{ - return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); -} - /* * Probe for an expansion card. * * If bit 1 of the first byte of the card is set, then the * card does not exist. */ -__initfunc(static int ecard_probe(int card, int freeslot, card_type_t type)) +__initfunc(static int +ecard_probe(int slot, card_type_t type)) { - ecard_t *ec = expcard + freeslot; + ecard_t **ecp; + ecard_t *ec; struct ex_ecid cid; char buffer[200]; - int i; + int i, rc = -ENOMEM; - irqno_to_expcard[card] = -1; + ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); - ec->slot_no = card; + if (!ec) + goto nodev; + + memset(ec, 0, sizeof(ecard_t)); + + ec->slot_no = slot; + ec->type = type; ec->irq = NO_IRQ; ec->fiq = NO_IRQ; ec->dma = NO_DMA; ec->card_desc = NULL; ec->ops = &ecard_default_ops; + rc = -ENODEV; if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) - return 0; + goto nodev; cid.r_zero = 1; ecard_readbytes(&cid, ec, 0, 16, 0); if (cid.r_zero) - return 0; - - irqno_to_expcard[card] = freeslot; + goto nodev; - ec->type = type; ec->cid.id = cid.r_id; ec->cid.cd = cid.r_cd; ec->cid.is = cid.r_is; @@ -415,9 +871,9 @@ ec->cid.fiqmask = cid.r_fiqmask; ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); ec->fiqaddr = - ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr); + ec->irqaddr = (unsigned char *)ioaddr(ec->podaddr); - if (ec->cid.cd && ec->cid.is) { + if (ec->cid.is) { ec->irqmask = ec->cid.irqmask; ec->irqaddr += ec->cid.irqoff; ec->fiqmask = ec->cid.fiqmask; @@ -430,88 +886,69 @@ for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) if (blacklist[i].manufacturer == ec->cid.manufacturer && blacklist[i].product == ec->cid.product) { - ec->loader = blacklist[i].loader; ec->card_desc = blacklist[i].type; break; } - ecard_prints(buffer, ec); - printk("%s", buffer); - - ec->irq = 32 + card; + ec->irq = 32 + slot; #ifdef IO_EC_MEMC8_BASE - if (card == 8) + if (slot == 8) ec->irq = 11; #endif #ifdef CONFIG_ARCH_RPC /* On RiscPC, only first two slots have DMA capability */ - if (card < 2) - ec->dma = 2 + card; + if (slot < 2) + ec->dma = 2 + slot; #endif #if 0 /* We don't support FIQs on expansion cards at the moment */ - ec->fiq = 96 + card; + ec->fiq = 96 + slot; #endif - return 1; -} + rc = 0; -/* - * This is called to reset the loaders for each expansion card on reboot. - * - * This is required to make sure that the card is in the correct state - * that RiscOS expects it to be. - */ -void ecard_reset(int card) -{ - extern int ecard_loader_reset(volatile unsigned int pa, loader_t loader); + for (ecp = &cards; *ecp; ecp = &(*ecp)->next); - if (card >= ecard_numcards) - return; - - if (card < 0) { - for (card = 0; card < ecard_numcards; card++) - if (expcard[card].loader) - ecard_loader_reset(BUS_ADDR(expcard[card].podaddr), - expcard[card].loader); - } else - if (expcard[card].loader) - ecard_loader_reset(BUS_ADDR(expcard[card].podaddr), - expcard[card].loader); + *ecp = ec; -#ifdef HAS_EXPMASK - if (have_expmask) { - have_expmask |= ~0; - EXPMASK_ENABLE = have_expmask; +nodev: + if (rc && ec) + kfree(ec); + else { + slot_to_expcard[slot] = ec; + + ecard_prints(buffer, ec); + printk("%s", buffer); } -#endif + return rc; } -static unsigned int ecard_startcard; +static ecard_t *finding_pos; void ecard_startfind(void) { - ecard_startcard = 0; + finding_pos = NULL; } ecard_t *ecard_find(int cid, const card_ids *cids) { - int card; + if (!finding_pos) + finding_pos = cards; + else + finding_pos = finding_pos->next; - if (!cids) { - for (card = ecard_startcard; card < ecard_numcards; card++) - if (!expcard[card].claimed && - (expcard[card].cid.id ^ cid) == 0) + for (; finding_pos; finding_pos = finding_pos->next) { + if (finding_pos->claimed) + continue; + + if (!cids) { + if ((finding_pos->cid.id ^ cid) == 0) break; - } else { - for (card = ecard_startcard; card < ecard_numcards; card++) { + } else { unsigned int manufacturer, product; int i; - if (expcard[card].claimed) - continue; - - manufacturer = expcard[card].cid.manufacturer; - product = expcard[card].cid.product; + manufacturer = finding_pos->cid.manufacturer; + product = finding_pos->cid.product; for (i = 0; cids[i].manufacturer != 65535; i++) if (manufacturer == cids[i].manufacturer && @@ -523,111 +960,24 @@ } } - ecard_startcard = card + 1; - - return card < ecard_numcards ? &expcard[card] : NULL; + return finding_pos; } -int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) +__initfunc(static void ecard_free_all(void)) { - struct ex_chunk_dir excd; - int index = 16; - int useld = 0; + ecard_t *ec, *ecn; - if (!ec->cid.is || !ec->cid.cd) - return 0; + for (ec = cards; ec; ec = ecn) { + ecn = ec->next; - while(1) { - ecard_readbytes(&excd, ec, index, 8, useld); - index += 8; - if (c_id(&excd) == 0) { - if (!useld && ec->loader) { - useld = 1; - index = 0; - continue; - } - return 0; - } - if (c_id(&excd) == 0xf0) { /* link */ - index = c_start(&excd); - continue; - } - if (c_id(&excd) == 0x80) { /* loader */ - if (!ec->loader) { - ec->loader = (loader_t)kmalloc(c_len(&excd), GFP_KERNEL); - ecard_readbytes(ec->loader, ec, (int)c_start(&excd), c_len(&excd), useld); - } - continue; - } - if (c_id(&excd) == id && num-- == 0) - break; + kfree(ec); } - if (c_id(&excd) & 0x80) { - switch (c_id(&excd) & 0x70) { - case 0x70: - ecard_readbytes((unsigned char *)excd.d.string, ec, - (int)c_start(&excd), c_len(&excd), useld); - break; - case 0x00: - break; - } - } - cd->start_offset = c_start(&excd); - memcpy(cd->d.string, excd.d.string, 256); - return 1; -} - -unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) -{ - switch (ec->slot_no) { - case 0 ... 3: - switch (type) { - case ECARD_MEMC: - return IO_EC_MEMC_BASE + (ec->slot_no << 12); - - case ECARD_IOC: - return IO_EC_IOC_BASE + (speed << 17) + (ec->slot_no << 12); - -#ifdef IO_EC_EASI_BASE - case ECARD_EASI: - return IO_EC_EASI_BASE + (ec->slot_no << 22); -#endif - } - break; - - case 4 ... 7: - switch (type) { -#ifdef IO_EC_IOC4_BASE - case ECARD_IOC: - return IO_EC_IOC4_BASE + (speed << 17) + ((ec->slot_no - 4) << 12); -#endif -#ifdef IO_EC_EASI_BASE - case ECARD_EASI: - return IO_EC_EASI_BASE + (ec->slot_no << 22); -#endif - default: - break; - } - break; + cards = NULL; -#ifdef IO_EC_MEMC8_BASE - case 8: - return IO_EC_MEMC8_BASE; -#endif - } - return 0; + memset(slot_to_expcard, 0, sizeof(slot_to_expcard)); } -static struct irqaction irqexpansioncard = { - ecard_irq_noexpmask, - SA_INTERRUPT, - 0, - "expansion cards", - NULL, - NULL -}; - /* * Initialise the expansion card system. * Locate all hardware - interrupt management and @@ -635,51 +985,31 @@ */ __initfunc(void ecard_init(void)) { - int i, nc = 0; - - memset(expcard, 0, sizeof(expcard)); + int slot; -#ifdef HAS_EXPMASK - if (ecard_checkirqhw()) { - printk(KERN_DEBUG "Expansion card interrupt management hardware found\n"); - irqexpansioncard.handler = ecard_irq_expmask; - irqexpansioncard.flags |= SA_IRQNOMASK; - have_expmask = -1; - } -#endif + oldlatch_init(); - printk("Installed expansion cards:"); + printk("Probing expansion cards: (does not imply support)\n"); - /* - * First of all, probe all cards on the expansion card interrupt line - */ - for (i = 0; i < 8; i++) - if (ecard_probe(i, nc, ECARD_IOC) || ecard_probe(i, nc, ECARD_EASI)) - nc += 1; - else - have_expmask &= ~(1< + .equ ioc_base_high, IOC_BASE & 0xff000000 .equ ioc_base_low, IOC_BASE & 0x00ff0000 .macro disable_fiq @@ -186,113 +194,113 @@ .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 .endm -#elif defined(CONFIG_ARCH_EBSA285) +#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE) +#include .macro disable_fiq .endm + .equ irq_mask_pci_err_high, IRQ_MASK_PCI_ERR & 0xff000000 + .equ irq_mask_pci_err_low, IRQ_MASK_PCI_ERR & 0x00ffffff + .equ dc21285_high, ARMCSR_BASE & 0xff000000 + .equ dc21285_low, ARMCSR_BASE & 0x00ffffff + .macro get_irqnr_and_base, irqnr, irqstat, base - mov r4, #0xfe000000 + mov r4, #dc21285_high + .if dc21285_low + orr r4, r4, #dc21285_low + .endif ldr \irqstat, [r4, #0x180] @ get interrupts - mov \irqnr, #0 -1001: tst \irqstat, #1 - addeq \irqnr, \irqnr, #1 - moveq \irqstat, \irqstat, lsr #1 - tsteq \irqnr, #32 - beq 1001b - teq \irqnr, #32 - .endm - .macro irq_prio_table - .endm + mov \irqnr, #IRQ_SDRAMPARITY + tst \irqstat, #IRQ_MASK_SDRAMPARITY + bne 1001f -#elif defined(CONFIG_ARCH_NEXUSPCI) + tst \irqstat, #IRQ_MASK_UART_RX + movne \irqnr, #IRQ_CONRX + bne 1001f - .macro disable_fiq - .endm + tst \irqstat, #IRQ_MASK_DMA1 + movne \irqnr, #IRQ_DMA1 + bne 1001f - .macro get_irqnr_and_base, irqnr, irqstat, base - ldr r4, =0xffe00000 - ldr \irqstat, [r4, #0x180] @ get interrupts - mov \irqnr, #0 -1001: tst \irqstat, #1 - addeq \irqnr, \irqnr, #1 - moveq \irqstat, \irqstat, lsr #1 - tsteq \irqnr, #32 - beq 1001b - teq \irqnr, #32 - .endm + tst \irqstat, #IRQ_MASK_DMA2 + movne \irqnr, #IRQ_DMA2 + bne 1001f - .macro irq_prio_table - .endm + tst \irqstat, #IRQ_MASK_IN0 + movne \irqnr, #IRQ_IN0 + bne 1001f -#elif defined(CONFIG_ARCH_VNC) + tst \irqstat, #IRQ_MASK_IN1 + movne \irqnr, #IRQ_IN1 + bne 1001f - .macro disable_fiq - .endm + tst \irqstat, #IRQ_MASK_IN2 + movne \irqnr, #IRQ_IN2 + bne 1001f - .equ pci_iack_high, PCI_IACK & 0xff000000 - .equ pci_iack_low, PCI_IACK & 0x00ff0000 + tst \irqstat, #IRQ_MASK_IN3 + movne \irqnr, #IRQ_IN3 + bne 1001f - .macro get_irqnr_and_base, irqnr, irqstat, base - mov r4, #IO_BASE_ARM_CSR - ldr \irqstat, [r4, #CSR_IRQ_STATUS] @ just show us the unmasked ones + tst \irqstat, #IRQ_MASK_PCI + movne \irqnr, #IRQ_PCI + bne 1001f - @ run through hard priorities - @ timer - tst \irqstat, #IRQ_MASK_TIMER0 - movne \irqnr, #IRQ_TIMER0 + tst \irqstat, #IRQ_MASK_DOORBELLHOST + movne \irqnr, #IRQ_DOORBELLHOST + bne 1001f + + tst \irqstat, #IRQ_MASK_I2OINPOST + movne \irqnr, #IRQ_I2OINPOST bne 1001f - @ ether10 - tst \irqstat, #IRQ_MASK_ETHER10 - movne \irqnr, #IRQ_ETHER10 + tst \irqstat, #IRQ_MASK_TIMER1 + movne \irqnr, #IRQ_TIMER1 bne 1001f - @ ether100 - tst \irqstat, #IRQ_MASK_ETHER100 - movne \irqnr, #IRQ_ETHER100 + tst \irqstat, #IRQ_MASK_TIMER2 + movne \irqnr, #IRQ_TIMER2 bne 1001f - @ video compressor - tst \irqstat, #IRQ_MASK_VIDCOMP - movne \irqnr, #IRQ_VIDCOMP + tst \irqstat, #IRQ_MASK_TIMER3 + movne \irqnr, #IRQ_TIMER3 bne 1001f - @ now try all the PIC sources - @ determine whether we have an irq - tst \irqstat, #IRQ_MASK_EXTERN_IRQ - beq 1002f - mov r4, #pci_iack_high - orr r4, r4, #pci_iack_low - ldrb \irqnr, [r4] @ get the IACK byte - b 1001f + tst \irqstat, #IRQ_MASK_UART_TX + movne \irqnr, #IRQ_CONTX + bne 1001f -1002: @ PCI errors - tst \irqstat, #IRQ_MASK_PCI_ERR + tst \irqstat, #irq_mask_pci_err_high + tsteq \irqstat, #irq_mask_pci_err_low movne \irqnr, #IRQ_PCI_ERR bne 1001f +1001: + .endm - @ softint - tst \irqstat, #IRQ_MASK_SOFTIRQ - movne \irqnr, #IRQ_SOFTIRQ - bne 1001f + .macro irq_prio_table + .endm - @ debug uart - tst \irqstat, #IRQ_MASK_UART_DEBUG - movne \irqnr, #IRQ_CONRX - bne 1001f +#elif defined(CONFIG_ARCH_NEXUSPCI) - @ watchdog - tst \irqstat, #IRQ_MASK_WATCHDOG - movne \irqnr, #IRQ_WATCHDOG + .macro disable_fiq + .endm -1001: @ If Z is set, then we will not enter an interrupt + .macro get_irqnr_and_base, irqnr, irqstat, base + ldr r4, =0xffe00000 + ldr \irqstat, [r4, #0x180] @ get interrupts + mov \irqnr, #0 +1001: tst \irqstat, #1 + addeq \irqnr, \irqnr, #1 + moveq \irqstat, \irqstat, lsr #1 + tsteq \irqnr, #32 + beq 1001b + teq \irqnr, #32 .endm .macro irq_prio_table .endm - #else #error Unknown architecture #endif @@ -306,22 +314,20 @@ stmia sp, {r0 - r12} @ Calling r0 - r12 add r8, sp, #S_PC stmdb r8, {sp, lr}^ @ Calling sp, lr - mov r7, r0 + str lr, [r8, #0] @ Save calling PC mrs r6, spsr - mov r5, lr - stmia r8, {r5, r6, r7} @ Save calling PC, CPSR, OLD_R0 + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 .endm .macro restore_user_regs - mrs r0, cpsr @ disable IRQs - orr r0, r0, #I_BIT - msr cpsr, r0 ldr r0, [sp, #S_PSR] @ Get calling cpsr + msr 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 - add sp, sp, #S_PC - ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE movs pc, lr @ return & move spsr_svc into cpsr .endm @@ -331,16 +337,15 @@ /* 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 @@ -348,25 +353,6 @@ msr cpsr, \temp .endm - .macro initialise_traps_extra - mrs r0, cpsr - bic r0, r0, #31 - orr r0, r0, #0xd3 - msr cpsr, r0 - .endm - - -#ifndef __ARM_ARCH_4__ -.Larm700bug: str lr, [r8] - ldr r0, [sp, #S_PSR] @ Get calling cpsr - msr spsr, r0 - ldmia sp, {r0 - lr}^ @ Get calling r0 - lr - mov r0, r0 - add sp, sp, #S_PC - ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0 - movs pc, lr -#endif - .macro get_current_task, rd mov \rd, sp, lsr #13 mov \rd, \rd, lsl #13 @@ -379,269 +365,124 @@ adr\cond \reg, \label .endm -/*============================================================================= - * Address exception handler - *----------------------------------------------------------------------------- - * These aren't too critical. - * (they're not supposed to happen, and won't happen in 32-bit mode). - */ - -vector_addrexcptn: - b vector_addrexcptn - -/*============================================================================= - * Undefined FIQs - *----------------------------------------------------------------------------- - * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC - * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg. - * Basically to switch modes, we *HAVE* to clobber one register... brain - * damage alert! I don't think that we can execute any code in here in any - * other mode than FIQ... Ok you can switch to another mode, but you can't - * get out of that mode without clobbering one register. - */ -_unexp_fiq: disable_fiq - subs pc, lr, #4 - -/*============================================================================= - * Interrupt entry dispatcher - *----------------------------------------------------------------------------- - * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC - */ -vector_IRQ: @ - @ save mode specific registers - @ - ldr r13, .LCirq - sub lr, lr, #4 - str lr, [r13] @ save lr_IRQ - mrs lr, spsr - str lr, [r13, #4] @ save spsr_IRQ - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr @ switch to SVC mode - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - cmp lr, #4 - addlts pc, pc, lr, lsl #2 @ Changes mode and branches - b __irq_invalid @ 4 - 15 - b __irq_usr @ 0 (USR_26 / USR_32) - b __irq_invalid @ 1 (FIQ_26 / FIQ_32) - b __irq_invalid @ 2 (IRQ_26 / IRQ_32) - b __irq_svc @ 3 (SVC_26 / SVC_32) -/* - *------------------------------------------------------------------------------------------------ - * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode - *------------------------------------------------------------------------------------------------ - * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC - */ -.LCirq: .word __temp_irq -.LCund: .word __temp_und -.LCabt: .word __temp_abt + .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 -vector_undefinstr: - @ - @ save mode specific registers - @ - ldr r13, [pc, #.LCund - . - 8] - str lr, [r13] - mrs lr, spsr - str lr, [r13, #4] - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - cmp lr, #4 - addlts pc, pc, lr, lsl #2 @ Changes mode and branches - b __und_invalid @ 4 - 15 - b __und_usr @ 0 (USR_26 / USR_32) - b __und_invalid @ 1 (FIQ_26 / FIQ_32) - b __und_invalid @ 2 (IRQ_26 / IRQ_32) - b __und_svc @ 3 (SVC_26 / SVC_32) -/* - *------------------------------------------------------------------------------------------------ - * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode - *------------------------------------------------------------------------------------------------ - * Enter in ABT mode, spsr = USR CPSR, lr = USR PC - */ -vector_prefetch: - @ - @ save mode specific registers - @ - sub lr, lr, #4 - ldr r13, .LCabt - str lr, [r13] - mrs lr, spsr - str lr, [r13, #4] - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - adds pc, pc, lr, lsl #2 @ Changes mode and branches - b __pabt_invalid @ 4 - 15 - b __pabt_usr @ 0 (USR_26 / USR_32) - b __pabt_invalid @ 1 (FIQ_26 / FIQ_32) - b __pabt_invalid @ 2 (IRQ_26 / IRQ_32) - b __pabt_invalid @ 3 (SVC_26 / SVC_32) /* - *------------------------------------------------------------------------------------------------ - * Data abort dispatcher - dispatches it to the correct handler for the processor mode - *------------------------------------------------------------------------------------------------ - * Enter in ABT mode, spsr = USR CPSR, lr = USR PC + * Invalid mode handlers */ -vector_data: @ - @ save mode specific registers - @ - sub lr, lr, #8 - ldr r13, .LCabt - str lr, [r13] - mrs lr, spsr - str lr, [r13, #4] - @ - @ now branch to the relevent MODE handling routine - @ - mrs sp, cpsr - bic sp, sp, #31 - orr sp, sp, #0x13 - msr spsr, sp - and lr, lr, #15 - cmp lr, #4 - addlts pc, pc, lr, lsl #2 @ Changes mode & branches - b __dabt_invalid @ 4 - 15 - b __dabt_usr @ 0 (USR_26 / USR_32) - b __dabt_invalid @ 1 (FIQ_26 / FIQ_32) - b __dabt_invalid @ 2 (IRQ_26 / IRQ_32) - b __dabt_svc @ 3 (SVC_26 / SVC_32) +__pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - lr} @ Save XXX r0 - lr + ldr r4, .LCabt + mov r1, #BAD_PREFETCH + b 1f -/*============================================================================= - * Prefetch abort handler - *----------------------------------------------------------------------------- - */ -pabtmsg: .ascii "Pabt: %08lX\n\0" - .align -__pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go - stmia sp, {r0 - r12} @ Save r0 - r12 - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr +__dabt_invalid: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact] ldr r4, .LCabt - ldmia r4, {r5 - r7} @ Get USR pc, cpsr - stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 + mov r1, #BAD_DATA + b 1f - mrs r7, cpsr @ Enable interrupts if they were - bic r7, r7, #I_BIT @ previously - msr cpsr, r7 - mov r0, r5 @ address (pc) - mov r1, sp @ regs - bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler - teq r0, #0 @ Does this still apply??? - bne ret_from_exception @ Return from exception -#ifdef DEBUG_UNDEF - adr r0, t - bl SYMBOL_NAME(printk) -#endif - mov r0, r5 - mov r1, sp - and r2, r6, #31 - bl SYMBOL_NAME(do_undefinstr) - ldr lr, [sp, #S_PSR] @ Get USR cpsr - msr spsr, lr - ldmia sp, {r0 - pc}^ @ Restore USR registers +__irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame + stmfd sp, {r0 - lr} @ Save r0 - lr + ldr r4, .LCirq + mov r1, #BAD_IRQ + b 1f -__pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go - stmia sp, {r0 - lr} @ Save XXX r0 - lr - mov r7, r0 @ OLD R0 - ldr r4, .LCabt - ldmia r4, {r5 - r7} @ Get XXX pc, cpsr +__und_invalid: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - lr} + ldr r4, .LCund + mov r1, #BAD_UNDEFINSTR @ int reason + +1: mov fp, #0 + ldmia r4, {r5 - r7} @ Get XXX pc, cpsr, old_r0 add r4, sp, #S_PC stmia r4, {r5 - r7} @ Save XXX pc, cpsr, old_r0 - mov r0, sp @ Prefetch aborts are definitely *not* - mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant - and r2, r6, #31 @ recover from this problem. + mov r0, sp + and r2, r6, #31 @ int mode b SYMBOL_NAME(bad_mode) -#ifdef DEBUG_UNDEF -t: .ascii "*** undef ***\r\n\0" - .align -#endif -/*============================================================================= - * Data abort handler code - *----------------------------------------------------------------------------- +wfs_mask_data: .word 0x0e200110 @ WFS/RFS + .word 0x0fef0fff + .word 0x0d0d0100 @ LDF [sp]/STF [sp] + .word 0x0d0b0100 @ LDF [fp]/STF [fp] + .word 0x0f0f0f00 + +/* We get here if an undefined instruction happens and the floating + * point emulator is not present. If the offending instruction was + * a WFS, we just perform a normal return as if we had emulated the + * operation. This is a hack to allow some basic userland binaries + * to run so that the emulator module proper can be loaded. --philb */ -.LCprocfns: .word SYMBOL_NAME(processor) +fpe_not_present: + adr r10, wfs_mask_data + ldmia r10, {r4, r5, r6, r7, r8} + ldr r10, [sp, #S_PC] @ Load PC + sub r10, r10, #-4 + mask_pc r10, r10 + ldrt r10, [r10] @ get instruction + and r5, r10, r5 + teq r5, r4 @ Is it WFS? + moveq pc, r9 + and r5, r10, r8 + teq r5, r6 @ Is it LDF/STF on sp or fp? + teqne r5, r7 + movne pc, lr + tst r10, #0x00200000 @ Does it have WB + moveq pc, r9 + and r4, r10, #255 @ get offset + and r6, r10, #0x000f0000 + tst r10, #0x00800000 @ +/- + ldr r5, [sp, r6, lsr #14] @ Load reg + rsbeq r4, r4, #0 + add r5, r5, r4, lsl #2 + str r5, [sp, r6, lsr #14] @ Save reg + mov pc, r9 -__dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go - stmia sp, {r0 - r12} @ save r0 - r12 - add r3, sp, #S_PC - stmdb r3, {sp, lr}^ - ldr r0, .LCabt - ldmia r0, {r0 - r2} @ Get USR pc, cpsr - stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0 - mov fp, #0 - mrs r2, cpsr @ Enable interrupts if they were - bic r2, r2, #I_BIT @ previously - msr cpsr, r2 - ldr r2, .LCprocfns - mov lr, pc - ldr pc, [r2, #8] @ call processor specific code - mov r3, sp - bl SYMBOL_NAME(do_DataAbort) - b ret_from_sys_call - -__dabt_svc: sub sp, sp, #S_FRAME_SIZE +/* + * SVC mode handlers + */ + .align 5 +__dabt_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 ldr r2, .LCabt add r0, sp, #S_FRAME_SIZE + ldmia r2, {r2 - r4} @ get pc, cpsr add r5, sp, #S_SP mov r1, lr - ldmia r2, {r2 - r4} @ get pc, cpsr stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + mrs r9, cpsr @ Enable interrupts if they were tst r3, #I_BIT - mrseq r0, cpsr @ Enable interrupts if they were - biceq r0, r0, #I_BIT @ previously - msreq cpsr, r0 + biceq r9, r9, #I_BIT @ previously mov r0, r2 +/* + * This routine must not corrupt r9 + */ ldr r2, .LCprocfns mov lr, pc ldr pc, [r2, #8] @ call processor specific code + 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 -__dabt_invalid: sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact] - mov r7, r0 - ldr r4, .LCabt - ldmia r4, {r5, r6} @ Get SVC pc, cpsr - add r4, sp, #S_PC - stmia r4, {r5, r6, r7} @ Save SVC pc, cpsr, old_r0 - mov r0, sp - mov r1, #BAD_DATA - and r2, r6, #31 - b SYMBOL_NAME(bad_mode) - -/*============================================================================= - * Interrupt (IRQ) handler - *----------------------------------------------------------------------------- - */ -__irq_usr: sub sp, sp, #S_FRAME_SIZE + .align 5 +__irq_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ - ldr r4, .LCirq - ldmia r4, {r5 - r7} @ get saved PC, SPSR - stmia r8, {r5 - r7} @ save pc, psr, old_r0 + ldr r7, .LCirq + add r5, sp, #S_FRAME_SIZE + ldmia r7, {r7 - r9} + add r4, sp, #S_SP + mov r6, lr + stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro 1: get_irqnr_and_base r0, r6, r5 movne r1, sp @ @@ -649,148 +490,388 @@ @ adrsvc ne, lr, 1b bne do_IRQ - b ret_with_reschedule - - irq_prio_table + ldr r0, [sp, #S_PSR] @ irqs are already disabled + msr spsr, r0 + ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr -__irq_svc: sub sp, sp, #S_FRAME_SIZE + .align 5 +__und_svc: sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ save r0 - r12 + ldr r7, .LCund mov r6, lr - ldr r7, .LCirq ldmia r7, {r7 - r9} add r5, sp, #S_FRAME_SIZE add r4, sp, #S_SP - stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + + adrsvc al, r9, 1f @ r9 = normal FP return + bl call_fpe @ lr = undefined instr return + + mov r0, r5 @ unsigned long pc + mov r1, sp @ struct pt_regs *regs + bl SYMBOL_NAME(do_undefinstr) + +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 + + .align 5 +.LCirq: .word __temp_irq +.LCund: .word __temp_und +.LCabt: .word __temp_abt +.LCprocfns: .word SYMBOL_NAME(processor) +.LCfp: .word SYMBOL_NAME(fp_enter) +#ifdef CONFIG_ALIGNMENT_TRAP +.LCswi: .word SYMBOL_NAME(cr_alignment) +#endif + + irq_prio_table + +/* + * User mode handlers + */ + .align 5 +__dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - r12} @ save r0 - r12 + ldr r4, .LCabt + add r3, sp, #S_PC + ldmia r4, {r0 - r2} @ Get USR pc, cpsr + stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0 + stmdb r3, {sp, lr}^ + alignment_trap r4, r7, __temp_abt + mov fp, #0 + ldr r2, .LCprocfns + mov lr, pc + ldr pc, [r2, #8] @ call processor specific code + msr cpsr_c, #MODE_SVC @ Enable interrupts + mov r3, sp + adrsvc al, lr, ret_from_sys_call + b SYMBOL_NAME(do_DataAbort) + + .align 5 +__irq_usr: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ save r0 - r12 + ldr r4, .LCirq + add r8, sp, #S_PC + ldmia r4, {r5 - r7} @ get saved PC, SPSR + stmia r8, {r5 - r7} @ save pc, psr, old_r0 + stmdb r8, {sp, lr}^ + alignment_trap r4, r7, __temp_irq + mov fp, #0 1: get_irqnr_and_base r0, r6, r5 movne r1, sp + adrsvc ne, lr, 1b @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ - adrsvc ne, lr, 1b bne do_IRQ - ldr r0, [sp, #S_PSR] - msr spsr, r0 - ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr - -__irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame - stmfd sp, {r0 - lr} @ Save r0 - lr - mov r7, #-1 - ldr r4, .LCirq - ldmia r4, {r5, r6} @ get saved pc, psr - add r4, sp, #S_PC - stmia r4, {r5, r6, r7} - mov fp, #0 - mov r0, sp - mov r1, #BAD_IRQ - b SYMBOL_NAME(bad_mode) - -/*============================================================================= - * Undefined instruction handler - *----------------------------------------------------------------------------- - * Handles floating point instructions - */ -.LC2: .word SYMBOL_NAME(fp_enter) + mov r4, #0 + b ret_with_reschedule + .align 5 __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia sp, {r0 - r12} @ Save r0 - r12 - add r8, sp, #S_PC - stmdb r8, {sp, lr}^ @ Save user r0 - r12 ldr r4, .LCund + add r8, sp, #S_PC ldmia r4, {r5 - r7} stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 + stmdb r8, {sp, lr}^ @ Save user r0 - r12 + alignment_trap r4, r7, __temp_und mov fp, #0 - - adrsvc al, r9, ret_from_exception @ r9 = normal FP return + adrsvc al, r9, ret_from_sys_call @ r9 = normal FP return adrsvc al, lr, fpundefinstr @ lr = undefined instr return -1: get_current_task r10 +call_fpe: get_current_task r10 mov r8, #1 strb r8, [r10, #TSK_USED_MATH] @ set current->used_math + ldr r4, .LCfp add r10, r10, #TSS_FPESAVE @ r10 = workspace - ldr r4, .LC2 ldr pc, [r4] @ Call FP module USR entry point -__und_svc: sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - r12} @ save r0 - r12 - mov r6, lr - ldr r7, .LCund - ldmia r7, {r7 - r9} - add r5, sp, #S_FRAME_SIZE - add r4, sp, #S_SP - stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro - - adrsvc al, r9, 3f @ r9 = normal FP return - bl 1b @ lr = undefined instr return +fpundefinstr: mov r0, lr + mov r1, sp + msr cpsr_c, #MODE_SVC + adrsvc al, lr, ret_from_sys_call + b SYMBOL_NAME(do_undefinstr) - mov r0, r5 @ unsigned long pc - mov r1, sp @ struct pt_regs *regs + .align 5 +__pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - r12} @ Save r0 - r12 + ldr r4, .LCabt + add r8, sp, #S_PC + 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 + alignment_trap r4, r7, __temp_abt + mov fp, #0 + msr cpsr_c, #MODE_SVC @ Enable interrupts + mov r0, r5 @ address (pc) + mov r1, sp @ regs + bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler + teq r0, #0 @ Does this still apply??? + bne ret_from_sys_call @ Return from exception +#ifdef DEBUG_UNDEF + adr r0, t + bl SYMBOL_NAME(printk) +#endif + mov r0, r5 + mov r1, sp + and r2, r6, #31 bl SYMBOL_NAME(do_undefinstr) - -3: ldr lr, [sp, #S_PSR] @ Get SVC cpsr + ldr lr, [sp, #S_PSR] @ Get USR cpsr msr spsr, lr - ldmia sp, {r0 - pc}^ @ Restore SVC registers + ldmia sp, {r0 - pc}^ @ Restore USR registers -fpundefinstr: mov r0, lr - mov r1, sp - mrs r4, cpsr @ Enable interrupts - bic r4, r4, #I_BIT - msr cpsr, r4 - adrsvc al, lr, ret_from_exception - b SYMBOL_NAME(do_undefinstr) +#ifdef DEBUG_UNDEF +t: .ascii "Prefetch -> undefined instruction\n\0" + .align +#endif -__und_invalid: sub sp, sp, #S_FRAME_SIZE - stmia sp, {r0 - lr} - mov r7, r0 - ldr r4, .LCund - ldmia r4, {r5, r6} @ Get UND/IRQ/FIQ/ABT pc, cpsr - add r4, sp, #S_PC - stmia r4, {r5, r6, r7} @ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0 - mov r0, sp @ struct pt_regs *regs - mov r1, #BAD_UNDEFINSTR @ int reason - and r2, r6, #31 @ int mode - b SYMBOL_NAME(bad_mode) @ Does not ever return... +#include "entry-common.S" -/* We get here if an undefined instruction happens and the floating - * point emulator is not present. If the offending instruction was - * a WFS, we just perform a normal return as if we had emulated the - * operation. This is a hack to allow some basic userland binaries - * to run so that the emulator module proper can be loaded. --philb + .text + +#ifndef __ARM_ARCH_4__ +.Larm700bug: ldr r0, [sp, #S_PSR] @ Get calling cpsr + str lr, [r8] + msr spsr, r0 + ldmia sp, {r0 - lr}^ @ Get calling r0 - lr + mov r0, r0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE + movs pc, lr +#endif + + .section ".text.init",#alloc,#execinstr +/* + * Vector stubs. NOTE that we only align 'vector_IRQ' to a cache line boundary, + * and we rely on each stub being exactly 48 (1.5 cache lines) in size. This + * means that we only ever load two cache lines for this code, or one if we're + * lucky. We also copy this code to 0x200 so that we can use branches in the + * vectors, rather than ldr's. */ -fpe_not_present: - adr r10, wfs_mask_data - ldmia r10, {r4, r5, r6, r7, r8} - ldr r10, [sp, #S_PC] @ Load PC - sub r10, r10, #4 - mask_pc r10, r10 - ldrt r10, [r10] @ get instruction - and r5, r10, r5 - teq r5, r4 @ Is it WFS? - moveq pc, r9 - and r5, r10, r8 - teq r5, r6 @ Is it LDF/STF on sp or fp? - teqne r5, r7 - movne pc, lr - tst r10, #0x00200000 @ Does it have WB - moveq pc, r9 - and r4, r10, #255 @ get offset - and r6, r10, #0x000f0000 - tst r10, #0x00800000 @ +/- - rsbeq r4, r4, #0 - ldr r5, [sp, r6, lsr #14] @ Load reg - add r5, r5, r4, lsl #2 - str r5, [sp, r6, lsr #14] @ Save reg - mov pc, r9 + .align 5 +__stubs_start: +/* + * Interrupt dispatcher + * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC + */ +vector_IRQ: @ + @ save mode specific registers + @ + ldr r13, .LCsirq + sub lr, lr, #4 + str lr, [r13] @ save lr_IRQ + mrs lr, spsr + str lr, [r13, #4] @ save spsr_IRQ + @ + @ now branch to the relevent MODE handling routine + @ + msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode -wfs_mask_data: .word 0x0e200110 @ WFS - .word 0x0fff0fff - .word 0x0d0d0100 @ LDF [sp]/STF [sp] - .word 0x0d0b0100 @ LDF [fp]/STF [fp] - .word 0x0f0f0f00 + and lr, lr, #15 + ldr lr, [pc, lr, lsl #2] + movs pc, lr @ Changes mode and branches -#include "entry-common.S" +.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 + */ +vector_data: @ + @ save mode specific registers + @ + ldr r13, .LCsabt + sub lr, lr, #8 + str lr, [r13] + mrs lr, spsr + str lr, [r13, #4] + @ + @ now branch to the relevent MODE handling routine + @ + msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode + + and lr, lr, #15 + 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 + */ +vector_prefetch: + @ + @ save mode specific registers + @ + ldr r13, .LCsabt + sub lr, lr, #4 + str lr, [r13] @ save lr_ABT + mrs lr, spsr + str lr, [r13, #4] @ save spsr_ABT + @ + @ now branch to the relevent MODE handling routine + @ + 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 + */ +vector_undefinstr: + @ + @ save mode specific registers + @ + ldr r13, .LCsund + str lr, [r13] @ save lr_UND + mrs lr, spsr + str lr, [r13, #4] @ save spsr_UND + @ + @ now branch to the relevent MODE handling routine + @ + msr spsr_c, #I_BIT | MODE_SVC @ switch to SVC_32 mode + + and lr, lr, #15 + 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 + *----------------------------------------------------------------------------- + * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC + * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg. + * Basically to switch modes, we *HAVE* to clobber one register... brain + * damage alert! I don't think that we can execute any code in here in any + * other mode than FIQ... Ok you can switch to another mode, but you can't + * get out of that mode without clobbering one register. + */ +vector_FIQ: disable_fiq + subs pc, lr, #4 + +/*============================================================================= + * Address exception handler + *----------------------------------------------------------------------------- + * These aren't too critical. + * (they're not supposed to happen, and won't happen in 32-bit data mode). + */ + +vector_addrexcptn: + b vector_addrexcptn + +/* + * We group all the following data together to optimise + * for CPUs with separate I & D caches. + */ + .align 5 + +.LCvswi: .word vector_swi + +.LCsirq: .word __temp_irq +.LCsund: .word __temp_und +.LCsabt: .word __temp_abt + +__stubs_end: + + .equ __real_stubs_start, .LCvectors + 0x200 + +.LCvectors: swi SYS_ERROR0 + b __real_stubs_start + (vector_undefinstr - __stubs_start) + ldr pc, __real_stubs_start + (.LCvswi - __stubs_start) + b __real_stubs_start + (vector_prefetch - __stubs_start) + b __real_stubs_start + (vector_data - __stubs_start) + b __real_stubs_start + (vector_addrexcptn - __stubs_start) + b __real_stubs_start + (vector_IRQ - __stubs_start) + b __real_stubs_start + (vector_FIQ - __stubs_start) + +ENTRY(trap_init) + stmfd sp!, {r4 - r6, lr} + + adr r1, .LCvectors @ set up the vectors + mov r0, #0 + ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr} + stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr} + + add r2, r0, #0x200 + adr r0, __stubs_start @ copy stubs to 0x200 + adr r1, __stubs_end +1: ldr r3, [r0], #4 + str r3, [r2], #4 + cmp r0, r1 + blt 1b + LOADREGS(fd, sp!, {r4 - r6, pc}) .data +/* + * Do not reorder these, and do not insert extra data between... + */ + __temp_irq: .word 0 @ saved lr_irq .word 0 @ saved spsr_irq .word -1 @ old_r0 @@ -800,3 +881,10 @@ __temp_abt: .word 0 @ Saved lr_abt .word 0 @ Saved spsr_abt .word -1 @ old_r0 + + .globl SYMBOL_NAME(cr_alignment) + .globl SYMBOL_NAME(cr_no_alignment) +SYMBOL_NAME(cr_alignment): + .space 4 +SYMBOL_NAME(cr_no_alignment): + .space 4 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.2.17/arch/arm/kernel/entry-common.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/entry-common.S Fri Sep 15 23:28:37 2000 @@ -1,51 +1,54 @@ /*============================================================================ * All exits to user mode from the kernel go through this code. */ - -#include - .globl ret_from_sys_call -ret_from_exception: - adr r0, 1f - ldmia r0, {r0, r1} + .align 5 +fast_syscall_return: + str r0, [sp, #S_R0 + 4] @ returned r0 +slow_syscall_return: + add sp, sp, #4 +ret_from_sys_call: + adr r0, bh_data + ldmia r0, {r0, r4} ldr r0, [r0] - ldr r1, [r1] + ldr r1, [r4] tst r0, r1 blne SYMBOL_NAME(do_bottom_half) -ret_from_intr: ldr r0, [sp, #S_PSR] - tst r0, #3 - beq ret_with_reschedule - b ret_from_all +ret_with_reschedule: + get_current_task r1 @ check for scheduling + ldr r0, [r1, #TSK_NEED_RESCHED] + teq r0, #0 + bne ret_reschedule + ldr r1, [r1, #TSK_SIGPENDING] + teq r1, #0 @ check for signals + bne ret_signal + +ret_from_all: restore_user_regs ret_signal: mov r1, sp adrsvc al, lr, ret_from_all + mov r2, r4 b SYMBOL_NAME(do_signal) -2: bl SYMBOL_NAME(schedule) +ret_reschedule: adrsvc al, lr, ret_with_reschedule + b SYMBOL_NAME(schedule) -ret_from_sys_call: - adr r0, 1f + .globl ret_from_exception +ret_from_exception: + adr r0, bh_data ldmia r0, {r0, r1} ldr r0, [r0] ldr r1, [r1] + mov r4, #0 tst r0, r1 - adrsvc ne, lr, ret_from_intr - bne SYMBOL_NAME(do_bottom_half) - -ret_with_reschedule: - get_current_task r1 - ldr r0, [r1, #TSK_NEED_RESCHED] - teq r0, #0 - bne 2b - ldr r1, [r1, #TSK_SIGPENDING] - teq r1, #0 - bne ret_signal - -ret_from_all: restore_user_regs + blne SYMBOL_NAME(do_bottom_half) + ldr r0, [sp, #S_PSR] + tst r0, #3 @ returning to user mode? + beq ret_with_reschedule + b ret_from_all -1: .word SYMBOL_NAME(bh_mask) - .word SYMBOL_NAME(bh_active) +#include "calls.S" /*============================================================================= * SWI handler @@ -57,84 +60,65 @@ * too worried. */ -#include "calls.S" - + .align 5 vector_swi: save_user_regs - mov fp, #0 mask_pc lr, lr - ldr r6, [lr, #-4]! @ get SWI instruction + mov fp, #0 + ldr r6, [lr, #-4] @ get SWI instruction arm700_bug_check r6, r7 +#ifdef CONFIG_ALIGNMENT_TRAP + ldr r7, .LCswi + ldr r7, [r7] + mcr p15, 0, r7, c1, c0 +#endif enable_irqs r7 - + + str r4, [sp, #-4]! @ new style: (r0 = arg1, r4 = arg5) + 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 bcs 2f - get_current_task r5 - ldr ip, [r5, #TSK_FLAGS] @ check for syscall tracing + get_current_task r7 + ldr ip, [r7, #TSK_FLAGS] @ check for syscall tracing + adr r5, SYMBOL_NAME(sys_call_table) tst ip, #PF_TRACESYS - bne 1f + ldreq pc, [r5, r6, lsl #2] @ call sys routine - adr ip, SYMBOL_NAME(sys_call_table) - str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5) - mov lr, pc - ldr pc, [ip, r6, lsl #2] @ call sys routine - add sp, sp, #4 - str r0, [sp, #S_R0] @ returned r0 - b ret_from_sys_call - -1: ldr r7, [sp, #S_IP] @ save old IP + ldr r7, [sp, #S_IP + 4] @ save old IP mov r0, #0 - str r0, [sp, #S_IP] @ trace entry [IP = 0] + str r0, [sp, #S_IP + 4] @ trace entry [IP = 0] bl SYMBOL_NAME(syscall_trace) - str r7, [sp, #S_IP] - ldmia sp, {r0 - r3} @ have to reload r0 - r3 - adr ip, SYMBOL_NAME(sys_call_table) - str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5) + str r7, [sp, #S_IP + 4] + + ldmib sp, {r0 - r3} @ have to reload r0 - r3 mov lr, pc - ldr pc, [ip, r6, lsl #2] @ call sys routine - add sp, sp, #4 - str r0, [sp, #S_R0] @ returned r0 + ldr pc, [r5, r6, lsl #2] @ call sys routine + str r0, [sp, #S_R0 + 4] @ returned r0 + mov r0, #1 - str r0, [sp, #S_IP] @ trace exit [IP = 1] + str r0, [sp, #S_IP + 4] @ trace exit [IP = 1] bl SYMBOL_NAME(syscall_trace) - str r7, [sp, #S_IP] - b ret_from_sys_call + str r7, [sp, #S_IP + 4] + b slow_syscall_return -2: tst r6, #0x00f00000 @ is it a Unix SWI? +2: add r1, sp, #4 + tst r6, #0x00f00000 @ is it a Unix SWI? bne 3f - cmp r6, #(KSWI_SYS_BASE - KSWI_BASE) - bcc 4f @ not private func - bic r0, r6, #0x000f0000 - mov r1, sp - bl SYMBOL_NAME(arm_syscall) - b ret_from_sys_call - -3: eor r0, r6, #OS_NUMBER<<20 @ Put OS number back - mov r1, sp - bl SYMBOL_NAME(deferred) - ldmfd sp, {r0 - r3} - b ret_from_sys_call - -4: bl SYMBOL_NAME(sys_ni_syscall) - str r0, [sp, #0] @ returned r0 - b ret_from_sys_call + subs r0, r6, #(KSWI_SYS_BASE - KSWI_BASE) + bcs SYMBOL_NAME(arm_syscall) + b SYMBOL_NAME(sys_ni_syscall) @ not private func -@ r0 = syscall number -@ r1 = syscall r0 -@ r5 = syscall r4 -@ ip = syscall table -SYMBOL_NAME(sys_syscall): - mov r6, r0 - eor r6, r6, #OS_NUMBER << 20 - cmp r6, #NR_syscalls @ check range - movgt r0, #-ENOSYS - movgt pc, lr - add sp, sp, #4 @ take of the save of our r4 - ldmib sp, {r0 - r4} @ get our args - str r4, [sp, #-4]! @ Put our arg on the stack - ldr pc, [ip, r6, lsl #2] +3: eor r0, r6, #OS_NUMBER <<20 @ Put OS number back + adrsvc al, lr, slow_syscall_return + b SYMBOL_NAME(deferred) + + .align 5 + +bh_data: .word SYMBOL_NAME(bh_mask) + .word SYMBOL_NAME(bh_active) ENTRY(sys_call_table) #include "calls.S" @@ -142,10 +126,26 @@ /*============================================================================ * Special system call wrappers */ +@ r0 = syscall number +@ r5 = syscall table +SYMBOL_NAME(sys_syscall): + eor r6, r0, #OS_NUMBER << 20 + cmp r6, #NR_syscalls @ check range + addle 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] + mov r0, #-ENOSYS + mov pc, lr + sys_fork_wrapper: add r0, sp, #4 b SYMBOL_NAME(sys_fork) +sys_vfork_wrapper: + add r0, sp, #4 + b SYMBOL_NAME(sys_vfork) + sys_execve_wrapper: add r3, sp, #4 b SYMBOL_NAME(sys_execve) @@ -191,99 +191,6 @@ sys_sigaltstack_wrapper: ldr r2, [sp, #4 + S_SP] b do_sigaltstack - -/* - *============================================================================= - * Low-level interface code - *----------------------------------------------------------------------------- - * Trap initialisation - *----------------------------------------------------------------------------- - * - * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20 - * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes - * some excess cycles). - * - * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000 - * (the kernel). - * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for - * the actual address to jump to. - */ - - .section ".text.init",#alloc,#execinstr - -#if defined(CONFIG_CPU_32) -/* - * these go into 0x00 - */ -.Lbranches: swi SYS_ERROR0 - ldr pc, .Lbranches + 0xe4 - ldr pc, .Lbranches + 0xe8 - ldr pc, .Lbranches + 0xec - ldr pc, .Lbranches + 0xf0 - ldr pc, .Lbranches + 0xf4 - ldr pc, .Lbranches + 0xf8 - ldr pc, .Lbranches + 0xfc -/* - * this is put into 0xe4 and above - */ -.Ljump_addresses: - .word vector_undefinstr @ 0xe4 - .word vector_swi @ 0xe8 - .word vector_prefetch @ 0xec - .word vector_data @ 0xf0 - .word vector_addrexcptn @ 0xf4 - .word vector_IRQ @ 0xf8 - .word _unexp_fiq @ 0xfc -/* - * initialise the trap system - */ -ENTRY(trap_init) - stmfd sp!, {r4 - r7, lr} - initialise_traps_extra - mov r0, #0xe4 - adr r1, .Ljump_addresses - ldmia r1, {r1 - r7} - stmia r0, {r1 - r7} - mov r0, #0 - adr r1, .Lbranches - ldmia r1, {r1 - r7} - stmia r0, {r1 - r7} - LOADREGS(fd, sp!, {r4 - r7, pc}) -#elif defined(CONFIG_CPU_26) -.Ljump_addresses: - swi SYS_ERROR0 - .word vector_undefinstr - 12 - .word vector_swi - 16 - .word vector_prefetch - 20 - .word vector_data - 24 - .word vector_addrexcptn - 28 - .word vector_IRQ - 32 - .word _unexp_fiq - 36 - b . + 8 -/* - * initialise the trap system - */ -ENTRY(trap_init) - stmfd sp!, {r4 - r7, lr} - adr r1, .Ljump_addresses - ldmia r1, {r1 - r7, ip, lr} - orr r2, lr, r2, lsr #2 - orr r3, lr, r3, lsr #2 - orr r4, lr, r4, lsr #2 - orr r5, lr, r5, lsr #2 - orr r6, lr, r6, lsr #2 - orr r7, lr, r7, lsr #2 - orr ip, lr, ip, lsr #2 - mov r0, #0 - stmia r0, {r1 - r7, ip} - ldmfd sp!, {r4 - r7, pc}^ -#endif - - .previous - -/*============================================================================ - * FP support - */ .data diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c --- v2.2.17/arch/arm/kernel/fiq.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/fiq.c Fri Sep 15 23:28:37 2000 @@ -2,6 +2,8 @@ * linux/arch/arm/kernel/fiq.c * * Copyright (C) 1998 Russell King + * Copyright (C) 1998, 1999 Phil Blundell + * * FIQ support written by Philip Blundell , 1998. * * FIQ support re-written by Russell King to be more generic @@ -51,15 +53,12 @@ #ifdef CONFIG_CPU_32 static inline void unprotect_page_0(void) { - __asm__ __volatile__("mcr p15, 0, %0, c3, c0" : - : "r" (DOMAIN_USER_MANAGER | - DOMAIN_KERNEL_CLIENT | - DOMAIN_IO_CLIENT)); + modify_domain(DOMAIN_USER, DOMAIN_MANAGER); } static inline void protect_page_0(void) { - set_fs(get_fs()); + modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } #else @@ -78,7 +77,7 @@ unprotect_page_0(); *(unsigned long *)FIQ_VECTOR = no_fiq_insn; protect_page_0(); - __flush_entry_to_ram(FIQ_VECTOR); + flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + 4); } return 0; @@ -106,28 +105,77 @@ memcpy((void *)FIQ_VECTOR, start, length); protect_page_0(); -#ifdef CONFIG_CPU_32 - processor.u.armv3v4._flush_cache_area(FIQ_VECTOR, FIQ_VECTOR + length, 1); -#endif + flush_icache_range(FIQ_VECTOR, FIQ_VECTOR + length); } +/* + * Taking an interrupt in FIQ mode is death, so both these functions + * disable irqs for the duration. + */ void set_fiq_regs(struct pt_regs *regs) { - /* not yet - - * this is temporary to get the floppy working - * again on RiscPC. It *will* become more - * generic. - */ -#ifdef CONFIG_ARCH_ACORN - extern void floppy_fiqsetup(unsigned long len, unsigned long addr, - unsigned long port); - floppy_fiqsetup(regs->ARM_r9, regs->ARM_r10, regs->ARM_fp); + register unsigned long tmp, tmp2; + __asm__ volatile ( +#ifdef CONFIG_CPU_26 + "mov %0, pc + bic %1, %0, #0x3 + orr %1, %1, #0x0c000001 + teqp %1, #0 @ select FIQ mode + mov r0, r0 + ldmia %2, {r8 - r14} + teqp %0, #0 @ return to SVC mode + mov r0, r0" #endif +#ifdef CONFIG_CPU_32 + "mrs %0, cpsr + bic %1, %0, #0xf + orr %1, %1, #0xc1 + msr cpsr, %1 @ select FIQ mode + mov r0, r0 + ldmia %2, {r8 - r14} + msr cpsr, %0 @ return to SVC mode + mov r0, r0" +#endif + : "=&r" (tmp), "=&r" (tmp2) + : "r" (®s->ARM_r8) + /* These registers aren't modified by the above code in a way + visible to the compiler, but we mark them as clobbers anyway + so that GCC won't put any of the input or output operands in + them. */ + : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); } void get_fiq_regs(struct pt_regs *regs) { - /* not yet */ + register unsigned long tmp, tmp2; + __asm__ volatile ( +#ifdef CONFIG_CPU_26 + "mov %0, pc + bic %1, %0, #0x3 + orr %1, %1, #0x0c000001 + teqp %1, #0 @ select FIQ mode + mov r0, r0 + stmia %2, {r8 - r14} + teqp %0, #0 @ return to SVC mode + mov r0, r0" +#endif +#ifdef CONFIG_CPU_32 + "mrs %0, cpsr + bic %1, %0, #0xf + orr %1, %1, #0xc1 + msr cpsr, %1 @ select FIQ mode + mov r0, r0 + stmia %2, {r8 - r14} + msr cpsr, %0 @ return to SVC mode + mov r0, r0" +#endif + : "=&r" (tmp), "=&r" (tmp2) + : "r" (®s->ARM_r8) + /* These registers aren't modified by the above code in a way + visible to the compiler, but we mark them as clobbers anyway + so that GCC won't put any of the input or output operands in + them. */ + : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); } int claim_fiq(struct fiq_handler *f) @@ -165,7 +213,7 @@ while (current_fiq->fiq_op(current_fiq->dev_id, 0)); } -__initfunc(void init_FIQ(void)) +void __init init_FIQ(void) { no_fiq_insn = *(unsigned long *)FIQ_VECTOR; set_fs(get_fs()); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.2.17/arch/arm/kernel/head-armv.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/head-armv.S Fri Sep 15 23:28:37 2000 @@ -1,157 +1,238 @@ /* - * linux/arch/arm/kernel/head32.S + * linux/arch/arm/kernel/head-armv.S * - * Copyright (C) 1994-1998 Russell King + * Copyright (C) 1994-1999 Russell King * - * Kernel 32 bit startup code for ARM6 / ARM7 / StrongARM + * 32-bit kernel startup code for all architectures */ #include #include -#ifndef CONFIG_ARCH_VNC +#include + #if (TEXTADDR & 0xffff) != 0x8000 #error TEXTADDR must start at 0xXXXX8000 #endif -#else - .text - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 - mov r0, r0 + +#define SWAPPER_PGDIR_OFFSET 0x4000 + + .globl SYMBOL_NAME(swapper_pg_dir) + .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x8000 + SWAPPER_PGDIR_OFFSET + + .section ".text.init",#alloc,#execinstr +ENTRY(stext) +ENTRY(_stext) + +#ifdef CONFIG_ARCH_NETWINDER +/* + * Compatability cruft for old NetWinder NeTTroms. This + * code is currently scheduled for destruction in 2.5.xx + */ + .rept 8 mov r0, r0 + .endr + + adr r2, 1f + ldmdb r2, {r7, r8} + and r3, r2, #0xc000 + teq r3, #0x8000 + beq __entry + bic r3, r2, #0xc000 + orr r3, r3, #0x8000 + mov r0, r3 + mov r4, #64 + sub r5, r8, r7 + b 1f + + .word _stext + .word __bss_start + +1: + .rept 4 + ldmia r2!, {r6, r7, r8, r9} + stmia r3!, {r6, r7, r8, r9} + .endr + subs r4, r4, #64 + bcs 1b + movs r4, r5 + mov r5, #0 + movne pc, r0 + mov r0, #0 mov r1, #5 #endif -#define DEBUG +/* + * Entry point. Entry *must* be called with r0 == 0, with the MMU off. + * 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. + */ +__entry: teq r0, #0 + movne r0, #'i' + bne __error + bl __lookup_processor_type + teq r10, #0 @ invalid processor? + moveq r0, #'p' + beq __error + bl __lookup_architecture_type + teq r7, #0 @ invalid architecture? + moveq r0, #'a' + beq __error + bl __create_page_tables + adr lr, __ret + add pc, r10, #12 @ flush caches (returns ctrl reg) - .globl SYMBOL_NAME(swapper_pg_dir) - .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000 +__switch_data: .long __mmap_switched + .long SYMBOL_NAME(__bss_start) + .long SYMBOL_NAME(_end) + .long SYMBOL_NAME(processor_id) + .long SYMBOL_NAME(__machine_arch_type) + .long SYMBOL_NAME(cr_alignment) + .long SYMBOL_NAME(init_task_union)+8192 + +__ret: ldr lr, __switch_data + mcr p15, 0, r0, c1, c0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov pc, lr + + /* + * This code follows on after the page + * table switch and jump above. + * + * r0 = processor control register + * r1 = machine ID + * r9 = processor ID + */ + .align 5 +__mmap_switched: + adr r3, __switch_data + 4 + ldmia r3, {r4, r5, r6, r7, r8, sp} @ Setup stack + + mov fp, #0 @ Clear BSS +1: cmp r4, r5 + strcc fp, [r4],#4 + bcc 1b + + 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) - .text -/* - * Entry point and restart point. Entry *must* be called with r0 == 0, - * MMU off. Note! These should be unique!!! Please read Documentation/ARM-README - * for more information. - * - * r1 = 0 -> DEC EBSA-110 - * r1 = 1 -> Acorn RiscPC - * r1 = 2 -> ebsit - * r1 = 3 -> nexuspci - * r1 = 4 -> DEC EBSA-285 - * r1 = 5 -> Corel Netwinder - * r1 = 6 -> CATS - * r1 = 7 -> tbox - */ -ENTRY(stext) -ENTRY(_stext) -__entry: teq r0, #0 @ check for illegal entry... - bne .Lerror @ loop indefinitely - cmp r1, #8 @ Unknown machine architecture - bge .Lerror -/* First thing to do is to get the page tables set up so that we can call the kernel - * in the correct place. This is relocatable code... - * - Read processor ID register (CP#15, CR0). - */ - mrc p15, 0, r9, c0, c0 @ get Processor ID -/* Values are: - * XX01XXXX = ARMv4 architecture (StrongARM) - * XX00XXXX = ARMv3 architecture - * 4156061X = ARM 610 - */ - adr r10, .LCProcTypes -1: ldmia r10!, {r5, r6, r8} @ Get Set, Mask, MMU Flags - teq r5, #0 @ End of list? - beq .Lerror - eor r5, r5, r9 - tst r5, r6 - addne r10, r10, #8 - bne 1b - adr r4, .LCMachTypes - add r4, r4, r1, lsl #4 - ldmia r4, {r4, r5, r6} /* - * r4 = page dir in physical ram + * Setup the initial page tables. We only setup the barest + * amount which are required to get the kernel running, which + * generally means mapping in the kernel code. + * + * We only map in 4MB of RAM, which should be sufficient in + * all cases. + * * r5 = physical address of start of RAM - * r6 = I/O address + * 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 -1: str r3, [r0], #4 @ Clear page table + add r2, r0, #0x4000 @ Clear page table +1: str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 teq r0, r2 bne 1b -/* - * Add enough entries to allow the kernel to be called. - * It will sort out the real mapping in paging_init. - * We map in 2MB of memory into (TEXTADDR-0x8000) + 2MB - */ - add r0, r4, #(TEXTADDR - 0x8000) >> 18 - mov r3, #0x0000000c @ SECT_CACHEABLE | SECT_BUFFERABLE + /* + * 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() + */ + 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 -#ifdef DEBUG -/* Map in IO space - * This allows debug messages to be output via a serial - * before/while paging_init. - */ - add r0, r4, #0x3800 + str r3, [r0], #4 + add r3, r3, #1 << 20 + str r3, [r0], #4 +#ifdef CONFIG_DEBUG_LL + /* + * Map in IO space for serial debugging. + * This allows debug messages to be output + * 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 bne 1b -#ifdef CONFIG_ARCH_VNC - add r0, r4, #0x3f00 - add r0, r0, #0x00f8 +#ifdef CONFIG_ARCH_NETWINDER + teq r1, #5 + bne 1f + add r0, r4, #0x3fc0 mov r3, #0x7c000000 orr r3, r3, r8 str r3, [r0], #4 add r3, r3, #1 << 20 str r3, [r0], #4 +1: #endif #endif #ifdef CONFIG_ARCH_RPC -/* Map in screen at 0x02000000 & SCREEN2_BASE - * Similar reasons here - for debug, and when things go - * wrong to a certain extent. This is of limited use to - * non-Acorn RiscPC architectures though. - */ + /* + * Map in screen at 0x02000000 & SCREEN2_BASE + * Similar reasons here - for debug. This is + * only for Acorn RiscPC architectures. + */ teq r5, #0 - addne r0, r4, #0x80 @ 02000000 + addne r0, r4, #0x80 @ 02000000 movne r3, #0x02000000 orrne r3, r3, r8 strne r3, [r0] - addne r0, r4, #0x3600 @ d8000000 + addne r0, r4, #0x3600 @ d8000000 strne r3, [r0] #endif -@ -@ The following should work on both v3 and v4 implementations -@ - mov lr, pc - mov pc, r10 @ Call processor flush (returns ctrl reg) - adr r5, __entry - sub r10, r10, r5 @ Make r10 PIC - ldr lr, .Lbranch - mcr p15, 0, r0, c1, c0 @ Enable MMU & caches. In 3 instructions - @ we lose this page! mov pc, lr -.Lerror: + + +/* + * Exception handling. Something went wrong and we can't + * proceed. We ought to tell the user, but since we + * don't have any guarantee that we're even running on + * the right architecture, we do virtually nothing. + * r0 = ascii error character + * + * Generally, only serious errors cause this. + */ +__error: #ifdef CONFIG_ARCH_RPC -/* Turn the screen red on a error - RiscPC only. +/* + * Turn the screen red on a error - RiscPC only. */ -1: mov r0, #0x02000000 + mov r0, #0x02000000 mov r3, #0x11 orr r3, r3, r3, lsl #8 orr r3, r3, r3, lsl #16 @@ -160,160 +241,157 @@ str r3, [r0], #4 str r3, [r0], #4 #endif +1: mov r0, r0 b 1b -.Lbranch: .long .Lalready_done_mmap @ Real address of routine - @ DEC EBSA110 (pg dir phys, phys ram start, phys i/o) -.LCMachTypes: .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0xe0000000 @ I/O address + +/* + * Read processor ID register (CP#15, CR0), and determine + * processor type. + * + * Returns: + * r5, r6, r7 corrupted + * r8 = page table flags + * r9 = processor ID + * r10 = pointer to processor structure + */ +__lookup_processor_type: + adr r5, 2f + ldmia r5, {r7, r9, r10} + sub r5, r5, r9 + add r7, r7, r5 + add r10, r10, r5 + mrc p15, 0, r9, c0, c0 @ get processor id +1: ldmia r10, {r5, r6, r8} @ value, mask, mmuflags + eor r5, r5, r9 + tst r5, r6 + moveq pc, lr + add r10, r10, #36 @ sizeof(proc_info_list) + cmp r10, r7 + blt 1b + mov r10, #0 + mov pc, lr + +2: .long __proc_info_end + .long 2b + .long __proc_info_begin + +/* + * Lookup machine architecture + * r1 = machine architecture number + * Returns: + * r4 = unused word + * r5 = physical start address of RAM + * r6 = physical address of IO + * r7 = byte offset into page tables for IO + */ +__lookup_architecture_type: + cmp r1, #(__arch_types_end - __arch_types_start) / 16 + bge 1f + adr r4, __arch_types_start + add r4, r4, r1, lsl #4 + ldmia r4, {r4, r5, r6, r7} + mov r7, r7, lsr #18 + mov pc, lr +1: mov r7, #0 + mov pc, lr + +/* + * Machine parameters. Each machine requires 4 words, which are: + * + * word0: unused + * word1: physical start address of RAM + * word2: physical start address of IO + * word3: virtual start address of IO + * + * The IO mappings entered here are used to set up mappings + * required for debugging information to be shown to the user. + * paging_init() does the real page table initialisation. + */ + @ 0x00 - DEC EBSA110 +__arch_types_start: + .long 0 .long 0 + .long 0xe0000000 + .long 0xe0000000 - @ Acorn RiscPC - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x10000000 + @ 0x01 - Acorn RiscPC + .long 0 .long 0x10000000 .long 0x03000000 - .long 0 + .long 0xe0000000 - @ EBSIT ??? - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + @ 0x02 - Unused .long 0 - .long 0xe0000000 .long 0 + .long 0xe0000000 + .long 0xe0000000 - @ NexusPCI - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x40000000 + @ 0x03 - NexusPCI + .long 0 .long 0x40000000 .long 0x10000000 - .long 0 + .long 0xe0000000 - @ DEC EBSA285 - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0x24000000 @ I/O base address (0x42000000 -> 0xFE000000) + @ 0x04 - DEC EBSA285 .long 0 - - @ Corel VNC - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) .long 0 + .long 0x42000000 + .long 0xfe000000 - @ CATS - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) - .long 0 @ Address of RAM - .long 0x24000000 @ I/O base address (0x42000000 -> 0xfe000000) + @ 0x05 - Rebel.com NetWinder .long 0 - - @ tbox - .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x80000000 - .long 0x80000000 @ Address of RAM - .long 0x00400000 @ Uart .long 0 + .long 0x42000000 + .long 0xfe000000 -.LCProcTypes: @ ARM6 / 610 - .long 0x41560600 - .long 0xffffff00 - .long 0x00000c12 - b .Larmv3_flush_early @ arm v3 flush & ctrl early setup - mov pc, lr - - @ ARM7 - .long 0x41007000 - .long 0xfffff000 - .long 0x00000c12 - b .Larmv3_flush_late @ arm v3 flush & ctrl late setup - mov pc, lr - - @ ARM710 - .long 0x41007000 - .long 0xfff8f000 @ arm710 processors are weird - .long 0x00000c12 - b .Larmv3_flush_late @ arm v3 flush & ctrl late setup - mov pc, lr + @ 0x06 - CATS + .long 0 + .long 0 + .long 0x42000000 + .long 0xfe000000 - @ StrongARM - .long 0x4401a100 - .long 0xfffffff0 - .long 0x00000c02 - b .Larmv4_flush_early - b .Lsa_fastclock + @ 0x07 - tbox + .long 0 + .long 0x80000000 + .long 0x00400000 @ Uart + .long 0xe0000000 + @ 0x08 - DEC EBSA285 as co-processor .long 0 - .align + .long 0 + .long 0x42000000 @ Physical I/O base address + .long 0x7cf00000 @ Virtual I/O base address -.Larmv3_flush_early: - mov r0, #0 - mcr p15, 0, r0, c7, c0 @ flush caches on v3 - mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 - mcr p15, 0, r4, c2, c0 @ load page table pointer - mov r0, #0x1f @ Domains 0, 1 = client - mcr p15, 0, r0, c3, c0 @ load domain access register - mov r0, #0x3d @ ....S..DPWC.M - orr r0, r0, #0x100 - mov pc, lr + @ 0x09 - CL-PS7110 -.Larmv3_flush_late: - mov r0, #0 - mcr p15, 0, r0, c7, c0 @ flush caches on v3 - mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 - mcr p15, 0, r4, c2, c0 @ load page table pointer - mov r0, #0x1f @ Domains 0, 1 = client - mcr p15, 0, r0, c3, c0 @ load domain access register - mov r0, #0x7d @ ....S.LDPWC.M - orr r0, r0, #0x100 - mov pc, lr + @ 0x0a - Acorn Archimedes -.Larmv4_flush_early: - mov r0, #0 - mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4 - mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 - mcr p15, 0, r0, c8, c7 @ flush I,D TLBs on v4 - mcr p15, 0, r4, c2, c0 @ load page table pointer - mov r0, #0x1f @ Domains 0, 1 = client - mcr p15, 0, r0, c3, c0 @ load domain access register - mrc p15, 0, r0, c1, c0 @ get control register v4 - bic r0, r0, #0x0e00 - bic r0, r0, #0x0002 - orr r0, r0, #0x003d @ I...S..DPWC.M - orr r0, r0, #0x1100 @ v4 supports separate I cache - mov pc, lr + @ 0x0b - Acorn A5000 - .section ".text.init",#alloc,#execinstr + @ 0x0c - Etoile -.Lsa_fastclock: mcr p15, 0, r4, c15, c1, 2 @ Enable clock switching - mov pc, lr + @ 0x0d - LaCie_NAS -.LC0: .long SYMBOL_NAME(__entry) - .long SYMBOL_NAME(machine_type) - .long SYMBOL_NAME(__bss_start) - .long SYMBOL_NAME(processor_id) - .long SYMBOL_NAME(_end) - .long SYMBOL_NAME(init_task_union)+8192 - .align + @ 0x0e - CL-PS7500 -.Lalready_done_mmap: - adr r4, .LC0 - ldmia r4, {r3, r4, r5, r6, r8, sp} @ Setup stack - add r10, r10, r3 @ Add base back in - mov fp, #0 -1: cmp r5, r8 @ Clear BSS - strcc fp, [r5],#4 - bcc 1b + @ 0x0f - Shark - str r1, [r4] @ Save machine type - str r9, [r6] @ Save processor ID - mov lr, pc - add pc, r10, #4 @ Call post-processor init - mov fp, #0 - b SYMBOL_NAME(start_kernel) + @ 0x10 - SA1100 + + /* + * Don't add anything here unless you have an + * architecture number allocated - see + * Documentation/arm/README + */ +__arch_types_end: - .text -#ifdef DEBUG +#ifdef CONFIG_DEBUG_LL /* * Some debugging routines (useful if you've got MM problems and - * printk isn't working). For DEBUGGING ONLY!!! + * printk isn't working). For DEBUGGING ONLY!!! Do not leave + * references to these in a production kernel! */ #if defined(CONFIG_ARCH_RPC) .macro addruart,rx @@ -362,64 +440,71 @@ beq 1001b .endm -#elif defined(CONFIG_ARCH_EBSA285) +#elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE) +#ifndef CONFIG_DEBUG_DC21285_PORT + /* For NetWinder debugging */ .macro addruart,rx - mov \rx, #0xfe000000 + mov \rx, #0xff000000 + orr \rx, \rx, #0x000003f8 .endm .macro senduart,rd,rx - str \rd, [\rx, #0x160] @ UARTDR + strb \rd, [\rx] .endm .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #0x178] @ UARTFLG - tst \rd, #1 << 3 - bne 1001b +1002: ldrb \rd, [\rx, #0x5] + and \rd, \rd, #0x60 + teq \rd, #0x60 + bne 1002b .endm .macro waituart,rd,rx +1001: ldrb \rd, [\rx, #0x6] + tst \rd, #0x10 + beq 1001b .endm +#else + /* For EBSA285 debugging */ + .equ dc21285_high, ARMCSR_BASE & 0xff000000 + .equ dc21285_low, ARMCSR_BASE & 0x00ffffff -#elif defined(CONFIG_ARCH_NEXUSPCI) .macro addruart,rx - ldr \rx, =0xfff00000 + mov \rx, #dc21285_high + .if dc21285_low + orr \rx, \rx, #dc21285_low + .endif .endm .macro senduart,rd,rx - str \rd, [\rx, #0xc] + str \rd, [\rx, #0x160] @ UARTDR .endm .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #0x4] - tst \rd, #1 << 0 +1001: ldr \rd, [\rx, #0x178] @ UARTFLG + tst \rd, #1 << 3 bne 1001b .endm .macro waituart,rd,rx .endm - -#elif defined(CONFIG_ARCH_VNC) +#endif +#elif defined(CONFIG_ARCH_NEXUSPCI) .macro addruart,rx - mov \rx, #0xff000000 - orr \rx, \rx, #0x00e00000 - orr \rx, \rx, #0x000003f8 + ldr \rx, =0xfff00000 .endm .macro senduart,rd,rx - strb \rd, [\rx] + str \rd, [\rx, #0xc] .endm .macro busyuart,rd,rx -1002: ldrb \rd, [\rx, #0x5] - and \rd, \rd, #0x60 - teq \rd, #0x60 - bne 1002b +1001: ldr \rd, [\rx, #0x4] + tst \rd, #1 << 0 + bne 1001b .endm .macro waituart,rd,rx -1001: ldrb \rd, [\rx, #0x6] - tst \rd, #0x10 - beq 1001b .endm #else #error Unknown architecture @@ -475,8 +560,6 @@ mov r1, r0 mov r0, #0 b 1b - - .ltorg .bss hexbuf: .space 16 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/hw-ebsa285.c linux/arch/arm/kernel/hw-ebsa285.c --- v2.2.17/arch/arm/kernel/hw-ebsa285.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/hw-ebsa285.c Thu Jan 1 01:00:00 1970 @@ -1,161 +0,0 @@ -/* - * arch/arm/kernel/hw-ebsa286.c - * - * EBSA285 hardware specific functions - * - * Copyright (C) 1998 Russell King, Phil Blundel - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -extern int setup_arm_irq(int, struct irqaction *); - -extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set); -extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr); -extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq); - -static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 }; -static int irqmap_cats[] __initdata = { 18, 8, 9, 11 }; - -__initfunc(static int ebsa_irqval(struct pci_dev *dev)) -{ - unsigned char pin; - - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_PIN, - &pin); - - return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; -} - -__initfunc(static int cats_irqval(struct pci_dev *dev)) -{ - if (dev->irq >= 128) - return 32 + (dev->irq & 0x1f); - - switch (dev->irq) { - case 1: - case 2: - case 3: - case 4: - return irqmap_cats[dev->irq - 1]; - case 0: - return 0; - } - - printk("PCI: device %02x:%02x has unknown irq line %x\n", - dev->bus->number, dev->devfn, dev->irq); - return 0; -} - -__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev)) -{ - char cmd; - - /* sort out the irq mapping for this device */ - switch (machine_type) { - case MACH_TYPE_EBSA285: - dev->irq = ebsa_irqval(dev); - break; - case MACH_TYPE_CATS: - dev->irq = cats_irqval(dev); - break; - } - - /* Turn on bus mastering - boot loader doesn't - * - perhaps it should! - dag - */ - pci_read_config_byte(dev, PCI_COMMAND, &cmd); - pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); -} - -static void irq_pci_err(int irq, void *dev_id, struct pt_regs *regs) -{ - const char *err = "unknown"; - unsigned long cmd = *(unsigned long *)0xfe000004 & 0xffff; - unsigned long ctrl = *(unsigned long *)0xfe00013c & 0xffffde07; - static unsigned long next_warn[7]; - int idx = 6; - - switch(irq) { - case IRQ_PCIPARITY: - *(unsigned long *)0xfe000004 = cmd | 1 << 31; - idx = 0; - err = "parity"; - break; - - case IRQ_PCITARGETABORT: - *(unsigned long *)0xfe000004 = cmd | 1 << 28; - idx = 1; - err = "target abort"; - break; - - case IRQ_PCIMASTERABORT: - *(unsigned long *)0xfe000004 = cmd | 1 << 29; - idx = 2; - err = "master abort"; - break; - - case IRQ_PCIDATAPARITY: - *(unsigned long *)0xfe000004 = cmd | 1 << 24; - idx = 3; - err = "data parity"; - break; - - case IRQ_DISCARDTIMER: - *(unsigned long *)0xfe00013c = ctrl | 1 << 8; - idx = 4; - err = "discard timer"; - break; - - case IRQ_SERR: - *(unsigned long *)0xfe00013c = ctrl | 1 << 3; - idx = 5; - err = "system"; - break; - } - if (time_after_eq(jiffies, next_warn[idx])) { - next_warn[idx] = jiffies + 3 * HZ / 100; - printk(KERN_ERR "PCI %s error detected\n", err); - } -} - -static struct irqaction irq_pci_error = { - irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL -}; - -__initfunc(void pcibios_init_ebsa285(void)) -{ - setup_arm_irq(IRQ_PCIPARITY, &irq_pci_error); - setup_arm_irq(IRQ_PCITARGETABORT, &irq_pci_error); - setup_arm_irq(IRQ_PCIMASTERABORT, &irq_pci_error); - setup_arm_irq(IRQ_PCIDATAPARITY, &irq_pci_error); - setup_arm_irq(IRQ_DISCARDTIMER, &irq_pci_error); - setup_arm_irq(IRQ_SERR, &irq_pci_error); - - /* - * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is slightly - * bizarre but apparently necessary to avoid problems with some - * video cards. - * - * We should really only do this if the central function is enabled. - */ - *(unsigned long *)0xfe000010 = 0; - *(unsigned long *)0xfe000018 = 0xe0000000; - *(unsigned long *)0xfe0000f8 = 0; - *(unsigned long *)0xfe0000fc = 0; - *(unsigned long *)0xfe000100 = 0x01fc0000; - *(unsigned long *)0xfe000104 = 0; - *(unsigned long *)0xfe000108 = 0x80000000; - *(unsigned long *)0xfe000004 = 0x17; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c --- v2.2.17/arch/arm/kernel/hw-footbridge.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/kernel/hw-footbridge.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,951 @@ +/* + * arch/arm/kernel/hw-footbridge.c + * + * Footbridge-dependent machine fixup + * + * Copyright (C) 1998, 1999 Russell King, Phil Blundell + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define IRDA_IO_BASE 0x180 +#define ETHER10_IO_BASE 0x301 +#define GP1_IO_BASE 0x338 +#define GP2_IO_BASE 0x33a +#define DEC21143_IO_BASE 0x401 +#define DEC21143_MEM_BASE 0x00800000 +#define CYBER2000_MEM_BASE 0x01000000 + +int have_isa_bridge; + +extern int setup_arm_irq(int, struct irqaction *); +extern void pci_set_cmd(struct pci_dev *dev, unsigned short clear, unsigned short set); +extern void pci_set_base_addr(struct pci_dev *dev, int idx, unsigned int addr); +extern void pci_set_irq_line(struct pci_dev *dev, unsigned int irq); +extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); + +#ifdef CONFIG_PCI + +static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; + +__initfunc(static int ebsa_irqval(struct pci_dev *dev)) +{ + unsigned char pin; + + pcibios_read_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_PIN, + &pin); + + return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; +} + +#ifdef CONFIG_CATS +static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; + +__initfunc(static int cats_irqval(struct pci_dev *dev)) +{ + if (dev->irq >= 128) + return 16 + (dev->irq & 0x1f); + + switch (dev->irq) { + case 1: + case 2: + case 3: + case 4: + return irqmap_cats[dev->irq - 1]; + case 0: + return 0; + } + + printk("PCI: device %02x:%02x has unknown irq line %x\n", + dev->bus->number, dev->devfn, dev->irq); + return 0; +} +#endif + +__initfunc(void pcibios_fixup_ebsa285(struct pci_dev *dev)) +{ + /* Latency timer of 32 */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); + + /* 32-byte cache line size */ + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); + + /* Set SysErr enable, Parity enable */ + pci_set_cmd(dev, 0, PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | PCI_COMMAND_PARITY); + + /* If this device is an ISA bridge, set the + * have_isa_bridge flag. We will then go looking + * for things like keyboard, etc + */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA || + (dev->class >> 8) == PCI_CLASS_BRIDGE_EISA) + have_isa_bridge = !0; + + /* sort out the irq mapping for this device */ + switch (machine_arch_type) { + case MACH_TYPE_EBSA285: + dev->irq = ebsa_irqval(dev); + /* Turn on bus mastering - boot loader doesn't + * - perhaps it should! - dag + */ + pci_set_cmd(dev, 0, PCI_COMMAND_MASTER); + break; + +#ifdef CONFIG_CATS + case MACH_TYPE_CATS: + dev->irq = cats_irqval(dev); + /* Turn on bus mastering - boot loader doesn't + * - perhaps it should! - dag + */ + pci_set_cmd(dev, 0, PCI_COMMAND_MASTER); + break; +#endif +#ifdef CONFIG_ARCH_NETWINDER + case MACH_TYPE_NETWINDER: + /* disable ROM */ + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); + +#define DEV(v,d) ((v)<<16|(d)) + switch (DEV(dev->vendor, dev->device)) { + /* Ether 100 */ + case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): + pci_set_base_addr(dev, 0, DEC21143_IO_BASE); + pci_set_base_addr(dev, 1, DEC21143_MEM_BASE); + pci_set_cmd(dev, 0, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + /* Put the chip to sleep in case the driver isn't loaded */ + pci_write_config_dword(dev, 0x40, 0x80000000); + dev->irq = IRQ_NETWINDER_ETHER100; + break; + + /* Ether 10 */ + case DEV(PCI_VENDOR_ID_WINBOND2,0x5a5a): + pci_set_base_addr(dev, 0, ETHER10_IO_BASE); + pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO); + dev->irq = IRQ_NETWINDER_ETHER10; + break; + + /* ISA bridge */ + case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_83C553): + pci_set_base_addr(dev, 0, 0); + pci_set_cmd(dev, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY, PCI_COMMAND_IO); + /* + * Enable all memory requests from ISA to be channeled to PCI + */ + pci_write_config_byte(dev, 0x48, 255); + /* + * Disable ping-pong (as per errata) + */ + pci_write_config_byte(dev, 0x42, 0); + /* + * Enable PCI packet retry + */ + pci_write_config_byte(dev, 0x40, 0x22); + /* + * Do not use PCI CPU park enable, park on + * last master, disable GAT bit + */ + pci_write_config_byte(dev, 0x83, 0x02); + /* + * Default rotating priorities + */ + pci_write_config_byte(dev, 0x80, 0xe0); + /* + * Rotate bank 4 + */ + pci_write_config_byte(dev, 0x81, 0x01); + break; + + /* IDE */ + case DEV(PCI_VENDOR_ID_WINBOND,PCI_DEVICE_ID_WINBOND_82C105): + pci_set_base_addr(dev, 0, 0x1f1); + pci_set_base_addr(dev, 1, 0x3f5); + pci_set_base_addr(dev, 2, 0x171); + pci_set_base_addr(dev, 3, 0x375); + pci_set_base_addr(dev, 4, 0xe801); + pci_set_cmd(dev, PCI_COMMAND_MEMORY, PCI_COMMAND_MASTER | PCI_COMMAND_IO); + dev->irq = IRQ_ISA_HARDDISK1; + break; + + /* VGA */ + case DEV(PCI_VENDOR_ID_INTERG,0x2000): + pci_set_base_addr(dev, 0, CYBER2000_MEM_BASE); + pci_set_cmd(dev, PCI_COMMAND_MASTER, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + dev->irq = IRQ_NETWINDER_VGA; + break; + } +#endif + } +} + +static inline void +report_pci_dev_error(void) +{ + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + unsigned short status; + + pci_read_config_word(dev, PCI_STATUS, &status); + if (status & 0xf900) { + printk(KERN_DEBUG "PCI: [%04X:%04X] status = %X\n", + dev->vendor, dev->device, status); + + pci_write_config_word(dev, PCI_STATUS, status & 0xf900); + } + } +} +#else +#define report_pci_dev_error() +#endif + +/* + * Warn on PCI errors. Please report any occurances! + */ +static void +irq_pci_err(int irq, void *dev_id, struct pt_regs *regs) +{ + static unsigned long next_warn; + unsigned long cmd = *CSR_PCICMD & 0x0000ffff; + unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07; + unsigned long irqstatus = *CSR_IRQ_RAWSTATUS; + int warn = time_after_eq(jiffies, next_warn); + + ctrl |= SA110_CNTL_DISCARDTIMER; + + if (warn) { + next_warn = jiffies + 3 * HZ / 100; + printk(KERN_DEBUG "PCI: "); + } + + if (irqstatus & (1 << 31)) { + if (warn) + printk("parity error "); + cmd |= 1 << 31; + } + + if (irqstatus & (1 << 30)) { + if (warn) + printk("target abort "); + cmd |= 1 << 28; + } + + if (irqstatus & (1 << 29)) { + if (warn) + printk("master abort "); + cmd |= 1 << 29; + } + + if (irqstatus & (1 << 28)) { + if (warn) + printk("data parity error "); + cmd |= 1 << 24; + } + + if (irqstatus & (1 << 27)) { + if (warn) + printk("discard timer expired "); + ctrl &= ~SA110_CNTL_DISCARDTIMER; + } + + if (irqstatus & (1 << 23)) { + if (warn) + printk("system error "); + ctrl |= SA110_CNTL_RXSERR; + } + + if (warn) + printk("pc=[<%08lX>]\n", instruction_pointer(regs)); + + report_pci_dev_error(); + + *CSR_PCICMD = cmd; + *CSR_SA110_CNTL = ctrl; +} + +static struct irqaction irq_pci_error = { + irq_pci_err, SA_INTERRUPT, 0, "PCI error", NULL, NULL +}; + +__initfunc(void pcibios_init_ebsa285(void)) +{ + setup_arm_irq(IRQ_PCI_ERR, &irq_pci_error); +} + +/* + * Netwinder stuff + */ +#ifdef CONFIG_ARCH_NETWINDER + +/* + * Winbond WB83977F accessibility stuff + */ +static inline void wb977_open(void) +{ + outb(0x87, 0x370); + outb(0x87, 0x370); +} + +static inline void wb977_close(void) +{ + outb(0xaa, 0x370); +} + +static inline void wb977_wb(int reg, int val) +{ + outb(reg, 0x370); + outb(val, 0x371); +} + +static inline void wb977_ww(int reg, int val) +{ + outb(reg, 0x370); + outb(val >> 8, 0x371); + outb(reg + 1, 0x370); + outb(val, 0x371); +} + +#define wb977_device_select(dev) wb977_wb(0x07, dev) +#define wb977_device_disable() wb977_wb(0x30, 0x00) +#define wb977_device_enable() wb977_wb(0x30, 0x01) + +/* + * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE + */ +spinlock_t __netwinder_data gpio_lock = SPIN_LOCK_UNLOCKED; + +static unsigned int __netwinder_data current_gpio_op = 0; +static unsigned int __netwinder_data current_gpio_io = 0; +static unsigned int __netwinder_data current_cpld = 0; + +void __netwinder_text gpio_modify_op(int mask, int set) +{ + unsigned int new_gpio, changed; + + new_gpio = (current_gpio_op & ~mask) | set; + changed = new_gpio ^ current_gpio_op; + current_gpio_op = new_gpio; + + if (changed & 0xff) + outb(new_gpio, GP1_IO_BASE); + if (changed & 0xff00) + outb(new_gpio >> 8, GP2_IO_BASE); +} + +static inline void __gpio_modify_io(int mask, int in) +{ + unsigned int new_gpio, changed; + int port; + + new_gpio = (current_gpio_io & ~mask) | in; + changed = new_gpio ^ current_gpio_io; + current_gpio_io = new_gpio; + + changed >>= 1; + new_gpio >>= 1; + + wb977_device_select(7); + + for (port = 0xe1; changed && port < 0xe8; changed >>= 1) { + wb977_wb(port, new_gpio & 1); + + port += 1; + new_gpio >>= 1; + } + + wb977_device_select(8); + + for (port = 0xe8; changed && port < 0xec; changed >>= 1) { + wb977_wb(port, new_gpio & 1); + + port += 1; + new_gpio >>= 1; + } +} + +void __netwinder_text gpio_modify_io(int mask, int in) +{ + /* Open up the SuperIO chip */ + wb977_open(); + + __gpio_modify_io(mask, in); + + /* Close up the EFER gate */ + wb977_close(); +} + +int __netwinder_text gpio_read(void) +{ + return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8; +} + +/* + * Initialise the Winbond W83977F global registers + */ +static inline void wb977_init_global(void) +{ + /* + * Enable R/W config registers + */ + wb977_wb(0x26, 0x40); + + /* + * Power down FDC (not used) + */ + wb977_wb(0x22, 0xfe); + + /* + * GP12, GP11, CIRRX, IRRXH, GP10 + */ + wb977_wb(0x2a, 0xc1); + + /* + * GP23, GP22, GP21, GP20, GP13 + */ + wb977_wb(0x2b, 0x6b); + + /* + * GP17, GP16, GP15, GP14 + */ + wb977_wb(0x2c, 0x55); +} + +/* + * Initialise the Winbond W83977F printer port + */ +static inline void wb977_init_printer(void) +{ + wb977_device_select(1); + + /* + * mode 1 == EPP + */ + wb977_wb(0xf0, 0x01); +} + +/* + * Initialise the Winbond W83977F keyboard controller + */ +static inline void wb977_init_keyboard(void) +{ + wb977_device_select(5); + + /* + * Keyboard controller address + */ + wb977_ww(0x60, 0x0060); + wb977_ww(0x62, 0x0064); + + /* + * Keyboard IRQ 1, active high, edge trigger + */ + wb977_wb(0x70, 1); + wb977_wb(0x71, 0x02); + + /* + * Mouse IRQ 5, active high, edge trigger + */ + wb977_wb(0x72, 5); + wb977_wb(0x73, 0x02); + + /* + * KBC 8MHz + */ + wb977_wb(0xf0, 0x40); + + /* + * Enable device + */ + wb977_device_enable(); +} + +/* + * Initialise the Winbond W83977F Infra-Red device + */ +static inline void wb977_init_irda(void) +{ + wb977_device_select(6); + + /* + * IR base address + */ + wb977_ww(0x60, IRDA_IO_BASE); + + /* + * IRDA IRQ 6, active high, edge trigger + */ + wb977_wb(0x70, 6); + wb977_wb(0x71, 0x02); + + /* + * RX DMA - ISA DMA 0 + */ + wb977_wb(0x74, 0x00); + + /* + * TX DMA - Disable Tx DMA + */ + wb977_wb(0x75, 0x04); + + /* + * Append CRC, Enable bank selection + */ + wb977_wb(0xf0, 0x03); + + /* + * Enable device + */ + wb977_device_enable(); +} + +/* + * Initialise Winbond W83977F general purpose IO + */ +static inline void wb977_init_gpio(void) +{ + unsigned long flags; + + /* + * Set up initial I/O definitions + */ + current_gpio_io = -1; + __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER); + + wb977_device_select(7); + + /* + * Group1 base address + */ + wb977_ww(0x60, GP1_IO_BASE); + wb977_ww(0x62, 0); + wb977_ww(0x64, 0); + + /* + * GP10 (Orage button) IRQ 10, active high, edge trigger + */ + wb977_wb(0x70, 10); + wb977_wb(0x71, 0x02); + + /* + * GP10: Debounce filter enabled, IRQ, input + */ + wb977_wb(0xe0, 0x19); + + /* + * Enable Group1 + */ + wb977_device_enable(); + + wb977_device_select(8); + + /* + * Group2 base address + */ + wb977_ww(0x60, GP2_IO_BASE); + + /* + * Clear watchdog timer regs + * - timer disable + */ + wb977_wb(0xf2, 0x00); + + /* + * - disable LED, no mouse nor keyboard IRQ + */ + wb977_wb(0xf3, 0x00); + + /* + * - timer counting, disable power LED, disable timeouot + */ + wb977_wb(0xf4, 0x00); + + /* + * Enable group2 + */ + wb977_device_enable(); + + /* + * Set Group1/Group2 outputs + */ + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN); + spin_unlock_irqrestore(&gpio_loc, flags); +} + +/* + * Initialise the Winbond W83977F chip. + */ +__initfunc(static void wb977_init(void)) +{ + request_region(0x370, 2, "W83977AF configuration"); + + /* + * Open up the SuperIO chip + */ + wb977_open(); + + /* + * Initialise the global registers + */ + wb977_init_global(); + + /* + * Initialise the various devices in + * the multi-IO chip. + */ + wb977_init_printer(); + wb977_init_keyboard(); + wb977_init_irda(); + wb977_init_gpio(); + + /* + * Close up the EFER gate + */ + wb977_close(); +} + +void __netwinder_text cpld_modify(int mask, int set) +{ + int msk; + + current_cpld = (current_cpld & ~mask) | set; + + gpio_modify_io(GPIO_DATA, 0); + gpio_modify_op(GPIO_IOLOAD, 0); + + for (msk = 8; msk; msk >>= 1) { + int bit = current_cpld & msk; + + gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0); + gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK); + } + + gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0); + gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK); + gpio_modify_op(GPIO_IOLOAD, 0); +} + +__initfunc(static void cpld_init(void)) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(-1, CPLD_UNMUTE | 4); + spin_unlock_irqrestore(&gpio_lock, flags); +} + +static unsigned char rwa_unlock[] __initdata = +{ 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 }; + +#ifndef DEBUG +#define dprintk if (0) printk +#else +#define dprintk printk +#endif + +#define WRITE_RWA(r,v) do { outb((r), 0x279); outb((v), 0xa79); } while (0) + +static inline void rwa010_unlock(void) +{ + int i; + + WRITE_RWA(2, 2); + mdelay(10); + + for (i = 0; i < sizeof(rwa_unlock); i++) + outb(rwa_unlock[i], 0x279); +} + +static inline void rwa010_read_ident(void) +{ + unsigned char si[9]; + int i, j; + + WRITE_RWA(3, 0); + WRITE_RWA(0, 128); + + outb(1, 0x279); + + mdelay(10); + + dprintk("Identifier: "); + for (i = 0; i < 9; i++) { + si[i] = 0; + for (j = 0; j < 8; j++) { + int bit; + mdelay(1); + inb(0x203); + mdelay(1); + bit = inb(0x203); + dprintk("%02X ", bit); + si[i] |= bit << j; + } + mdelay(10); + dprintk("%02X ", si[i]); + } + dprintk("\n"); +} + +static inline void rwa010_global_init(void) +{ + WRITE_RWA(6, 2); // Assign a card no = 2 + + dprintk("Card no = %d\n", inb(0x203)); + + WRITE_RWA(7, 3); + WRITE_RWA(0x30, 0); + + WRITE_RWA(7, 4); + WRITE_RWA(0x30, 0); + + WRITE_RWA(7, 2); + WRITE_RWA(0x30, 0); +} + +static inline void rwa010_game_port_init(void) +{ + int i; + + WRITE_RWA(7, 5); + + dprintk("Slider base: "); + WRITE_RWA(0x61, 1); + i = inb(0x203); + + WRITE_RWA(0x60, 2); + dprintk("%02X%02X (201)\n", inb(0x203), i); + + WRITE_RWA(0x30, 1); +} + +static inline void rwa010_waveartist_init(int base, int irq, int dma) +{ + int i; + + WRITE_RWA(7, 0); + + dprintk("WaveArtist base: "); + WRITE_RWA(0x61, base); + i = inb(0x203); + + WRITE_RWA(0x60, base >> 8); + dprintk("%02X%02X (%X),", inb(0x203), i, base); + + WRITE_RWA(0x70, irq); + dprintk(" irq: %d (%d),", inb(0x203), irq); + + WRITE_RWA(0x74, dma); + dprintk(" dma: %d (%d)\n", inb(0x203), dma); + + WRITE_RWA(0x30, 1); +} + +static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma) +{ + int i; + + WRITE_RWA(7, 1); + + dprintk("SoundBlaster base: "); + WRITE_RWA(0x61, sb_base); + i = inb(0x203); + + WRITE_RWA(0x60, sb_base >> 8); + dprintk("%02X%02X (%X),", inb(0x203), i, sb_base); + + dprintk(" irq: "); + WRITE_RWA(0x70, irq); + dprintk("%d (%d),", inb(0x203), irq); + + dprintk(" 8-bit DMA: "); + WRITE_RWA(0x74, dma); + dprintk("%d (%d)\n", inb(0x203), dma); + + dprintk("AdLib base: "); + WRITE_RWA(0x63, al_base); + i = inb(0x203); + + WRITE_RWA(0x62, al_base >> 8); + dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base); + + WRITE_RWA(0x30, 1); +} + +static void rwa010_soundblaster_reset(void) +{ + int i; + + outb(1, 0x226); + udelay(3); + outb(0, 0x226); + + for (i = 0; i < 5; i++) { + if (inb(0x22e) & 0x80) + break; + mdelay(1); + } + if (i == 5) + printk("SoundBlaster: DSP reset failed\n"); + + dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a)); + + for (i = 0; i < 5; i++) { + if ((inb(0x22c) & 0x80) == 0) + break; + mdelay(1); + } + + if (i == 5) + printk("SoundBlaster: DSP not ready\n"); + else { + outb(0xe1, 0x22c); + + dprintk("SoundBlaster DSP id: "); + i = inb(0x22a); + udelay(1); + i |= inb(0x22a) << 8; + dprintk("%04X\n", i); + + for (i = 0; i < 5; i++) { + if ((inb(0x22c) & 0x80) == 0) + break; + mdelay(1); + } + + if (i == 5) + printk("SoundBlaster: could not turn speaker off\n"); + + outb(0xd3, 0x22c); + } + + /* turn on OPL3 */ + outb(5, 0x38a); + outb(1, 0x38b); +} + +__initfunc(static void rwa010_init(void)) +{ + rwa010_unlock(); + rwa010_read_ident(); + rwa010_global_init(); + rwa010_game_port_init(); + rwa010_waveartist_init(0x250, 3, 7); + rwa010_soundblaster_init(0x220, 0x388, 3, 1); + rwa010_soundblaster_reset(); +} + +EXPORT_SYMBOL(gpio_lock); +EXPORT_SYMBOL(gpio_modify_op); +EXPORT_SYMBOL(gpio_modify_io); +EXPORT_SYMBOL(cpld_modify); + +#endif + +#ifdef CONFIG_LEDS +#define DEFAULT_LEDS 0 +#else +#define DEFAULT_LEDS GPIO_GREEN_LED +#endif + +/* + * CATS stuff + */ +#ifdef CONFIG_CATS + +#define CONFIG_PORT 0x370 +#define INDEX_PORT (CONFIG_PORT) +#define DATA_PORT (CONFIG_PORT + 1) + +static void __init cats_hw_init(void) +{ + /* Set Aladdin to CONFIGURE mode */ + outb(0x51, CONFIG_PORT); + outb(0x23, CONFIG_PORT); + + /* Select logical device 3 */ + outb(0x07, INDEX_PORT); + outb(0x03, DATA_PORT); + + /* Set parallel port to DMA channel 3, ECP+EPP1.9, + enable EPP timeout */ + outb(0x74, INDEX_PORT); + outb(0x03, DATA_PORT); + + outb(0xf0, INDEX_PORT); + outb(0x0f, DATA_PORT); + + outb(0xf1, INDEX_PORT); + outb(0x07, DATA_PORT); + + /* Select logical device 4 */ + outb(0x07, INDEX_PORT); + outb(0x04, DATA_PORT); + + /* UART1 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Select logical device 5 */ + outb(0x07, INDEX_PORT); + outb(0x05, DATA_PORT); + + /* UART2 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Set Aladdin to RUN mode */ + outb(0xbb, CONFIG_PORT); +} + +#endif + +__initfunc(void hw_init(void)) +{ + extern void register_isa_ports(unsigned int, unsigned int, + unsigned int); + register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); +#ifdef CONFIG_ARCH_NETWINDER + /* + * this ought to have a better home... + * Since this calls the above routines, which are + * compiled only if CONFIG_ARCH_NETWINDER is set, + * these should only be parsed by the compiler + * in the same circumstance. + */ + if (machine_is_netwinder()) { + unsigned long flags; + + wb977_init(); + cpld_init(); + rwa010_init(); + + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); + spin_unlock_irqrestore(&gpio_lock, flags); + } +#endif + + if (machine_is_cats()) + cats_hw_init(); + + leds_event(led_start); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/iic.c linux/arch/arm/kernel/iic.c --- v2.2.17/arch/arm/kernel/iic.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/iic.c Mon Oct 2 10:11:32 2000 @@ -7,20 +7,24 @@ */ #include +#include #include -#include #include +#include +#include + +#define FORCE_ONES 0xdc /* * if delay loop has been calibrated then us that, * else use IOC timer 1. */ -static void iic_delay (void) +static void iic_delay(void) { - extern unsigned long loops_per_sec; - if (loops_per_sec != (1 << 12)) { - udelay(10); + extern unsigned long loops_per_jiffy; + if (loops_per_jiffy != (1 << 12)) { + udelay(100); /* was 10 */ return; } else { unsigned long flags; @@ -30,7 +34,7 @@ outb(255, IOC_T1LTCHH); outb(0, IOC_T1GO); outb(1<<6, IOC_IRQCLRA); /* clear T1 irq */ - outb(4, IOC_T1LTCHL); + outb(10, IOC_T1LTCHL); /* was 4 */ outb(0, IOC_T1LTCHH); outb(0, IOC_T1GO); while ((inb(IOC_IRQSTATA) & (1<<6)) == 0); @@ -38,124 +42,207 @@ } } -static inline void iic_start (void) +#define IIC_INIT() dat = (inb(IOC_CONTROL) | FORCE_ONES) & ~3 +#define IIC_SET_DAT outb(dat|=1, IOC_CONTROL); +#define IIC_CLR_DAT outb(dat&=~1, IOC_CONTROL); +#define IIC_SET_CLK outb(dat|=2, IOC_CONTROL); +#define IIC_CLR_CLK outb(dat&=~2, IOC_CONTROL); +#define IIC_DELAY iic_delay(); +#define IIC_READ_DATA() (inb(IOC_CONTROL) & 1) + +static inline void iic_set_lines(int clk, int dat) { - unsigned char out; + int old; - out = inb(IOC_CONTROL) | 0xc2; + old = inb(IOC_CONTROL) | FORCE_ONES; - outb(out, IOC_CONTROL); - iic_delay(); + old &= ~3; + + if (clk) + old |= 2; + if (dat) + old |= 1; + + outb(old, IOC_CONTROL); - outb(out ^ 1, IOC_CONTROL); iic_delay(); } -static inline void iic_stop (void) +static inline unsigned int iic_read_data(void) { - unsigned char out; + return inb(IOC_CONTROL) & 1; +} - out = inb(IOC_CONTROL) | 0xc3; +/* + * C: ==~~_ + * D: =~~__ + */ +static inline void iic_start(void) +{ + unsigned int dat; - iic_delay(); - outb(out ^ 1, IOC_CONTROL); + IIC_INIT(); - iic_delay(); - outb(out, IOC_CONTROL); + IIC_SET_DAT + IIC_DELAY + IIC_SET_CLK + IIC_DELAY + + IIC_CLR_DAT + IIC_DELAY + IIC_CLR_CLK + IIC_DELAY } -static int iic_sendbyte (unsigned char b) +/* + * C: __~~ + * D: =__~ + */ +static inline void iic_stop(void) { - unsigned char out, in; - int i; + unsigned int dat; - out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; + IIC_INIT(); - outb(out, IOC_CONTROL); - for (i = 7; i >= 0; i--) { - unsigned char c; - c = out | ((b & (1 << i)) ? 1 : 0); + IIC_CLR_DAT + IIC_DELAY + IIC_SET_CLK + IIC_DELAY + IIC_SET_DAT + IIC_DELAY +} - outb(c, IOC_CONTROL); - iic_delay(); +/* + * C: __~_ + * D: =___ + */ +static inline void iic_acknowledge(void) +{ + unsigned int dat; - outb(c | 2, IOC_CONTROL); - iic_delay(); + IIC_INIT(); - outb(c, IOC_CONTROL); - } - outb(out | 1, IOC_CONTROL); - iic_delay(); + IIC_CLR_DAT + IIC_DELAY + IIC_SET_CLK + IIC_DELAY + IIC_CLR_CLK + IIC_DELAY +} - outb(out | 3, IOC_CONTROL); - iic_delay(); +/* + * C: __~_ + * D: =~H~ + */ +static inline int iic_is_acknowledged(void) +{ + unsigned int dat, ack_bit; - in = inb(IOC_CONTROL) & 1; + IIC_INIT(); - outb(out | 1, IOC_CONTROL); - iic_delay(); + IIC_SET_DAT + IIC_DELAY + IIC_SET_CLK + IIC_DELAY - outb(out, IOC_CONTROL); - iic_delay(); + ack_bit = IIC_READ_DATA(); - if(in) { - printk("No acknowledge from RTC\n"); - return 1; - } else - return 0; + IIC_CLR_CLK + IIC_DELAY + + return ack_bit == 0; +} + +/* + * C: _~__~__~__~__~__~__~__~_ + * D: =DDXDDXDDXDDXDDXDDXDDXDD + */ +static void iic_sendbyte(unsigned int b) +{ + unsigned int dat, i; + + IIC_INIT(); + + for (i = 0; i < 8; i++) { + if (b & 128) + IIC_SET_DAT + else + IIC_CLR_DAT + IIC_DELAY + + IIC_SET_CLK + IIC_DELAY + IIC_CLR_CLK + IIC_DELAY + + b <<= 1; + } } -static unsigned char iic_recvbyte (void) +/* + * C: __~_~_~_~_~_~_~_~_ + * D: =~HHHHHHHHHHHHHHHH + */ +static unsigned char iic_recvbyte(void) { - unsigned char out, in; - int i; + unsigned int dat, i, in; + + IIC_INIT(); - out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; + IIC_SET_DAT + IIC_DELAY - outb(out, IOC_CONTROL); in = 0; - for (i = 7; i >= 0; i--) { - outb(out | 1, IOC_CONTROL); - iic_delay(); - outb(out | 3, IOC_CONTROL); - iic_delay(); - in = (in << 1) | (inb(IOC_CONTROL) & 1); - outb(out | 1, IOC_CONTROL); - iic_delay(); + for (i = 0; i < 8; i++) { + IIC_SET_CLK + IIC_DELAY + + in = (in << 1) | IIC_READ_DATA(); + + IIC_CLR_CLK + IIC_DELAY } - outb(out, IOC_CONTROL); - iic_delay(); - outb(out | 2, IOC_CONTROL); - iic_delay(); return in; } -void iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len) +int iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len) { - iic_start(); + int i, err = -EIO; - if (iic_sendbyte(addr & 0xfe)) + iic_start(); + iic_sendbyte(addr & 0xfe); + if (!iic_is_acknowledged()) goto error; - if (iic_sendbyte(loc)) + iic_sendbyte(loc); + if (!iic_is_acknowledged()) goto error; if (addr & 1) { - int i; - - for (i = 0; i < len; i++) - if (iic_sendbyte (buf[i])) - break; - } else { - int i; - iic_stop(); iic_start(); iic_sendbyte(addr|1); - for (i = 0; i < len; i++) - buf[i] = iic_recvbyte (); + if (!iic_is_acknowledged()) + goto error; + + for (i = 0; i < len - 1; i++) { + buf[i] = iic_recvbyte(); + iic_acknowledge(); + } + buf[i] = iic_recvbyte(); + } else { + for (i = 0; i < len; i++) { + iic_sendbyte(buf[i]); + + if (!iic_is_acknowledged()) + goto error; + } } + + err = 0; error: iic_stop(); + + return err; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/ioport.c linux/arch/arm/kernel/ioport.c --- v2.2.17/arch/arm/kernel/ioport.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/ioport.c Fri Sep 15 23:28:37 2000 @@ -1,29 +1,36 @@ /* * linux/arch/arm/kernel/ioport.c * - * Io-port support is not used for ARM + * IO permission support for ARM. */ +#include #include #include #include #include #include +#include -/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ -/*asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) -{ -}*/ +#include +#include -asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) +#ifdef CONFIG_CPU_32 +asmlinkage int sys_iopl(unsigned long turn_on) { - return -ENOSYS; -} + if (turn_on && !capable(CAP_SYS_RAWIO)) + return -EPERM; -asmlinkage int sys_iopl(long ebx,long ecx,long edx, - long esi, long edi, long ebp, long eax, long ds, - long es, long fs, long gs, long orig_eax, - long eip,long cs,long eflags,long esp,long ss) + /* + * We only support an on_off approach + */ + modify_domain(DOMAIN_IO, turn_on ? DOMAIN_MANAGER : DOMAIN_CLIENT); + + return 0; +} +#else +asmlinkage int sys_iopl(unsigned long turn_on) { return -ENOSYS; } +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.2.17/arch/arm/kernel/irq.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/irq.c Fri Sep 15 23:28:37 2000 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -32,7 +31,6 @@ #include #include -#include #include #ifndef SMP @@ -46,10 +44,22 @@ #define cliIF() #endif +/* + * Maximum IRQ count. Currently, this is arbitary. + * However, it should not be set too low to prevent + * false triggering. Conversely, if it is set too + * high, then you could miss a stuck IRQ. + * + * Maybe we ought to set a timer and re-enable the + * IRQ at a later time? + */ +#define MAX_IRQ_CNT 100000 + unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; spinlock_t irq_controller_lock; +int setup_arm_irq(int, struct irqaction *); extern int get_fiq_list(char *); extern void init_FIQ(void); @@ -60,17 +70,29 @@ unsigned int probing : 1; /* IRQ in use for a probe */ unsigned int probe_ok : 1; /* IRQ can be used for probe */ unsigned int valid : 1; /* IRQ claimable */ - unsigned int unused :26; + unsigned int noautoenable : 1; /* don't automatically enable IRQ */ + unsigned int unused :25; void (*mask_ack)(unsigned int irq); /* Mask and acknowledge IRQ */ void (*mask)(unsigned int irq); /* Mask IRQ */ void (*unmask)(unsigned int irq); /* Unmask IRQ */ struct irqaction *action; - unsigned int unused2[3]; + /* + * IRQ lock detection + */ + unsigned int lck_cnt; + unsigned int lck_pc; + unsigned int lck_jif; }; static struct irqdesc irq_desc[NR_IRQS]; /* + * Get architecture specific interrupt handlers + * and interrupt initialisation. + */ +#include + +/* * Dummy mask/unmask handler */ static void dummy_mask_unmask_irq(unsigned int irq) @@ -94,10 +116,12 @@ spin_lock_irqsave(&irq_controller_lock, flags); cliIF(); - irq_desc[irq].enabled = 1; irq_desc[irq].probing = 0; irq_desc[irq].triggered = 0; - irq_desc[irq].unmask(irq); + if (!irq_desc[irq].noautoenable) { + irq_desc[irq].enabled = 1; + irq_desc[irq].unmask(irq); + } spin_unlock_irqrestore(&irq_controller_lock, flags); } @@ -119,21 +143,52 @@ *p++ = '\n'; } -#ifdef CONFIG_ACORN +#ifdef CONFIG_ARCH_ACORN p += get_fiq_list(p); #endif return p - buf; } /* + * IRQ lock detection. + * + * Hopefully, this should get us out of a few locked situations. + * However, it may take a while for this to happen, since we need + * a large number if IRQs to appear in the same jiffie with the + * same instruction pointer (or within 2 instructions). + */ +static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) +{ + unsigned long instr_ptr = instruction_pointer(regs); + + if (desc->lck_jif == jiffies && + desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) { + desc->lck_cnt += 1; + + if (desc->lck_cnt > MAX_IRQ_CNT) { + printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); + disable_irq(irq); + } + } else { + desc->lck_cnt = 0; + desc->lck_pc = instruction_pointer(regs); + desc->lck_jif = jiffies; + } +} + +/* * do_IRQ handles all normal device IRQ's */ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { - struct irqdesc * desc = irq_desc + irq; + struct irqdesc * desc; struct irqaction * action; int status, cpu; + irq = fixup_irq(irq); + + desc = irq_desc + irq; + spin_lock(&irq_controller_lock); desc->mask_ack(irq); spin_unlock(&irq_controller_lock); @@ -174,6 +229,12 @@ } } + /* + * Debug measure - hopefully we can continue if an + * IRQ lockup problem occurs... + */ + check_irq_lock(desc, irq, regs); + irq_exit(cpu, irq); /* @@ -181,15 +242,10 @@ * a return code from the irq handler to tell us * whether the handler wants us to do software bottom * half handling or not.. - * - * ** IMPORTANT NOTE: do_bottom_half() ENABLES IRQS!!! ** - * ** WE MUST DISABLE THEM AGAIN, ELSE IDE DISKS GO ** - * ** AWOL ** */ if (1) { if (bh_active & bh_mask) do_bottom_half(); - __cli(); } } @@ -227,11 +283,27 @@ struct irqaction *old, **p; unsigned long flags; - if (new->flags & SA_SAMPLE_RANDOM) + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ rand_initialize_irq(irq); + } + /* + * The following block of code has to be executed atomically + */ spin_lock_irqsave(&irq_controller_lock, flags); - p = &irq_desc[irq].action; if ((old = *p) != NULL) { /* Can't share interrupts unless both agree to */ @@ -252,28 +324,24 @@ if (!shared) { irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0; - irq_desc[irq].enabled = 1; irq_desc[irq].probing = 0; - irq_desc[irq].unmask(irq); + if (!irq_desc[irq].noautoenable) { + irq_desc[irq].enabled = 1; + irq_desc[irq].unmask(irq); + } } spin_unlock_irqrestore(&irq_controller_lock, flags); return 0; } -/* - * Using "struct sigaction" is slightly silly, but there - * are historical reasons and it works well, so.. - */ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irq_flags, const char * devname, void *dev_id) { unsigned long retval; struct irqaction *action; - if (!irq_desc[irq].valid) - return -EINVAL; - if (!handler) + if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler) return -EINVAL; action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -299,28 +367,30 @@ struct irqaction * action, **p; unsigned long flags; - if (!irq_desc[irq].valid) { + if (irq >= NR_IRQS || !irq_desc[irq].valid) { printk(KERN_ERR "Trying to free IRQ%d\n",irq); #ifdef CONFIG_DEBUG_ERRORS __backtrace(); #endif return; } + + spin_lock_irqsave(&irq_controller_lock, flags); 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_flags_cli (flags); *p = action->next; - restore_flags (flags); kfree(action); - return; + goto out; } printk(KERN_ERR "Trying to free free IRQ%d\n",irq); #ifdef CONFIG_DEBUG_ERRORS __backtrace(); #endif +out: + spin_unlock_irqrestore(&irq_controller_lock, flags); } /* Start the interrupt probing. Unlike other architectures, @@ -346,7 +416,6 @@ continue; irq_desc[i].probing = 1; - irq_desc[i].enabled = 1; irq_desc[i].triggered = 0; irq_desc[i].unmask(i); irqs += 1; @@ -364,7 +433,8 @@ */ spin_lock_irq(&irq_controller_lock); for (i = 0; i < NR_IRQS; i++) { - if (irq_desc[i].probing && irq_desc[i].triggered) { + if (irq_desc[i].probing && + irq_desc[i].triggered) { irq_desc[i].probing = 0; irqs -= 1; } @@ -383,7 +453,7 @@ int probe_irq_off(unsigned long irqs) { unsigned int i; - int irq_found = -1; + int irq_found = NO_IRQ; /* * look at the interrupts, and find exactly one @@ -393,7 +463,7 @@ for (i = 0; i < NR_IRQS; i++) { if (irq_desc[i].probing && irq_desc[i].triggered) { - if (irq_found != -1) { + if (irq_found != NO_IRQ) { irq_found = NO_IRQ; goto out; } @@ -405,21 +475,19 @@ irq_found = NO_IRQ; out: spin_unlock_irq(&irq_controller_lock); + return irq_found; } -/* - * Get architecture specific interrupt handlers - * and interrupt initialisation. - */ -#include - -unsigned long __init init_IRQ(unsigned long memory) +unsigned long __init init_IRQ(unsigned long memory) { extern void init_dma(void); int irq; for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].probe_ok = 0; + irq_desc[irq].valid = 0; + irq_desc[irq].noautoenable = 0; irq_desc[irq].mask_ack = dummy_mask_unmask_irq; irq_desc[irq].mask = dummy_mask_unmask_irq; irq_desc[irq].unmask = dummy_mask_unmask_irq; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/isa.c linux/arch/arm/kernel/isa.c --- v2.2.17/arch/arm/kernel/isa.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/kernel/isa.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,47 @@ +/* + * arch/arm/kernel/isa.c + * + * ISA shared memory and I/O port support + * + * Copyright (C) 1999 Phil Blundell + */ + +/* + * Nothing about this is actually ARM specific. One day we could move + * it into kernel/resource.c or some place like that. + */ + +#include +#include +#include +#include +#include +#include + +static unsigned int isa_membase, isa_portbase, isa_portshift; + +static ctl_table ctl_isa_vars[4] = { + {BUS_ISA_MEM_BASE, "membase", &isa_membase, + sizeof(isa_membase), 0444, NULL, &proc_dointvec}, + {BUS_ISA_PORT_BASE, "portbase", &isa_portbase, + sizeof(isa_portbase), 0444, NULL, &proc_dointvec}, + {BUS_ISA_PORT_SHIFT, "portshift", &isa_portshift, + sizeof(isa_portshift), 0444, NULL, &proc_dointvec}, + {0} +}; + +static struct ctl_table_header *isa_sysctl_header; + +static ctl_table ctl_isa[2] = {{BUS_ISA, "isa", NULL, 0, 0555, ctl_isa_vars}, + {0}}; +static ctl_table ctl_bus[2] = {{CTL_BUS, "bus", NULL, 0, 0555, ctl_isa}, + {0}}; + +void __init +register_isa_ports(unsigned int membase, unsigned int portbase, unsigned int portshift) +{ + isa_membase = membase; + isa_portbase = portbase; + isa_portshift = portshift; + isa_sysctl_header = register_sysctl_table(ctl_bus, 0); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/leds-ebsa110.c linux/arch/arm/kernel/leds-ebsa110.c --- v2.2.17/arch/arm/kernel/leds-ebsa110.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/leds-ebsa110.c Fri Sep 15 23:28:37 2000 @@ -7,11 +7,13 @@ * * - Red - toggles state every 50 timer interrupts */ +#include + #include #include #include -void leds_event(led_event_t ledevt) +void ebsa110_leds_event(led_event_t ledevt) { unsigned long flags; @@ -28,3 +30,7 @@ restore_flags(flags); } + +void (*leds_event)(led_event_t) = ebsa110_leds_event; + +EXPORT_SYMBOL(leds_event); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/leds-ebsa285.c linux/arch/arm/kernel/leds-ebsa285.c --- v2.2.17/arch/arm/kernel/leds-ebsa285.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/leds-ebsa285.c Thu Jan 1 01:00:00 1970 @@ -1,44 +0,0 @@ -/* - * arch/arm/kernel/leds-ebsa285.c - * - * Copyright (C) 1998 Russell King - * - * EBSA-285 LED control routines. We use the leds as follows: - * - * - Green - toggles state every 50 timer interrupts - * - Amber - On if system is not idle - * - Red - currently unused - */ -#include -#include -#include - -static char led_state = XBUS_LED_RED | XBUS_LED_GREEN; - -void leds_event(led_event_t ledevt) -{ - unsigned long flags; - - save_flags_cli(flags); - - switch(ledevt) { - case led_idle_start: - led_state |= XBUS_LED_AMBER; - break; - - case led_idle_end: - led_state &= ~XBUS_LED_AMBER; - break; - - case led_timer: - led_state ^= XBUS_LED_GREEN; - break; - - default: - break; - } - - restore_flags(flags); - - *XBUS_LEDS = led_state; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c --- v2.2.17/arch/arm/kernel/leds-footbridge.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/kernel/leds-footbridge.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,245 @@ +/* + * arch/arm/kernel/leds-footbridge.c + * + * Copyright (C) 1998-1999 Russell King + * + * EBSA-285 and NetWinder LED control routines. + * + * The EBSA-285 uses the leds as follows: + * - Green - toggles state every 50 timer interrupts + * - Amber - On if system is not idle + * - Red - currently unused + * + * The Netwinder uses the leds as follows: + * - Green - toggles state every 50 timer interrupts + * - Red - On if the system is not idle + * + * Changelog: + * 02-05-1999 RMK Various cleanups + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 +static char led_state; +static char hw_led_state; + +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; +extern spinlock_t gpio_lock; + +#ifdef CONFIG_FOOTBRIDGE + +static void __ebsa285_text ebsa285_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch (evt) { + case led_start: + hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN; +#ifndef CONFIG_LEDS_IDLE + hw_led_state |= XBUS_LED_AMBER; +#endif + led_state |= LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= XBUS_LED_GREEN; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= XBUS_LED_RED; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~XBUS_LED_RED; + break; +#endif + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~XBUS_LED_GREEN; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= XBUS_LED_GREEN; + break; + + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~XBUS_LED_AMBER; + break; + + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= XBUS_LED_AMBER; + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~XBUS_LED_RED; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= XBUS_LED_RED; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + *XBUS_LEDS = hw_led_state; + + spin_unlock_irqrestore(&leds_lock, flags); +} + +#endif + +#ifdef CONFIG_ARCH_NETWINDER + +static void __netwinder_text netwinder_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&leds_lock, flags); + + switch (evt) { + case led_start: + led_state |= LED_STATE_ENABLED; + hw_led_state = GPIO_GREEN_LED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = 0; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = 0; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= GPIO_GREEN_LED; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~GPIO_RED_LED; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= GPIO_RED_LED; + break; +#endif + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= GPIO_GREEN_LED; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~GPIO_GREEN_LED; + break; + + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED; + break; + + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED); + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= GPIO_RED_LED; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~GPIO_RED_LED; + break; + + default: + break; + } + + spin_unlock_irqrestore(&leds_lock, flags); + + if (led_state & LED_STATE_ENABLED) { + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state); + spin_unlock_irqrestore(&gpio_lock, flags); + } +} + +#endif + +static void dummy_leds_event(led_event_t evt) +{ +} + +static void __init +init_leds_event(led_event_t evt) +{ + leds_event = dummy_leds_event; + +#ifdef CONFIG_FOOTBRIDGE + if (machine_is_ebsa285() || machine_is_co285()) + leds_event = ebsa285_leds_event; +#endif +#ifdef CONFIG_ARCH_NETWINDER + if (machine_is_netwinder()) + leds_event = netwinder_leds_event; +#endif + + leds_event(evt); +} + +void (*leds_event)(led_event_t) = init_leds_event; + +EXPORT_SYMBOL(leds_event); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/oldlatches.c linux/arch/arm/kernel/oldlatches.c --- v2.2.17/arch/arm/kernel/oldlatches.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/oldlatches.c Fri Sep 15 23:28:37 2000 @@ -4,6 +4,7 @@ * (c) David Alan Gilbert 1995/1996 */ #include +#include #include #include @@ -40,7 +41,7 @@ } #endif -void oldlatch_init(void) +void __init oldlatch_init(void) { printk("oldlatch: init\n"); #ifdef LATCHAADDR diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.2.17/arch/arm/kernel/process.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/process.c Fri Sep 15 23:28:37 2000 @@ -32,11 +32,11 @@ #include #include -#include #include #include extern char *processor_modes[]; +extern void setup_mm_for_reboot(char mode); asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); @@ -53,46 +53,57 @@ } /* - * The idle loop on an arm.. + * The idle loop on an ARM... */ asmlinkage int sys_idle(void) { - int ret = -EPERM; + current->priority = 0; + current->counter = -100; - lock_kernel(); - if (current->pid != 0) - goto out; /* endless idle loop with no priority at all */ - current->priority = -100; - for (;;) - { + while (1) { + if (!current->need_resched && !hlt_counter) + arch_do_idle(); + schedule(); +#ifndef CONFIG_NO_PGT_CACHE check_pgt_cache(); -#if 0 //def ARCH_IDLE_OK - if (!hlt_counter && !current->need_resched) - proc_idle (); #endif - run_task_queue(&tq_scheduler); - schedule(); } - ret = 0; -out: - unlock_kernel(); - return ret; } +static char reboot_mode = 'h'; + __initfunc(void reboot_setup(char *str, int *ints)) { + reboot_mode = str[0]; } -/* - * This routine reboots the machine by resetting the expansion cards via - * their loaders, turning off the processor cache (if ARM3), copying the - * first instruction of the ROM to 0, and executing it there. - */ void machine_restart(char * __unused) { - proc_hard_reset (); - arch_hard_reset (); + /* + * Clean and disable cache, turn off interrupts + */ + processor._proc_fin(); + + /* + * Tell the mm system that we are going to reboot - + * we may need to insert some 1:1 mappings so that + * soft boot works. + */ + setup_mm_for_reboot(reboot_mode); + + /* + * Now call the architecture specific reboot code. + */ + arch_reset(reboot_mode); + + /* + * Whoops - the architecture was unable to reboot. + * Tell the user! + */ + mdelay(1000); + panic("Reboot failed -- System halted\n"); + while (1); } void machine_halt(void) @@ -148,6 +159,67 @@ } /* + * Task structure and kernel stack allocation. + * + * Taken from the i386 version. + */ +#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; +#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; + + tsk = ll_alloc_task_struct(); + + if (!tsk) { + index = task_struct_stack_ptr; + + 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 + */ + 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) +{ +#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; + } else +#endif + ll_free_task_struct(p); +} + +/* * Free current thread data structures etc.. */ void exit_thread(void) @@ -177,9 +249,10 @@ childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1; *childregs = *regs; childregs->ARM_r0 = 0; + childregs->ARM_sp = esp; save = ((struct context_save_struct *)(childregs)) - 1; - copy_thread_css(save); + init_thread_css(save); p->tss.save = save; return 0; @@ -222,3 +295,29 @@ dump->regs = *regs; dump->u_fpvalid = dump_fpu (regs, &dump->u_fp); } + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + extern int sys_exit(int) __attribute__((noreturn)); + pid_t __ret; + + __asm__ __volatile__( + "mov r0, %1 @ kernel_thread sys_clone\n" +" mov r1, #0\n" + __syscall(clone)"\n" +" mov %0, r0" + : "=r" (__ret) + : "Ir" (flags | CLONE_VM) : "r0", "r1"); + if (__ret == 0) + sys_exit((fn)(arg)); + return __ret; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.2.17/arch/arm/kernel/ptrace.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/ptrace.c Fri Sep 15 23:28:37 2000 @@ -25,6 +25,17 @@ * Breakpoint SWI instruction: SWI &9F0001 */ #define BREAKINST 0xef9f0001 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 + +static inline struct pt_regs * +get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task + 8192 - sizeof(struct pt_regs)); +} /* * this routine will get a word off of the processes privileged stack. @@ -34,11 +45,7 @@ */ static inline long get_stack_long(struct task_struct *task, int offset) { - unsigned char *stack; - - stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); - stack += offset << 2; - return *(unsigned long *)stack; + return get_user_regs(task)->uregs[offset]; } /* @@ -47,15 +54,21 @@ * this routine assumes that all the privileged stacks are in our * data space. */ -static inline long put_stack_long(struct task_struct *task, int offset, - unsigned long data) +static inline int +put_stack_long(struct task_struct *task, int offset, long data) { - unsigned char *stack; + struct pt_regs newregs, *regs = get_user_regs(task); + int ret = -EINVAL; - stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); - stack += offset << 2; - *(unsigned long *) stack = data; - return 0; + newregs = *regs; + newregs.uregs[offset] = data; + + if (valid_user_regs(&newregs)) { + regs->uregs[offset] = data; + ret = 0; + } + + return ret; } /* @@ -71,39 +84,42 @@ pmd_t *pgmiddle; pte_t *pgtable; unsigned long page; + int fault; repeat: pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } + if (pgd_none(*pgdir)) + goto none; if (pgd_bad(*pgdir)) { printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); pgd_clear(pgdir); return 0; } pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } + if (pmd_none(*pgmiddle)) + goto none; if (pmd_bad(*pgmiddle)) { printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); pmd_clear(pgmiddle); return 0; } pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 0); - goto repeat; - } + if (!pte_present(*pgtable)) + goto none; page = pte_page(*pgtable); if(MAP_NR(page) >= max_mapnr) return 0; page += addr & ~PAGE_MASK; return *(unsigned long *)page; + +none: + fault = handle_mm_fault(tsk, vma, addr, 0); + if (fault > 0) + goto repeat; + if (fault < 0) + force_sig(SIGKILL, tsk); + return 0; } /* @@ -122,46 +138,52 @@ pmd_t *pgmiddle; pte_t *pgtable; unsigned long page; + int fault; repeat: pgdir = pgd_offset(vma->vm_mm, addr); - if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } + if (!pgd_present(*pgdir)) + goto none; if (pgd_bad(*pgdir)) { printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); pgd_clear(pgdir); return; } pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } + if (pmd_none(*pgmiddle)) + goto none; if (pmd_bad(*pgmiddle)) { printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); pmd_clear(pgmiddle); return; } pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } + if (!pte_present(*pgtable)) + goto none; page = pte_page(*pgtable); - if (!pte_write(*pgtable)) { - handle_mm_fault(tsk, vma, addr, 1); - goto repeat; - } + if (!pte_write(*pgtable)) + goto none; if (MAP_NR(page) < max_mapnr) { page += addr & ~PAGE_MASK; + + flush_cache_range(vma->vm_mm, addr, addr + sizeof(unsigned long)); + *(unsigned long *)page = data; - __flush_entry_to_ram(page); + + clean_cache_area(page, sizeof(unsigned long)); + + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb_page(vma, addr & PAGE_MASK); } - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb(); + return; + +none: + fault = handle_mm_fault(tsk, vma, addr, 1); + if (fault > 0) + goto repeat; + if (fault < 0) + force_sig(SIGKILL, tsk); } static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr) @@ -669,7 +691,6 @@ return 0; wake_up_process (child); child->exit_code = SIGKILL; - ptrace_cancel_bpt (child); /* make sure single-step breakpoint is gone. */ ptrace_cancel_bpt (child); ret = 0; @@ -685,6 +706,54 @@ child->exit_code = data; /* give it a chance to run. */ ret = 0; + goto out; + + case PTRACE_GETREGS: + { /* Get all gp regs from the child. */ + unsigned char *stack; + + ret = 0; + stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs)); + if (copy_to_user((void *)data, stack, + sizeof(struct pt_regs))) + ret = -EFAULT; + + goto out; + }; + + /* Set all gp regs in the child. */ + case PTRACE_SETREGS: + { + struct pt_regs newregs; + + ret = -EFAULT; + if (copy_from_user(&newregs, (void *)data, + sizeof(struct pt_regs)) == 0) { + struct pt_regs *regs = get_user_regs(child); + + ret = -EINVAL; + if (valid_user_regs(&newregs)) { + *regs = newregs; + ret = 0; + } + } + goto out; + } + + case PTRACE_GETFPREGS: + /* Get the child FPU state. */ + ret = 0; + if (copy_to_user((void *)data, &child->tss.fpstate, + sizeof(struct user_fp))) + ret = -EFAULT; + goto out; + + case PTRACE_SETFPREGS: + /* Set the child FPU state. */ + ret = 0; + if (copy_from_user(&child->tss.fpstate, (void *)data, + sizeof(struct user_fp))) + ret = -EFAULT; goto out; case PTRACE_DETACH: /* detach a process that was attached. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.2.17/arch/arm/kernel/setup.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/setup.c Mon Oct 2 10:11:32 2000 @@ -1,68 +1,73 @@ /* * linux/arch/arm/kernel/setup.c * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1999 Russell King */ - -/* - * This file obtains various parameters about the system that the kernel - * is running on. - */ - #include -#include -#include #include #include #include -#include -#include -#include -#include -#include #include #include #include -#include #include #include -#include #include +#include #include #include #include -#include #include -#include #include #include -/* Work out which CPUs to support */ -#ifdef CONFIG_ARCH_ACORN -#define SUPPORT_CPU_ARM6 -#define SUPPORT_CPU_ARM7 -#define SUPPORT_CPU_SA110 -#else -#define SUPPORT_CPU_SA110 -#endif -#ifdef CONFIG_CPU_ARM6 -#define SUPPORT_CPU_ARM6 -#endif -#ifdef CONFIG_CPU_ARM7 -#define SUPPORT_CPU_ARM7 -#endif -#ifdef CONFIG_CPU_SA110 -#define SUPPORT_CPU_SA110 +#ifndef MEM_SIZE +#define MEM_SIZE (16*1024*1024) #endif #ifndef CONFIG_CMDLINE -#define CONFIG_CMDLINE "root=/dev/nfs rw" +#define CONFIG_CMDLINE "" #endif -#define MEM_SIZE (16*1024*1024) -#define COMMAND_LINE_SIZE 256 + +extern void reboot_setup(char *str, int *ints); +extern void disable_hlt(void); +extern int root_mountflags; +extern int _stext, _text, _etext, _edata, _end; + +unsigned int processor_id; +unsigned int __machine_arch_type; +unsigned int vram_size; +unsigned int system_rev; +unsigned int system_serial_low; +unsigned int system_serial_high; +unsigned int elf_hwcap; + +#ifdef CONFIG_ARCH_ACORN +unsigned int memc_ctrl_reg; +unsigned int number_mfm_drives; +#endif + +static unsigned long mem_end; + +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 **); +}; + +struct processor processor; struct drive_info_struct { char dummy[32]; } drive_info; + struct screen_info screen_info = { orig_video_lines: 30, orig_video_cols: 80, @@ -71,312 +76,429 @@ orig_video_isVGA: 1, orig_video_points: 8 }; -struct processor processor; + unsigned char aux_device_present; +char elf_platform[ELF_PLATFORM_SIZE]; +char saved_command_line[COMMAND_LINE_SIZE]; -extern const struct processor arm2_processor_functions; -extern const struct processor arm250_processor_functions; -extern const struct processor arm3_processor_functions; -extern const struct processor arm6_processor_functions; -extern const struct processor arm7_processor_functions; -extern const struct processor sa110_processor_functions; +static struct proc_info_item proc_info; +static const char *machine_name; +static char command_line[COMMAND_LINE_SIZE] = { 0, }; -char elf_platform[ELF_PLATFORM_SIZE]; +static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; +static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; +#define ENDIANNESS ((char)endian_test.l) -const struct armversions armidlist[] = { - /*-- Match -- --- Mask -- -- Manu -- Processor uname -m --- ELF STUFF --- - --- processor asm funcs --- */ -#if defined(CONFIG_CPU_26) - { 0x41560200, 0xfffffff0, "ARM/VLSI", "arm2" , "armv1" , "v1", 0, - &arm2_processor_functions }, - { 0x41560250, 0xfffffff0, "ARM/VLSI", "arm250" , "armv2" , "v2", HWCAP_SWP, - &arm250_processor_functions }, - { 0x41560300, 0xfffffff0, "ARM/VLSI", "arm3" , "armv2" , "v2", HWCAP_SWP, - &arm3_processor_functions }, -#elif defined(CONFIG_CPU_32) -#ifdef SUPPORT_CPU_ARM6 - { 0x41560600, 0xfffffff0, "ARM/VLSI", "arm6" , "armv3" , "v3", HWCAP_SWP, - &arm6_processor_functions }, - { 0x41560610, 0xfffffff0, "ARM/VLSI", "arm610" , "armv3" , "v3", HWCAP_SWP, - &arm6_processor_functions }, -#endif -#ifdef SUPPORT_CPU_ARM7 - { 0x41007000, 0xffffff00, "ARM/VLSI", "arm7" , "armv3" , "v3", HWCAP_SWP, - &arm7_processor_functions }, - /* ARM710 IDs are non-standard */ - { 0x41007100, 0xfff8ff00, "ARM/VLSI", "arm710" , "armv3" , "v3", HWCAP_SWP, - &arm7_processor_functions }, -#endif -#ifdef SUPPORT_CPU_SA110 - { 0x4401a100, 0xfffffff0, "DEC", "sa110" , "armv4" , "v3", HWCAP_SWP|HWCAP_HALF, - &sa110_processor_functions }, -#endif -#endif - { 0x00000000, 0x00000000, "***", "unknown", "unknown", "**", 0, NULL } -}; +static void __init setup_processor(void) +{ + extern struct proc_info_list __proc_info_begin, __proc_info_end; + struct proc_info_list *list; -/* - * From head-armv.S - */ -unsigned int processor_id; -unsigned int machine_type; -int armidindex; + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc-*.S + */ + for (list = &__proc_info_begin; list < &__proc_info_end ; list++) + if ((processor_id & list->cpu_mask) == list->cpu_val) + break; -extern int root_mountflags; -extern int _etext, _edata, _end; + /* + * If processor type is unrecognised, then we + * can do nothing... + */ + if (list >= &__proc_info_end) { + printk("CPU configuration botched (ID %08x), unable " + "to continue.\n", processor_id); + while (1); + } -/*------------------------------------------------------------------------- - * Early initialisation routines for various configurable items in the - * kernel. Each one either supplies a setup_ function, or defines this - * symbol to be empty if not configured. - */ + proc_info = *list->info; -/* - * Risc-PC specific initialisation - */ -#ifdef CONFIG_ARCH_RPC + processor = *list->proc; -#include + printk("Processor: %s %s revision %d\n", + proc_info.manufacturer, proc_info.cpu_name, + (int)processor_id & 15); -unsigned int vram_half_sam; + sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); + sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); + elf_hwcap = list->elf_hwcap; -static void -setup_rpc(struct param_struct *params) -{ - extern void init_dram_banks(const struct param_struct *params); + processor._proc_init(); +} - init_dram_banks(params); +static unsigned long __init memparse(char *ptr, char **retptr) +{ + unsigned long ret = simple_strtoul(ptr, retptr, 0); - switch (params->u1.s.pages_in_vram) { - case 256: - vram_half_sam = 1024; - break; - case 512: + switch (**retptr) { + case 'M': + case 'm': + ret <<= 10; + case 'K': + case 'k': + ret <<= 10; + (*retptr)++; default: - vram_half_sam = 2048; + break; } + return ret; } -#else -#define setup_rpc(x) -#endif - -#ifdef PARAMS_BASE - -#ifdef CONFIG_ARCH_ACORN -int memc_ctrl_reg; -int number_ide_drives; -int number_mfm_drives; -#endif -static struct param_struct *params = (struct param_struct *)PARAMS_BASE; - -__initfunc(static char * -setup_params(unsigned long *mem_end_p)) +/* + * Initial parsing of the command line. We need to pick out the + * memory size. We look for mem=size, where size is "size[KkMm]" + */ +static void __init +parse_cmdline(char **cmdline_p, char *from) { - ROOT_DEV = to_kdev_t(params->u1.s.rootdev); - ORIG_X = params->u1.s.video_x; - ORIG_Y = params->u1.s.video_y; - ORIG_VIDEO_COLS = params->u1.s.video_num_cols; - ORIG_VIDEO_LINES = params->u1.s.video_num_rows; + char c = ' ', *to = command_line; + int usermem = 0, len = 0; -#ifdef CONFIG_ARCH_ACORN -#ifndef CONFIG_FB - { - extern int bytes_per_char_h; - extern int bytes_per_char_v; - - bytes_per_char_h = params->u1.s.bytes_per_char_h; - bytes_per_char_v = params->u1.s.bytes_per_char_v; - } -#endif - memc_ctrl_reg = params->u1.s.memc_control_reg; - number_ide_drives = (params->u1.s.adfsdrives >> 6) & 3; - number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; + for (;;) { + if (c == ' ' && !memcmp(from, "mem=", 4)) { + unsigned long size, start; - setup_rpc(params); + if (to != command_line) + to -= 1; - if (!(params->u1.s.flags & FLAG_READONLY)) - root_mountflags &= ~MS_RDONLY; -#endif -#ifdef CONFIG_BLK_DEV_RAM - { - extern int rd_doload; - extern int rd_prompt; - extern int rd_image_start; - - rd_image_start = params->u1.s.rd_start; - rd_prompt = (params->u1.s.flags & FLAG_RDPROMPT) == 0; - rd_doload = (params->u1.s.flags & FLAG_RDLOAD) == 0; + start = PAGE_OFFSET; + size = memparse(from + 4, &from); + if (*from == '@') + memparse(from + 1, &from); + + if (usermem == 0) { + usermem = 1; + mem_end = start + size; + } + } + c = *from++; + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *to++ = c; } -#endif - -#ifdef CONFIG_ARCH_ACORN - *mem_end_p = GET_MEMORY_END(params); -#elif defined(CONFIG_ARCH_EBSA285) - *mem_end_p = PAGE_OFFSET + params->u1.s.page_size * params->u1.s.nr_pages; -#else - *mem_end_p = PAGE_OFFSET + MEM_SIZE; -#endif + *to = '\0'; + *cmdline_p = command_line; - return params->commandline; + /* remove trailing spaces */ + while (*--to == ' ' && to != command_line) + *to = '\0'; } -#else - -static char default_command_line[] __initdata = CONFIG_CMDLINE; - -__initfunc(static char * -setup_params(unsigned long *mem_end_p)) +static void __init +setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) { - ROOT_DEV = 0x00ff; - #ifdef CONFIG_BLK_DEV_RAM - { - extern int rd_doload; - extern int rd_prompt; - extern int rd_image_start; - - rd_image_start = 0; - rd_prompt = 1; - rd_doload = 1; - } -#endif + extern int rd_doload, rd_prompt, rd_image_start, rd_size; - *mem_end_p = PAGE_OFFSET + MEM_SIZE; + rd_image_start = image_start; + rd_prompt = prompt; + rd_doload = doload; - return default_command_line; -} + if (rd_sz) + rd_size = rd_sz; #endif +} /* * initial ram disk */ -#ifdef CONFIG_BLK_DEV_INITRD -__initfunc(static void -setup_initrd(const struct param_struct *params)) +static void __init setup_initrd(unsigned int start, unsigned int size) { - if (params->u1.s.initrd_start) { - initrd_start = params->u1.s.initrd_start; - initrd_end = initrd_start + params->u1.s.initrd_size; - } else { - initrd_start = 0; - initrd_end = 0; - } +#ifdef CONFIG_BLK_DEV_INITRD + if (start == 0) + size = 0; + initrd_start = start; + initrd_end = start + size; +#endif } -__initfunc(static void -check_initrd(unsigned long mem_start, unsigned long mem_end)) +/* + * Initialise memory. + */ +static void __init setup_bootmem(void) { + unsigned long mem_start; + + mem_start = (unsigned long)&_end; + +#ifdef CONFIG_BLK_DEV_INITRD if (initrd_end > mem_end) { printk ("initrd extends beyond end of memory " "(0x%08lx > 0x%08lx) - disabling initrd\n", initrd_end, mem_end); initrd_start = 0; } +#endif } -#else -#define setup_initrd(p) -#define check_initrd(ms,me) +/* + * 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) +{ +#ifdef CONFIG_ARCH_ACORN + if (machine_is_riscpc()) { + /* + * RiscPC can't handle half-word loads and stores + */ + elf_hwcap &= ~HWCAP_HALF; + + switch (params->u1.s.pages_in_vram) { + case 512: + vram_size += PAGE_SIZE * 256; + case 256: + vram_size += PAGE_SIZE * 256; + default: + break; + } + } + memc_ctrl_reg = params->u1.s.memc_control_reg; + number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; #endif +} -__initfunc(void -setup_processor(void)) +static void __init +fixup_ebsa285(struct machine_desc *desc, struct param_struct *params, + char **cmdline) { - armidindex = 0; - - while ((armidlist[armidindex].id ^ processor_id) & - armidlist[armidindex].mask) - armidindex += 1; - - if (armidlist[armidindex].id == 0) { -#ifdef CONFIG_ARCH_ACORN - int i; + 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; +} - for (i = 0; i < 3200; i++) - ((unsigned long *)SCREEN2_BASE)[i] = 0x77113322; -#endif - while (1); +/* + * 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 != 0x02000 && + params->u1.s.nr_pages != 0x04000 && + params->u1.s.nr_pages != 0x08000 && + params->u1.s.nr_pages != 0x10000) { + 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; } +} - processor = *armidlist[armidindex].proc; - processor._proc_init(); +/* + * 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; } -static char command_line[COMMAND_LINE_SIZE] = { 0, }; - char saved_command_line[COMMAND_LINE_SIZE]; +#define NO_PARAMS 0 +#define NO_VIDEO 0, 0 -__initfunc(static void -setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end)) +/* + * 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, + NULL + }, { "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, + NULL + } +}; + +void __init +setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { - char c, *to = command_line; - int len = 0; + struct param_struct *params = NULL; + struct machine_desc *mdesc; + char *from = default_command_line; - *mem_start = (unsigned long)&_end; +#if defined(CONFIG_ARCH_ARC) + __machine_arch_type = MACH_TYPE_ARCHIMEDES; +#elif defined(CONFIG_ARCH_A5K) + __machine_arch_type = MACH_TYPE_A5K; +#endif - for (;;) { - if (cmd_line[0] == ' ' && - cmd_line[1] == 'm' && - cmd_line[2] == 'e' && - cmd_line[3] == 'm' && - cmd_line[4] == '=') { - *mem_end = simple_strtoul(cmd_line+5, &cmd_line, 0); - switch(*cmd_line) { - case 'M': - case 'm': - *mem_end <<= 10; - case 'K': - case 'k': - *mem_end <<= 10; - cmd_line++; - } - *mem_end = *mem_end + PAGE_OFFSET; - } - c = *cmd_line++; - if (!c) - break; - if (COMMAND_LINE_SIZE <= ++len) - break; - *to++ = c; + 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", NULL); + + 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(KERN_WARNING "Warning: bad configuration page, " + "trying to continue\n"); + params = NULL; } - *to = '\0'; -} + if (params) { + mem_end = params->u1.s.page_size * + params->u1.s.nr_pages; + + 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; + system_serial_high = params->u1.s.system_serial_high; + + setup_ramdisk((params->u1.s.flags & FLAG_RDLOAD) == 0, + (params->u1.s.flags & FLAG_RDPROMPT) == 0, + params->u1.s.rd_start, + params->u1.s.ramdisk_size); -__initfunc(void -setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) -{ - static unsigned char smptrap; - unsigned long memory_end; - char endian = 'l'; - char *from; - - if (smptrap == 1) - return; - smptrap = 1; + setup_initrd(params->u1.s.initrd_start, + params->u1.s.initrd_size); - setup_processor(); + if (!(params->u1.s.flags & FLAG_READONLY)) + root_mountflags &= ~MS_RDONLY; + +#ifdef CONFIG_ARCH_RPC + { + extern void init_dram_banks(struct param_struct *); + init_dram_banks(params); + } +#endif + mem_end -= vram_size; - from = setup_params(&memory_end); - setup_initrd(params); + from = params->commandline; + } - /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, from, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + if (!mem_end) + mem_end = MEM_SIZE; - setup_mem(from, memory_start_p, &memory_end); - check_initrd(*memory_start_p, memory_end); + mem_end += PAGE_OFFSET; - init_task.mm->start_code = TASK_SIZE; - init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext; - init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata; - init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; + init_task.mm->start_code = (unsigned long) &_text; + init_task.mm->end_code = (unsigned long) &_etext; + init_task.mm->end_data = (unsigned long) &_edata; + init_task.mm->brk = (unsigned long) &_end; - *cmdline_p = command_line; - *memory_end_p = memory_end; + memcpy(saved_command_line, from, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + parse_cmdline(cmdline_p, from); + setup_bootmem(); - sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, endian); - sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, endian); +#ifdef CONFIG_NWFPE + fpe_init(); +#endif #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) @@ -385,69 +507,32 @@ conswitchp = &dummy_con; #endif #endif + + *cmdline_p = command_line; + *memory_start_p = (unsigned long)&_end; + *memory_end_p = mem_end; } -static const struct { - char *machine_name; - char *bus_name; -} machine_desc[] = { - { "DEC-EBSA110", "DEC" }, - { "Acorn-RiscPC", "Acorn" }, - { "Nexus-NexusPCI", "PCI" }, - { "DEC-EBSA285", "PCI" }, - { "Corel-Netwinder", "PCI/ISA" }, - { "Chalice-CATS", "PCI" }, - { "unknown-TBOX", "PCI" } -}; +int get_cpuinfo(char * buffer) +{ + char *p = buffer; -#if defined(CONFIG_ARCH_ARC) -#define HARDWARE "Acorn-Archimedes" -#define IO_BUS "Acorn" -#elif defined(CONFIG_ARCH_A5K) -#define HARDWARE "Acorn-A5000" -#define IO_BUS "Acorn" -#endif + p += sprintf(p, "Processor\t: %s %s rev %d (%s)\n", + proc_info.manufacturer, proc_info.cpu_name, + (int)processor_id & 15, elf_platform); -#if defined(CONFIG_CPU_ARM2) -#define OPTIMISATION "ARM2" -#elif defined(CONFIG_CPU_ARM3) -#define OPTIMISATION "ARM3" -#elif defined(CONFIG_CPU_ARM6) -#define OPTIMISATION "ARM6" -#elif defined(CONFIG_CPU_ARM7) -#define OPTIMISATION "ARM7" -#elif defined(CONFIG_CPU_SA110) -#define OPTIMISATION "StrongARM" -#else -#define OPTIMISATION "unknown" -#endif + p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n", + (loops_per_jiffy+2500) / (500000/HZ), + ((loops_per_jiffy+2500) / (5000/HZ)) % 100); -int get_cpuinfo(char * buffer) -{ - int len; + p += sprintf(p, "Hardware\t: %s\n", machine_name); - len = sprintf(buffer, - "Processor\t: %s %s rev %d\n" - "BogoMips\t: %lu.%02lu\n" - "Hardware\t: %s\n" - "Optimisation\t: %s\n" - "IO Bus\t\t: %s\n", - armidlist[armidindex].manu, - armidlist[armidindex].name, - (int)processor_id & 15, - (loops_per_sec+2500) / 500000, - ((loops_per_sec+2500) / 5000) % 100, -#ifdef HARDWARE - HARDWARE, -#else - machine_desc[machine_type].machine_name, -#endif - OPTIMISATION, -#ifdef IO_BUS - IO_BUS -#else - machine_desc[machine_type].bus_name -#endif - ); - return len; + p += sprintf(p, "Revision\t: %04x\n", + system_rev); + + p += sprintf(p, "Serial\t\t: %08x%08x\n", + system_serial_high, + system_serial_low); + + return p - buffer; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.2.17/arch/arm/kernel/signal.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/signal.c Fri Sep 15 23:28:37 2000 @@ -28,7 +28,7 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr, int options, unsigned long *ru); -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); extern int ptrace_cancel_bpt (struct task_struct *); extern int ptrace_set_bpt (struct task_struct *); @@ -50,7 +50,7 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal(&saveset, regs, 0)) return regs->ARM_r0; } } @@ -78,7 +78,7 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal(&saveset, regs, 0)) return regs->ARM_r0; } } @@ -158,12 +158,8 @@ #ifdef CONFIG_CPU_32 err |= __get_user(regs->ARM_cpsr, &sc->arm_cpsr); #endif - if (!valid_user_regs(regs)) - return 1; - /* send SIGTRAP if we're single-stepping */ - if (ptrace_cancel_bpt (current)) - send_sig (SIGTRAP, current, 1); + err |= !valid_user_regs(regs); return err; } @@ -173,6 +169,14 @@ struct sigframe *frame; sigset_t set; + /* + * Since we stacked the signal on a word boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (regs->ARM_sp & 3) + goto badframe; + frame = (struct sigframe *)regs->ARM_sp; if (verify_area(VERIFY_READ, frame, sizeof (*frame))) @@ -192,6 +196,10 @@ if (restore_sigcontext(regs, &frame->sc)) goto badframe; + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt (current)) + send_sig(SIGTRAP, current, 1); + return regs->ARM_r0; badframe: @@ -204,6 +212,14 @@ struct rt_sigframe *frame; sigset_t set; + /* + * Since we stacked the signal on a word boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (regs->ARM_sp & 3) + goto badframe; + frame = (struct rt_sigframe *)regs->ARM_sp; if (verify_area(VERIFY_READ, frame, sizeof (*frame))) @@ -220,6 +236,10 @@ if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt (current)) + send_sig(SIGTRAP, current, 1); + return regs->ARM_r0; badframe: @@ -260,6 +280,26 @@ return err; } +static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, + unsigned long framesize) +{ + unsigned long sp = regs->ARM_sp; + + /* + * This is the X/Open sanctioned signal stack switching. + */ + if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + /* + * No matter what happens, 'sp' must be word + * aligned otherwise nasty things could happen + */ + sp &= ~3; + + return (void *)(sp - framesize); +} + static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { @@ -267,9 +307,9 @@ unsigned long retcode; int err = 0; - frame = (struct sigframe *)regs->ARM_sp - 1; + frame = get_sigframe(ka, regs, sizeof(*frame)); - if (!access_ok(VERIFT_WRITE, frame, sizeof (*frame))) + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto segv_and_exit; err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); @@ -286,7 +326,7 @@ } else { retcode = (unsigned long)&frame->retcode; err |= __put_user(SWI_SYS_SIGRETURN, &frame->retcode); - __flush_entry_to_ram (&frame->retcode); + flush_icache_range(retcode, retcode + 4); } if (err) @@ -299,6 +339,11 @@ regs->ARM_sp = (unsigned long)frame; regs->ARM_lr = retcode; regs->ARM_pc = (unsigned long)ka->sa.sa_handler; +#if defined(CONFIG_CPU_32) + /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */ + if (ka->sa.sa_flags & SA_THIRTYTWO) + regs->ARM_cpsr = USR_MODE; +#endif if (valid_user_regs(regs)) return; @@ -315,7 +360,8 @@ unsigned long retcode; int err = 0; - frame = (struct rt_sigframe *)regs->ARM_sp - 1; + frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto segv_and_exit; @@ -337,7 +383,7 @@ } else { retcode = (unsigned long)&frame->retcode; err |= __put_user(SWI_SYS_RT_SIGRETURN, &frame->retcode); - __flush_entry_to_ram (&frame->retcode); + flush_icache_range(retcode, retcode + 4); } if (err) @@ -350,6 +396,11 @@ regs->ARM_sp = (unsigned long)frame; regs->ARM_lr = retcode; regs->ARM_pc = (unsigned long)ka->sa.sa_handler; +#if defined(CONFIG_CPU_32) + /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */ + if (ka->sa.sa_flags & SA_THIRTYTWO) + regs->ARM_cpsr = USR_MODE; +#endif if (valid_user_regs(regs)) return; @@ -393,18 +444,25 @@ * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) { - unsigned long instr, *pc = (unsigned long *)(instruction_pointer(regs)-4); struct k_sigaction *ka; siginfo_t info; - int single_stepping, swi_instr; + int single_stepping; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 0; if (!oldset) oldset = ¤t->blocked; single_stepping = ptrace_cancel_bpt (current); - swi_instr = (!get_user (instr, pc) && (instr & 0x0f000000) == 0x0f000000); for (;;) { unsigned long signr; @@ -503,7 +561,7 @@ } /* Are we from a system call? */ - if (swi_instr) { + if (syscall) { switch (regs->ARM_r0) { case -ERESTARTNOHAND: regs->ARM_r0 = -EINTR; @@ -527,7 +585,7 @@ return 1; } - if (swi_instr && + if (syscall && (regs->ARM_r0 == -ERESTARTNOHAND || regs->ARM_r0 == -ERESTARTSYS || regs->ARM_r0 == -ERESTARTNOINTR)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c --- v2.2.17/arch/arm/kernel/sys_arm.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/sys_arm.c Fri Sep 15 23:28:37 2000 @@ -223,13 +223,7 @@ */ asmlinkage int sys_fork(struct pt_regs *regs) { - int ret; - - lock_kernel(); - ret = do_fork(SIGCHLD, regs->ARM_sp, regs); - unlock_kernel(); - - return ret; + return do_fork(SIGCHLD, regs->ARM_sp, regs); } /* Clone a task - this clones the calling program thread. @@ -237,14 +231,14 @@ */ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs) { - int ret; - - lock_kernel(); if (!newsp) newsp = regs->ARM_sp; - ret = do_fork(clone_flags, newsp, regs); - unlock_kernel(); - return ret; + return do_fork(clone_flags, newsp, regs); +} + +asmlinkage int sys_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs); } /* sys_execve() executes a new program. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.2.17/arch/arm/kernel/time.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/time.c Fri Sep 15 23:28:37 2000 @@ -76,6 +76,25 @@ )*60 + sec; /* finally seconds */ } +/* + * Handle profile stuff... + */ +static void do_profile(unsigned long pc) +{ + if (prof_buffer && current->pid) { + extern int _stext; + + pc -= (unsigned long)&_stext; + + pc >>= prof_shift; + + if (pc >= prof_len) + pc = prof_len - 1; + + prof_buffer[pc] += 1; + } +} + #include static unsigned long do_gettimeoffset(void) @@ -93,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; @@ -127,27 +146,12 @@ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti (); -} - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick. - */ -static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - if (reset_timer ()) - do_timer(regs); - - update_rtc (); + sti(); } -static struct irqaction irqtimer = { timer_interrupt, 0, 0, "timer", NULL, NULL}; - -__initfunc(void time_init(void)) +void __init time_init(void) { - xtime.tv_sec = setup_timer(); xtime.tv_usec = 0; - setup_arm_irq(IRQ_TIMER, &irqtimer); + setup_timer(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.2.17/arch/arm/kernel/traps.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/kernel/traps.c Fri Sep 15 23:28:37 2000 @@ -24,7 +24,6 @@ #include #include -extern void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret); extern void c_backtrace (unsigned long fp, int pmode); extern int ptrace_cancel_bpt (struct task_struct *); @@ -45,16 +44,17 @@ int kstack_depth_to_print = 200; -static int verify_stack_pointer (unsigned long stackptr, int size) +/* + * Stack pointers should always be within the kernels view of + * physical memory. If it is not there, then we can't dump + * out any information relating to the stack. + */ +static int verify_stack(unsigned long sp) { -#ifdef CONFIG_CPU_26 - if (stackptr < 0x02048000 || stackptr + size > 0x03000000) - return -EFAULT; -#else - if (stackptr < PAGE_OFFSET || stackptr + size > (unsigned long)high_memory) + if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory) return -EFAULT; -#endif - return 0; + + return 0; } /* @@ -90,22 +90,26 @@ static void dump_instr(unsigned long pc, int user) { - unsigned long module_start, module_end; int pmin = -2, pmax = 3, ok = 0; extern char start_kernel, _etext; if (!user) { + unsigned long module_start, module_end; + unsigned long kernel_start, kernel_end; + module_start = VMALLOC_START; module_end = module_start + MODULE_RANGE; - if ((pc >= (unsigned long) &start_kernel) && - (pc <= (unsigned long) &_etext)) { - if (pc + pmin < (unsigned long) &start_kernel) - pmin = ((unsigned long) &start_kernel) - pc; - if (pc + pmax > (unsigned long) &_etext) - pmax = ((unsigned long) &_etext) - pc; + kernel_start = (unsigned long)&start_kernel; + kernel_end = (unsigned long)&_etext; + + if (pc >= kernel_start && pc < kernel_end) { + if (pc + pmin < kernel_start) + pmin = kernel_start - pc; + if (pc + pmax > kernel_end) + pmax = kernel_end - pc; ok = 1; - } else if (pc >= module_start && pc <= module_end) { + } else if (pc >= module_start && pc < module_end) { if (pc + pmin < module_start) pmin = module_start - pc; if (pc + pmax > module_end) @@ -125,119 +129,139 @@ printk ("pc not in code space\n"); } -static void dump_state(char *str, struct pt_regs *regs, int err) +spinlock_t die_lock; + +/* + * This function is protected against re-entrancy. + */ +void die(const char *str, struct pt_regs *regs, int err) { + struct task_struct *tsk = current; + + spin_lock_irq(&die_lock); + console_verbose(); printk("Internal error: %s: %x\n", str, err); printk("CPU: %d\n", smp_processor_id()); show_regs(regs); printk("Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, 4096+(unsigned long)current); -} + current->comm, current->pid, 4096+(unsigned long)tsk); -/* - * This function is protected against kernel-mode re-entrancy. If it - * is re-entered it will hang the system since we can't guarantee in - * this case that any of the functions that it calls are safe any more. - * Even the panic function could be a problem, but we'll give it a go. - */ -void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret) -{ - static int died = 0; - unsigned long cstack, sstack, frameptr; - - if (user_mode(regs)) - return; + if (!user_mode(regs)) { + unsigned long sp = (unsigned long)(regs + 1); + unsigned long fp; + int dump_info = 1; + + printk("Stack: "); + if (verify_stack(sp)) { + printk("invalid kernel stack pointer %08lx", sp); + dump_info = 0; + } else if (sp < 4096+(unsigned long)tsk) + printk("kernel stack pointer underflow"); + printk("\n"); + + if (dump_info) + dump_mem(sp - 16, 8192+(unsigned long)tsk); + + dump_info = 1; + + printk("Backtrace: "); + fp = regs->ARM_fp; + if (!fp) { + printk("no frame pointer"); + dump_info = 0; + } else if (verify_stack(fp)) { + printk("invalid frame pointer %08lx", fp); + dump_info = 0; + } else if (fp < 4096+(unsigned long)tsk) + printk("frame pointer underflow"); + printk("\n"); - switch (died) { - case 2: - while (1); - case 1: - died ++; - panic ("die_if_kernel re-entered. Major kernel corruption. Please reboot me!"); - break; - case 0: - died ++; - break; - } + if (dump_info) + c_backtrace(fp, processor_mode(regs)); - dump_state(str, regs, err); + dump_instr(instruction_pointer(regs), 0); + } - cstack = (unsigned long)(regs + 1); - sstack = 4096+(unsigned long)current; + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} - printk("Stack: "); - if (verify_stack_pointer(cstack, 4)) - printk("invalid kernel stack pointer %08lx", cstack); - else if(cstack > sstack + 4096) - printk("(sp overflow)"); - else if(cstack < sstack) - printk("(sp underflow)"); - printk("\n"); - - dump_mem(cstack - 16, sstack + 4096); - - frameptr = regs->ARM_fp; - if (frameptr) { - if (verify_stack_pointer (frameptr, 4)) - printk ("Backtrace: invalid frame pointer\n"); - else { - printk("Backtrace: \n"); - c_backtrace (frameptr, processor_mode(regs)); - } - } +static void die_if_kernel(const char *str, struct pt_regs *regs, int err) +{ + if (user_mode(regs)) + return; - dump_instr(instruction_pointer(regs), 0); - died = 0; - if (ret != -1) - do_exit (ret); - else { - cli (); - while (1); - } + die(str, regs, err); } -void bad_user_access_alignment (const void *ptr) +void bad_user_access_alignment(const void *ptr) { - void *pc; - __asm__("mov %0, lr\n": "=r" (pc)); - printk (KERN_ERR "bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, pc); + printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr, + __builtin_return_address(0)); current->tss.error_code = 0; current->tss.trap_no = 11; - force_sig (SIGBUS, current); -/* die_if_kernel("Oops - bad user access alignment", regs, mode, SIGBUS);*/ + force_sig(SIGBUS, current); +/* die_if_kernel("Oops - bad user access alignment", regs, mode);*/ } -asmlinkage void do_undefinstr (int address, struct pt_regs *regs, int mode) +asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode) { +#ifdef CONFIG_DEBUG_USER + printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n", + current->comm, current->pid, instruction_pointer(regs)); +#endif current->tss.error_code = 0; current->tss.trap_no = 6; - force_sig (SIGILL, current); - die_if_kernel("Oops - undefined instruction", regs, mode, SIGILL); + force_sig(SIGILL, current); + die_if_kernel("Oops - undefined instruction", regs, mode); } -asmlinkage void do_excpt (int address, struct pt_regs *regs, int mode) +asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode) { +#ifdef CONFIG_DEBUG_USER + printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n", + current->comm, current->pid, instruction_pointer(regs)); +#endif current->tss.error_code = 0; current->tss.trap_no = 11; - force_sig (SIGBUS, current); - die_if_kernel("Oops - address exception", regs, mode, SIGBUS); + force_sig(SIGBUS, current); + die_if_kernel("Oops - address exception", regs, mode); } asmlinkage void do_unexp_fiq (struct pt_regs *regs) { #ifndef CONFIG_IGNORE_FIQ - printk ("Hmm. Unexpected FIQ received, but trying to continue\n"); - printk ("You may have a hardware problem...\n"); + printk("Hmm. Unexpected FIQ received, but trying to continue\n"); + printk("You may have a hardware problem...\n"); #endif } +/* + * 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... + */ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) { - printk (KERN_CRIT "Bad mode in %s handler detected: mode %s\n", - handler[reason], - processor_modes[proc_mode]); - die_if_kernel ("Oops", regs, 0, -1); + console_verbose(); + + printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n", + handler[reason], processor_modes[proc_mode]); + + /* + * Dump out the vectors and stub routines + */ + printk(KERN_CRIT "Vectors:\n"); + dump_mem(0, 0x40); + printk(KERN_CRIT "Stubs:\n"); + dump_mem(0x200, 0x4b8); + + die("Oops", regs, 0); + cli(); + while(1); } /* @@ -249,54 +273,85 @@ */ asmlinkage void math_state_restore (void) { - current->used_math = 1; + current->used_math = 1; } -asmlinkage void arm_syscall (int no, struct pt_regs *regs) +asmlinkage int arm_syscall (int no, struct pt_regs *regs) { switch (no) { case 0: /* branch through 0 */ force_sig(SIGSEGV, current); -// if (user_mode(regs)) { -// dump_state("branch through zero", regs, 0); -// if (regs->ARM_fp) -// c_backtrace (regs->ARM_fp, processor_mode(regs)); -// } - die_if_kernel ("branch through zero", regs, 0, SIGSEGV); + die_if_kernel("branch through zero", regs, 0); break; case 1: /* SWI_BREAK_POINT */ regs->ARM_pc -= 4; /* Decrement PC by one instruction */ - ptrace_cancel_bpt (current); - force_sig (SIGTRAP, current); + ptrace_cancel_bpt(current); + force_sig(SIGTRAP, current); + return regs->ARM_r0; + + case 2: /* sys_cacheflush */ +#ifdef CONFIG_CPU_32 + /* r0 = start, r1 = length, r2 = flags */ + processor.u.armv3v4._flush_cache_area(regs->ARM_r0, + regs->ARM_r1, + 1); +#endif break; default: - printk ("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); - force_sig (SIGILL, current); + /* Calls 9f00xx..9f07ff are defined to return -ENOSYS + if not implemented, rather than raising SIGILL. This + way the calling program can gracefully determine whether + a feature is supported. */ + if (no <= 0x7ff) + return -ENOSYS; +#ifdef CONFIG_DEBUG_USER + /* experiance shows that these seem to indicate that + * something catastrophic has happened + */ + printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); if (user_mode(regs)) { - show_regs (regs); - c_backtrace (regs->ARM_fp, processor_mode(regs)); + show_regs(regs); + c_backtrace(regs->ARM_fp, processor_mode(regs)); } - die_if_kernel ("Oops", regs, no, SIGILL); +#endif + force_sig(SIGILL, current); + die_if_kernel("Oops", regs, no); break; } + return 0; } asmlinkage void deferred(int n, struct pt_regs *regs) { - dump_state("old system call", regs, n); - force_sig (SIGILL, current); + /* You might think just testing `handler' would be enough, but PER_LINUX + * points it to no_lcall7 to catch undercover SVr4 binaries. Gutted. + */ + if (current->personality != PER_LINUX && current->exec_domain->handler) { + /* Hand it off to iBCS. The extra parameter and consequent type + * forcing is necessary because of the weird ARM calling convention. + */ + void (*handler)(int nr, struct pt_regs *regs) = (void *)current->exec_domain->handler; + (*handler)(n, regs); + return; + } + +#ifdef CONFIG_DEBUG_USER + printk(KERN_ERR "[%d] %s: old system call.\n", current->pid, + current->comm); +#endif + force_sig(SIGILL, current); } asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr) { - printk ("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc); + printk("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc); } -asmlinkage void arm_invalidptr (const char *function, int size) +asmlinkage void arm_invalidptr(const char *function, int size) { - printk ("Invalid pointer size in %s (PC=%p) size %d\n", + printk("Invalid pointer size in %s (pc=%p) size %d\n", function, __builtin_return_address(0), size); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.2.17/arch/arm/lib/Makefile Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/Makefile Fri Sep 15 23:28:37 2000 @@ -1,19 +1,25 @@ # # linux/arch/arm/lib/Makefile # -# Copyright (C) 1995-1998 Russell King +# Copyright (C) 1995-1999 Russell King # L_TARGET := lib.a -L_OBJS := backtrace.o bitops.o checksum.o delay.o io.o memcpy.o \ - system.o string.o uaccess.o +L_OBJS := changebit.o checksum.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 \ + semaphore.o system.o uaccess.o + +O_TARGET := lib.o +O_OBJS := backtrace.o delay.o ifeq ($(PROCESSOR),armo) L_OBJS += uaccess-armo.o endif ifdef CONFIG_ARCH_ACORN - L_OBJS += loaders.o ll_char_wr.o io-acorn.o + L_OBJS += io-acorn.o ifdef CONFIG_ARCH_A5K L_OBJS += floppydma.o endif @@ -24,31 +30,23 @@ ifeq ($(MACHINE),ebsa110) L_OBJS += io-ebsa110.o +else + OX_OBJS += io.o endif -ifeq ($(MACHINE),vnc) - L_OBJS += io-ebsa285.o -endif - -ifeq ($(MACHINE),ebsa285) - L_OBJS += io-ebsa285.o +ifeq ($(MACHINE),footbridge) + L_OBJS += io-footbridge.o endif include $(TOPDIR)/Rules.make +%.o: %.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< + constants.h: getconsdata.o extractconstants.pl $(PERL) extractconstants.pl $(OBJDUMP) > $@ getconsdata.o: getconsdata.c $(CC) $(CFLAGS) -c getconsdata.c -checksum.o: constants.h - -%.o: %.S -ifneq ($(CONFIG_BINUTILS_NEW),y) - $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.$<.s - $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.$<.s - $(RM) ..tmp.$<.s -else - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< -endif +checksum.o string.o: constants.h diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/backtrace.S linux/arch/arm/lib/backtrace.S --- v2.2.17/arch/arm/lib/backtrace.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/backtrace.S Fri Sep 15 23:28:37 2000 @@ -21,6 +21,11 @@ mov r0, fp ENTRY(c_backtrace) + +#ifndef CONFIG_FRAME_POINTER + mov pc, lr +#else + stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... #ifdef CONFIG_CPU_32 tst r1, #0x10 @ 26 or 32-bit? @@ -55,14 +60,14 @@ sub r0, frame, #16 ldr r1, [save, #4] - mov r3, r1, lsr #10 + mov r3, r1, lsr #11 ldr r2, .Ldsi+4 teq r3, r2 @ Check for stmia sp!, {args} addeq save, save, #4 @ next instruction bleq .Ldumpstm ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction - mov r3, r1, lsr #10 + mov r3, r1, lsr #11 ldr r2, .Ldsi teq r3, r2 bleq .Ldumpstm @@ -78,28 +83,36 @@ #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 reg, #10 + 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 +.Ldsi: .word 0x00e92dd8 >> 3 + .word 0x00e92d00 >> 3 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/bitops.S linux/arch/arm/lib/bitops.S --- v2.2.17/arch/arm/lib/bitops.S Fri Apr 21 12:45:45 2000 +++ 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/changebit.S linux/arch/arm/lib/changebit.S --- v2.2.17/arch/arm/lib/changebit.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/changebit.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/checksum.S linux/arch/arm/lib/checksum.S --- v2.2.17/arch/arm/lib/checksum.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/checksum.S Fri Sep 15 23:28:37 2000 @@ -74,8 +74,9 @@ stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc} .endm -#define LOAD_REGS(cond) \ - LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r8, fp, sp, pc}) + .macro load_regs,flags + ldm\flags fp, {r1, r2, r4-r8, fp, sp, pc} + .endm .macro load1b, reg1 9999: ldrbt \reg1, [r0], $1 @@ -130,12 +131,13 @@ 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] + ldr r9, [r9, #ADDR_LIMIT] mov r9, r9, lsr #24 .endm -#define LOAD_REGS(cond) \ - LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r9, fp, sp, pc}) + .macro load_regs,flags + ldm\flags fp, {r1, r2, r4-r9, fp, sp, pc}^ + .endm .macro load1b, reg1 tst r9, #0x01 @@ -245,7 +247,7 @@ adcs r3, r3, r4 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + load_regs eqea load1l r4 tst r2, #2 beq .exit @@ -259,11 +261,11 @@ andne r4, r4, #255 adcnes r3, r3, r4 adcs r0, r3, #0 - LOAD_REGS(al) + load_regs ea .too_small_user: teq r2, #0 - LOAD_REGS(eq) + load_regs eqea cmp r2, #2 blt .too_small_user1 load2b ip, r8 @@ -278,7 +280,7 @@ strb ip, [r1], #1 adcs r3, r3, ip .csum_exit: adc r0, r3, #0 - LOAD_REGS(al) + load_regs ea .src_not_aligned_user: cmp r2, #4 @@ -331,7 +333,7 @@ mov r4, r5, lsr #8 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + load_regs eqea tst r2, #2 beq .exit adcs r3, r3, r4, lsl #16 @@ -384,13 +386,16 @@ mov r4, r5, lsr #16 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + 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 @@ -437,7 +442,7 @@ mov r4, r5, lsr #24 4: ands r2, r2, #3 adceq r0, r3, #0 - LOAD_REGS(eq) + load_regs eqea tst r2, #2 beq .exit adcs r3, r3, r4, lsl #16 @@ -461,7 +466,7 @@ 6002: teq r2, r1 strneb r3, [r1], #1 bne 6002b - LOAD_REGS(al) + load_regs ea #if defined(CONFIG_CPU_32) .previous #endif @@ -520,13 +525,13 @@ LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) ldr r4, [r0], #4 tst r2, #2 - beq Lexit + 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 + b Lexit_r4 Ltoo_small: teq r2, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) @@ -538,10 +543,12 @@ adds r3, r3, ip strb ip, [r1], #1 strb r8, [r1], #1 -Lexit: tst r2, #1 -Ltoo_small1: ldrneb ip, [r0], #1 - strneb ip, [r1], #1 - adcnes r3, r3, ip + 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}) @@ -598,13 +605,13 @@ adceq r0, r3, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) tst r2, #2 - beq Lexit + 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 + b Lexit_r4 Lsrc2_aligned: mov r4, r4, lsr #16 adds r3, r3, #0 @@ -650,13 +657,13 @@ adceq r0, r3, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) tst r2, #2 - beq Lexit + 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 + b Lexit_r4 Lsrc3_aligned: mov r4, r4, lsr #24 adds r3, r3, #0 @@ -702,14 +709,14 @@ adceq r0, r3, #0 LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) tst r2, #2 - beq Lexit + 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 + b Lexit_r4 ENTRY(__csum_ipv6_magic) stmfd sp!, {lr} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/clearbit.S linux/arch/arm/lib/clearbit.S --- v2.2.17/arch/arm/lib/clearbit.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/clearbit.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/copy_page.S linux/arch/arm/lib/copy_page.S --- v2.2.17/arch/arm/lib/copy_page.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/copy_page.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/delay.S linux/arch/arm/lib/delay.S --- v2.2.17/arch/arm/lib/delay.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/delay.S Mon Oct 2 10:11:32 2000 @@ -7,7 +7,7 @@ #include .text -LC0: .word SYMBOL_NAME(loops_per_sec) +LC0: .word SYMBOL_NAME(loops_per_jiffy) ENTRY(udelay) mov r2, #0x1000 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/findbit.S linux/arch/arm/lib/findbit.S --- v2.2.17/arch/arm/lib/findbit.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/findbit.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/floppydma.S linux/arch/arm/lib/floppydma.S --- v2.2.17/arch/arm/lib/floppydma.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/floppydma.S Fri Sep 15 23:28:37 2000 @@ -26,32 +26,3 @@ strb r12, [r11, #-4] subs pc, lr, #4 SYMBOL_NAME(floppy_fiqout_end): - -@ Params: -@ r0 = length -@ r1 = address -@ r2 = floppy port -@ Puts these into R9_fiq, R10_fiq, R11_fiq -ENTRY(floppy_fiqsetup) - mov ip, sp - stmfd sp!, {fp, ip, lr, pc} - sub fp, ip, #4 - MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode - mov r0, r0 - mov r9, r0 - mov r10, r1 - mov r11, r2 - RESTOREMODE(r3) @ back to normal - mov r0, r0 - LOADREGS(ea,fp,{fp, sp, pc}) - -ENTRY(floppy_fiqresidual) - mov ip, sp - stmfd sp!, {fp, ip, lr, pc} - sub fp, ip, #4 - MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode - mov r0, r0 - mov r0, r9 - RESTOREMODE(r3) - mov r0, r0 - LOADREGS(ea,fp,{fp, sp, pc}) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c --- v2.2.17/arch/arm/lib/getconsdata.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/getconsdata.c Fri Sep 15 23:28:37 2000 @@ -10,23 +10,25 @@ #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) #define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n) -#ifdef KERNEL_DOMAIN -unsigned long DOM_KERNELDOMAIN = KERNEL_DOMAIN; -#endif -#ifdef USER_DOMAIN -unsigned long DOM_USERDOMAIN = USER_DOMAIN; -#endif - unsigned long TSK_STATE = OFF_TSK(state); unsigned long TSK_FLAGS = OFF_TSK(flags); unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched); unsigned long TSK_SIGPENDING = OFF_TSK(sigpending); -unsigned long TSK_ADDR_LIMIT = OFF_TSK(addr_limit); unsigned long TSK_USED_MATH = OFF_TSK(used_math); unsigned long MM = OFF_TSK(mm); @@ -36,8 +38,12 @@ unsigned long TSS_SAVE = OFF_TSK(tss.save); unsigned long TSS_FPESAVE = OFF_TSK(tss.fpstate.soft.save); #ifdef CONFIG_CPU_26 +unsigned long ADDR_LIMIT = OFF_TSK(addr_limit); unsigned long TSS_MEMCMAP = OFF_TSK(tss.memcmap); #endif +#ifdef CONFIG_CPU_32 +unsigned long TSS_DOMAIN = OFF_TSK(tss.domain); +#endif #ifdef _PAGE_PRESENT unsigned long PAGE_PRESENT = _PAGE_PRESENT; @@ -66,6 +72,25 @@ #ifdef _PAGE_CLEAN unsigned long PAGE_CLEAN = _PAGE_CLEAN; #endif + +#ifdef PTE_TYPE_SMALL +unsigned long HPTE_TYPE_SMALL = PTE_TYPE_SMALL; +unsigned long HPTE_AP_READ = PTE_AP_READ; +unsigned long HPTE_AP_WRITE = PTE_AP_WRITE; +#endif + +#ifdef L_PTE_PRESENT +unsigned long LPTE_PRESENT = L_PTE_PRESENT; +unsigned long LPTE_YOUNG = L_PTE_YOUNG; +unsigned long LPTE_BUFFERABLE = L_PTE_BUFFERABLE; +unsigned long LPTE_CACHEABLE = L_PTE_CACHEABLE; +unsigned long LPTE_USER = L_PTE_USER; +unsigned long LPTE_WRITE = L_PTE_WRITE; +unsigned long LPTE_EXEC = L_PTE_EXEC; +unsigned long LPTE_DIRTY = L_PTE_DIRTY; +#endif + +unsigned long PAGE_SZ = PAGE_SIZE; unsigned long KSWI_BASE = 0x900000; unsigned long KSWI_SYS_BASE = 0x9f0000; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S --- v2.2.17/arch/arm/lib/io-acorn.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/io-acorn.S Fri Sep 15 23:28:37 2000 @@ -11,50 +11,514 @@ .text .align -#define OUT(reg) \ - mov r8, reg, lsl $16 ;\ - orr r8, r8, r8, lsr $16 ;\ - str r8, [r3, r0, lsl $2] ;\ - mov r8, reg, lsr $16 ;\ - orr r8, r8, r8, lsl $16 ;\ - str r8, [r3, r0, lsl $2] - -#define IN(reg) \ - ldr reg, [r0] ;\ - and reg, reg, ip ;\ - ldr lr, [r0] ;\ - orr reg, reg, lr, lsl $16 - - .equ pcio_base_high, PCIO_BASE & 0xff000000 - .equ pcio_base_low, PCIO_BASE & 0x00ff0000 - .equ io_base_high, IO_BASE & 0xff000000 - .equ io_base_low, IO_BASE & 0x00ff0000 - - .equ addr_io_diff_hi, pcio_base_high - io_base_high - .equ addr_io_diff_lo, pcio_base_low - io_base_low - - .macro addr reg, off - tst \off, #0x80000000 - .if addr_io_diff_hi - movne \reg, #IO_BASE - moveq \reg, #pcio_base_high - .if pcio_base_low - addeq \reg, \reg, #pcio_base_low - .endif - .else - mov \reg, #IO_BASE - addeq \reg, \reg, #addr_io_diff_lo - .endif + .equ diff_pcio_base, PCIO_BASE - IO_BASE + + .macro outw2 rd + mov r8, \rd, lsl #16 + orr r8, r8, r8, lsr #16 + str r8, [r3, r0, lsl #2] + mov r8, \rd, lsr #16 + orr r8, r8, r8, lsl #16 + str r8, [r3, r0, lsl #2] + .endm + + .macro inw2 rd, mask, temp + ldr \rd, [r0] + and \rd, \rd, \mask + ldr \temp, [r0] + orr \rd, \rd, \temp, lsl #16 + .endm + + .macro addr rd + tst \rd, #0x80000000 + mov \rd, \rd, lsl #2 + add \rd, \rd, #IO_BASE + addeq \rd, \rd, #diff_pcio_base .endm -@ Purpose: read a block of data from a hardware register to memory. -@ Proto : insw(int from_port, void *to, int len_in_words); -@ Proto : inswb(int from_port, void *to, int len_in_bytes); -@ Notes : increment to +.iosw_bad_align_msg: + .ascii "insw: bad buffer alignment (%p), called from %08lX\n\0" +.iosl_warning: + .ascii "<4>insl/outsl not implemented, called from %08lX\0" + .align + +/* + * These make no sense on Acorn machines. + * Print a warning message. + */ +ENTRY(insl) +ENTRY(outsl) + adr r0, .iosl_warning + mov r1, lr + b SYMBOL_NAME(printk) + +.iosw_bad_alignment: + adr r0, .iosw_bad_align_msg + mov r2, lr + b SYMBOL_NAME(panic) + + +/* Purpose: read a block of data from a hardware register to memory. + * Proto : void insw(int from_port, void *to, int len_in_words); + * Notes : increment to, 'to' must be 16-bit aligned + */ + +.insw_align: tst r1, #1 + bne .iosw_bad_alignment + + ldr r3, [r0] + strb r3, [r1], #1 + mov r3, r3, lsr #8 + strb r3, [r1], #1 + + subs r2, r2, #1 + bne .insw_aligned ENTRY(insw) + teq r2, #0 + RETINSTR(moveq,pc,lr) + addr r0 + tst r1, #3 + bne .insw_align + +.insw_aligned: mov ip, #0xff + orr ip, ip, ip, lsl #8 + stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_insw_8 + +.insw_8_lp: ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + ldr r5, [r0] + and r5, r5, ip + ldr r6, [r0] + orr r5, r5, r6, lsl #16 + + ldr r6, [r0] + and r6, r6, ip + ldr lr, [r0] + orr r6, r6, lr, lsl #16 + + stmia r1!, {r3 - r6} + subs r2, r2, #8 + bpl .insw_8_lp + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_insw_8: tst r2, #4 + beq .no_insw_4 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + stmia r1!, {r3, r4} + +.no_insw_4: tst r2, #2 + beq .no_insw_2 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + str r3, [r1], #4 + +.no_insw_2: tst r2, #1 + ldrne r3, [r0] + strneb r3, [r1], #1 + movne r3, r3, lsr #8 + strneb r3, [r1] + LOADREGS(fd, sp!, {r4, r5, r6, pc}) + +@ Purpose: write a block of data from memory to a hardware register. +@ Proto : outsw(int to_reg, void *from, int len_in_words); +@ Notes : increments from + +.outsw_align: tst r1, #1 + bne .iosw_bad_alignment + + add r1, r1, #2 + + ldr r3, [r1, #-4] + mov r3, r3, lsr #16 + orr r3, r3, r3, lsl #16 + str r3, [r0] + subs r2, r2, #1 + bne .outsw_aligned + +ENTRY(outsw) + teq r2, #0 + RETINSTR(moveq,pc,lr) + addr r0 + tst r1, #3 + bne .outsw_align + +.outsw_aligned: stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_outsw_8 +.outsw_8_lp: ldmia r1!, {r3, r4, r5, r6} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r5, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r5, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r6, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r6, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + subs r2, r2, #8 + bpl .outsw_8_lp + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_outsw_8: tst r2, #4 + beq .no_outsw_4 + + ldmia r1!, {r3, r4} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_4: tst r2, #2 + beq .no_outsw_2 + + ldr r3, [r1], #4 + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_2: tst r2, #1 + + ldrne r3, [r1] + + movne ip, r3, lsl #16 + orrne ip, ip, ip, lsr #16 + strne ip, [r0] + + LOADREGS(fd, sp!, {r4, r5, r6, pc}) + +.insb_align: rsb ip, ip, #4 + cmp ip, r2 + movgt ip, r2 + cmp ip, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1], #1 + subs r2, r2, ip + bne .insb_aligned + +ENTRY(insb) + teq r2, #0 + moveq pc, lr + addr r0 + ands ip, r1, #3 + bne .insb_align + +.insb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .insb_no_16 + +.insb_16_lp: ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + ldrb r5, [r0] + ldrb r6, [r0] + orr r5, r5, r6, lsl #8 + ldrb r6, [r0] + orr r5, r5, r6, lsl #16 + ldrb r6, [r0] + orr r5, r5, r6, lsl #24 + ldrb r6, [r0] + ldrb ip, [r0] + orr r6, r6, ip, lsl #8 + ldrb ip, [r0] + orr r6, r6, ip, lsl #16 + ldrb ip, [r0] + orr r6, r6, ip, lsl #24 + stmia r1!, {r3 - r6} + subs r2, r2, #16 + bpl .insb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.insb_no_16: tst r2, #8 + beq .insb_no_8 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + stmia r1!, {r3, r4} + +.insb_no_8: tst r2, #4 + bne .insb_no_4 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + str r3, [r1], #4 + +.insb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1] + LOADREGS(fd, sp!, {r4 - r6, pc}) + + + +.outsb_align: rsb ip, ip, #4 + cmp ip, r2 + mov ip, r2 + cmp ip, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1], #1 + strgtb r3, [r0] + subs r2, r2, ip + bne .outsb_aligned + +ENTRY(outsb) + teq r2, #0 + moveq pc, lr + addr r0 + ands ip, r1, #3 + bne .outsb_align + +.outsb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .outsb_no_16 + +.outsb_16_lp: ldmia r1!, {r3 - r6} + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + subs r2, r2, #16 + bpl .outsb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.outsb_no_16: tst r2, #8 + beq .outsb_no_8 + + ldmia r1, {r3, r4} + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + +.outsb_no_8: tst r2, #4 + bne .outsb_no_4 + + ldr r3, [r1], #4 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + +.outsb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1] + strgtb r3, [r0] + LOADREGS(fd, sp!, {r4 - r6, pc}) + + + + +@ Purpose: write a memc register +@ Proto : void memc_write(int register, int value); +@ Returns: nothing + +#if defined(CONFIG_CPU_26) +ENTRY(memc_write) + cmp r0, #7 + RETINSTR(movgt,pc,lr) + mov r0, r0, lsl #17 + mov r1, r1, lsl #15 + mov r1, r1, lsr #17 + orr r0, r0, r1, lsl #2 + add r0, r0, #0x03600000 + strb r0, [r0] + RETINSTR(mov,pc,lr) +#define CPSR2SPSR(rt) +#else +#define CPSR2SPSR(rt) \ + mrs rt, cpsr; \ + msr spsr, rt +#endif + +@ Purpose: call an expansion card loader to read bytes. +@ Proto : char read_loader(int offset, char *card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_read) + stmfd sp!, {r4 - r12, lr} + mov r11, r1 + mov r1, r0 + CPSR2SPSR(r0) + mov lr, pc + mov pc, r2 + LOADREGS(fd, sp!, {r4 - r12, pc}) + +@ Purpose: call an expansion card loader to reset the card +@ Proto : void read_loader(int card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_reset) + stmfd sp!, {r4 - r12, lr} + mov r11, r0 + CPSR2SPSR(r0) + mov lr, pc + add pc, r1, #8 + LOADREGS(fd, sp!, {r4 - r12, pc}) + + +#if 0 mov r2, r2, lsl#1 -ENTRY(inswb) mov ip, sp stmfd sp!, {r4 - r10, fp, ip, lr, pc} sub fp, ip, #4 @@ -122,14 +586,9 @@ bgt Linsw_notaligned LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) -@ Purpose: write a block of data from memory to a hardware register. -@ Proto : outsw(int to_reg, void *from, int len_in_words); -@ Proto : outswb(int to_reg, void *from, int len_in_bytes); -@ Notes : increments from ENTRY(outsw) - mov r2, r2, LSL#1 -ENTRY(outswb) + mov r2, r2, lsl#1 mov ip, sp stmfd sp!, {r4 - r8, fp, ip, lr, pc} sub fp, ip, #4 @@ -166,56 +625,5 @@ bgt 3b LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) -/* - * These make no sense on Acorn machines atm. - */ -ENTRY(insl) -ENTRY(outsl) - RETINSTR(mov,pc,lr) - -@ Purpose: write a memc register -@ Proto : void memc_write(int register, int value); -@ Returns: nothing - -#if defined(CONFIG_CPU_26) -ENTRY(memc_write) - cmp r0, #7 - RETINSTR(movgt,pc,lr) - mov r0, r0, lsl #17 - mov r1, r1, lsl #15 - mov r1, r1, lsr #17 - orr r0, r0, r1, lsl #2 - add r0, r0, #0x03600000 - strb r0, [r0] - RETINSTR(mov,pc,lr) -#define CPSR2SPSR(rt) -#else -#define CPSR2SPSR(rt) \ - mrs rt, cpsr; \ - msr spsr, rt #endif -@ Purpose: call an expansion card loader to read bytes. -@ Proto : char read_loader(int offset, char *card_base, char *loader); -@ Returns: byte read - -ENTRY(ecard_loader_read) - stmfd sp!, {r4 - r12, lr} - mov r11, r1 - mov r1, r0 - CPSR2SPSR(r0) - mov lr, pc - mov pc, r2 - LOADREGS(fd, sp!, {r4 - r12, pc}) - -@ Purpose: call an expansion card loader to reset the card -@ Proto : void read_loader(int card_base, char *loader); -@ Returns: byte read - -ENTRY(ecard_loader_reset) - stmfd sp!, {r4 - r12, lr} - mov r11, r0 - CPSR2SPSR(r0) - mov lr, pc - add pc, r1, #8 - LOADREGS(fd, sp!, {r4 - r12, pc}) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/io-ebsa110.S linux/arch/arm/lib/io-ebsa110.S --- v2.2.17/arch/arm/lib/io-ebsa110.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/io-ebsa110.S Fri Sep 15 23:28:37 2000 @@ -22,6 +22,22 @@ ldr lr, [r0] ;\ orr reg, reg, lr, lsl $16 +/* + * These make no sense on these machines. + * Print a warning message. + */ +ENTRY(insl) +ENTRY(outsl) +ENTRY(insb) +ENTRY(outsb) + adr r0, io_long_warning + mov r1, lr + b SYMBOL_NAME(printk) + +io_long_warning: + .ascii "<4>ins?/outs? not implemented on this architecture\0" + .align + @ Purpose: read a block of data from a hardware register to memory. @ Proto : insw(int from_port, void *to, int len_in_words); @ Proto : inswb(int from_port, void *to, int len_in_bytes); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/io-ebsa285.S linux/arch/arm/lib/io-ebsa285.S --- v2.2.17/arch/arm/lib/io-ebsa285.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/io-ebsa285.S Thu Jan 1 01:00:00 1970 @@ -1,197 +0,0 @@ -#include - -ENTRY(insl) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 - ands ip, r1, #3 - bne 2f - -1: ldr r3, [r0] - str r3, [r1], #4 - subs r2, r2, #1 - bne 1b - mov pc, lr - -2: cmp ip, #2 - ldr ip, [r0] - blt 3f - bgt 4f - - strh ip, [r1], #2 - mov ip, ip, lsr #16 -1: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #16 - strne ip, [r1], #4 - movne ip, r3, lsr #16 - bne 1b - strh ip, [r1], #2 - mov pc, lr - -3: strb ip, [r1], #1 - mov ip, ip, lsr #8 - strh ip, [r1], #2 - mov ip, ip, lsr #16 -1: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #8 - strne ip, [r1], #4 - movne ip, r3, lsr #24 - bne 1b - strb ip, [r1], #1 - mov pc, lr - -4: strb ip, [r1], #1 - mov ip, ip, lsr #8 -1: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #24 - strne ip, [r1], #4 - movne ip, r3, lsr #8 - bne 1b - strb ip, [r1], #1 - mov ip, ip, lsr #8 - strh ip, [r1], #2 - mov pc, lr - -ENTRY(outsl) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 - ands ip, r1, #3 - bne 2f - -1: ldr r3, [r1], #4 - str r3, [r0] - subs r2, r2, #1 - bne 1b - mov pc, lr - -2: bic r1, r1, #3 - cmp ip, #2 - ldr ip, [r1], #4 - mov ip, ip, lsr #16 - blt 3f - bgt 4f - -1: ldr r3, [r1], #4 - orr ip, ip, r3, lsl #16 - str ip, [r0] - mov ip, r3, lsr #16 - subs r2, r2, #1 - bne 1b - mov pc, lr - -3: ldr r3, [r1], #4 - orr ip, ip, r3, lsl #8 - str ip, [r0] - mov ip, r3, lsr #24 - subs r2, r2, #1 - bne 3b - mov pc, lr - -4: ldr r3, [r1], #4 - orr ip, ip, r3, lsl #24 - str ip, [r0] - mov ip, r3, lsr #8 - subs r2, r2, #1 - bne 4b - mov pc, lr - - /* Nobody could say these are optimal, but not to worry. */ - -ENTRY(outswb) - mov r2, r2, lsr #1 -ENTRY(outsw) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 -1: subs r2, r2, #1 - ldrgeh r3, [r1], #2 - strgeh r3, [r0] - bgt 1b - mov pc, lr - -ENTRY(inswb) - mov r2, r2, lsr #1 -ENTRY(insw) - stmfd sp!, {r4, r5, lr} - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 - @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 - subs ip, r2, #8 - blo too_little - @ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 - ands lr, r1, #3 @ check alignment - beq 1f - - ldrh r3, [r0] - strh r3, [r1], #2 - sub ip, ip, #1 - cmn ip, #8 - blo too_little - -1: ldrh r2, [r0] - ldrh r3, [r0] - orr r2, r2, r3, lsl #16 - ldrh r3, [r0] - ldrh r4, [r0] - orr r3, r3, r4, lsl #16 - ldrh r4, [r0] - ldrh r5, [r0] - orr r4, r4, r5, lsl #16 - ldrh r5, [r0] - ldrh lr, [r0] - orr r5, r5, lr, lsl #16 - stmia r1!, {r2, r3, r4, r5} - subs ip, ip, #8 - @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 + 0 + 1 - bhs 1b - @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 8 - 7 - cmn ip, #4 - ldrhsh r2, [r0] @ ... ... ... ... - 4 - 3 - 2 - 1 ... ... - ldrhsh r3, [r0] - orrhs r2, r2, r3, lsl #16 - ldrhsh r3, [r0] - ldrhsh r4, [r0] - orrhs r3, r3, r4, lsl #16 - stmhsia r1!, {r2, r3} - - tst ip, #2 - ldrneh r2, [r0] @ ... ... - 6 - 5 ... ... - 2 - 1 ... ... - ldrneh r3, [r0] - orrne r2, r2, r3, lsl #16 - strne r2, [r1], #4 - - tst ip, #1 - ldrneh r2, [r0] - strneh r2, [r1], #2 - - ldmfd sp!, {r4, r5, pc} - -too_little: subs r2, r2, #1 - ldrgeh r3, [r0] - strgeh r3, [r1], #2 - bgt too_little - - ldmfd sp!, {r4, r5, pc} - - -ENTRY(insb) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 -1: teq r2, #0 - ldrneb r3, [r0] - strneb r3, [r1], #1 - subne r2, r2, #1 - bne 1b - mov pc, lr - - -ENTRY(outsb) - add r0, r0, #0xff000000 - add r0, r0, #0x00e00000 -1: teq r2, #0 - ldrneb r3, [r1], #1 - strneb r3, [r0] - subne r2, r2, #1 - bne 1b - mov pc, lr diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/io-footbridge.S linux/arch/arm/lib/io-footbridge.S --- v2.2.17/arch/arm/lib/io-footbridge.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/io-footbridge.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,202 @@ +#include +#include + + .equ pcio_high, PCIO_BASE & 0xff000000 + .equ pcio_low, PCIO_BASE & 0x00ffffff + + .macro ioaddr, rd,rn + add \rd, \rn, #pcio_high + .if pcio_low + add \rd, \rd, #pcio_low + .endif + .endm + +ENTRY(insl) + ioaddr r0, r0 + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r0] + str r3, [r1], #4 + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: cmp ip, #2 + ldr ip, [r0] + blt 4f + bgt 6f + + strh ip, [r1], #2 + mov ip, ip, lsr #16 +3: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #16 + strne ip, [r1], #4 + movne ip, r3, lsr #16 + bne 3b + strh ip, [r1], #2 + mov pc, lr + +4: strb ip, [r1], #1 + mov ip, ip, lsr #8 + strh ip, [r1], #2 + mov ip, ip, lsr #16 +5: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #8 + strne ip, [r1], #4 + movne ip, r3, lsr #24 + bne 5b + strb ip, [r1], #1 + mov pc, lr + +6: strb ip, [r1], #1 + mov ip, ip, lsr #8 +7: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #24 + strne ip, [r1], #4 + movne ip, r3, lsr #8 + bne 7b + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strh ip, [r1], #2 + mov pc, lr + +ENTRY(outsl) + ioaddr r0, r0 + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r1], #4 + str r3, [r0] + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: bic r1, r1, #3 + cmp ip, #2 + ldr ip, [r1], #4 + mov ip, ip, lsr #16 + blt 4f + bgt 5f + +3: ldr r3, [r1], #4 + orr ip, ip, r3, lsl #16 + str ip, [r0] + mov ip, r3, lsr #16 + subs r2, r2, #1 + bne 3b + mov pc, lr + +4: ldr r3, [r1], #4 + orr ip, ip, r3, lsl #8 + str ip, [r0] + mov ip, r3, lsr #24 + subs r2, r2, #1 + bne 4b + mov pc, lr + +5: ldr r3, [r1], #4 + orr ip, ip, r3, lsl #24 + str ip, [r0] + mov ip, r3, lsr #8 + subs r2, r2, #1 + bne 5b + mov pc, lr + + /* Nobody could say these are optimal, but not to worry. */ + +ENTRY(outswb) + mov r2, r2, lsr #1 +ENTRY(outsw) + ioaddr r0, r0 +1: subs r2, r2, #1 + ldrgeh r3, [r1], #2 + strgeh r3, [r0] + bgt 1b + mov pc, lr + +ENTRY(inswb) + mov r2, r2, lsr #1 +ENTRY(insw) + stmfd sp!, {r4, r5, lr} + ioaddr r0, r0 + @ + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 + subs ip, r2, #8 + blo too_little + @ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + ands lr, r1, #3 @ check alignment + beq 1f + + ldrh r3, [r0] + strh r3, [r1], #2 + sub ip, ip, #1 + cmn ip, #8 + blo too_little + +1: ldrh r2, [r0] + ldrh r3, [r0] + orr r2, r2, r3, lsl #16 + ldrh r3, [r0] + ldrh r4, [r0] + orr r3, r3, r4, lsl #16 + ldrh r4, [r0] + ldrh r5, [r0] + orr r4, r4, r5, lsl #16 + ldrh r5, [r0] + ldrh lr, [r0] + orr r5, r5, lr, lsl #16 + stmia r1!, {r2, r3, r4, r5} + subs ip, ip, #8 + @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 + 0 + 1 + bhs 1b + @ - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 8 - 7 + cmn ip, #4 + ldrhsh r2, [r0] @ ... ... ... ... - 4 - 3 - 2 - 1 ... ... + ldrhsh r3, [r0] + orrhs r2, r2, r3, lsl #16 + ldrhsh r3, [r0] + ldrhsh r4, [r0] + orrhs r3, r3, r4, lsl #16 + stmhsia r1!, {r2, r3} + + tst ip, #2 + ldrneh r2, [r0] @ ... ... - 6 - 5 ... ... - 2 - 1 ... ... + ldrneh r3, [r0] + orrne r2, r2, r3, lsl #16 + strne r2, [r1], #4 + + tst ip, #1 + ldrneh r2, [r0] + strneh r2, [r1], #2 + + ldmfd sp!, {r4, r5, pc} + +too_little: subs r2, r2, #1 + ldrgeh r3, [r0] + strgeh r3, [r1], #2 + bgt too_little + + ldmfd sp!, {r4, r5, pc} + + +ENTRY(insb) + ioaddr r0, r0 +1: teq r2, #0 + ldrneb r3, [r0] + strneb r3, [r1], #1 + subne r2, r2, #1 + bne 1b + mov pc, lr + + +ENTRY(outsb) + ioaddr r0, r0 +1: teq r2, #0 + ldrneb r3, [r1], #1 + strneb r3, [r0] + subne r2, r2, #1 + bne 1b + mov pc, lr diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/io.c linux/arch/arm/lib/io.c --- v2.2.17/arch/arm/lib/io.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/io.c Fri Sep 15 23:28:37 2000 @@ -1,3 +1,5 @@ +#include + #include /* @@ -18,7 +20,7 @@ * Copy data from "real" memory space to IO memory space. * This needs to be optimized. */ -void _memcpy_toio(unsigned long to, void * from, unsigned long count) +void _memcpy_toio(unsigned long to, const void * from, unsigned long count) { while (count) { count--; @@ -40,3 +42,7 @@ dst++; } } + +EXPORT_SYMBOL(_memcpy_fromio); +EXPORT_SYMBOL(_memcpy_toio); +EXPORT_SYMBOL(_memset_io); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/ll_char_wr.S linux/arch/arm/lib/ll_char_wr.S --- v2.2.17/arch/arm/lib/ll_char_wr.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/ll_char_wr.S Thu Jan 1 01:00:00 1970 @@ -1,158 +0,0 @@ -/* - * linux/arch/arm/lib/ll_char_wr.S - * - * Copyright (C) 1995, 1996 Russell King. - * - * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King. - * - * 10-04-96 RMK Various cleanups & reduced register usage. - * 08-04-98 RMK Shifts re-ordered - */ - -@ Regs: [] = corruptible -@ {} = used -@ () = do not use - -#include -#include - .text - -#define BOLD 0x01 -#define ITALIC 0x02 -#define UNDERLINE 0x04 -#define FLASH 0x08 -#define INVERSE 0x10 - -LC0: .word SYMBOL_NAME(bytes_per_char_h) - .word SYMBOL_NAME(video_size_row) - .word SYMBOL_NAME(cmap_80) - .word SYMBOL_NAME(con_charconvtable) - -ENTRY(ll_write_char) - stmfd sp!, {r4 - r7, lr} -@ -@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) -@ - eor ip, r1, #UNDERLINE << 9 -/* - * calculate colours - */ - tst r1, #INVERSE << 9 - moveq r2, r1, lsr #16 - moveq r3, r1, lsr #24 - movne r2, r1, lsr #24 - movne r3, r1, lsr #16 - and r3, r3, #255 - and r2, r2, #255 -/* - * calculate offset into character table - */ - mov r1, r1, lsl #23 - mov r1, r1, lsr #20 -/* - * calculate offset required for each row [maybe I should make this an argument to this fn. - * Have to see what the register usage is like in the calling routines. - */ - adr r4, LC0 - ldmia r4, {r4, r5, r6, lr} - ldr r4, [r4] - ldr r5, [r5] -/* - * Go to resolution-dependent routine... - */ - cmp r4, #4 - blt Lrow1bpp - eor r2, r3, r2 @ Create eor mask to change colour from bg - orr r3, r3, r3, lsl #8 @ to fg. - orr r3, r3, r3, lsl #16 - add r0, r0, r5, lsl #3 @ Move to bottom of character - add r1, r1, #7 - ldrb r7, [r6, r1] - tst ip, #UNDERLINE << 9 - eoreq r7, r7, #255 - teq r4, #8 - beq Lrow8bpplp -@ -@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) -@ - orr r3, r3, r3, lsl #4 -Lrow4bpplp: ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow4bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) - -@ -@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) -@ -Lrow8bpplp: mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow8bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) - -@ -@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) -@ -Lrow1bpp: add r6, r6, r1 - ldmia r6, {r4, r7} - tst ip, #INVERSE << 9 - mvnne r4, r4 - mvnne r7, r7 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - tst ip, #UNDERLINE << 9 - mvneq r7, r7 - strb r7, [r0], r5 - LOADREGS(fd, sp!, {r4 - r7, pc}) - - .bss -ENTRY(con_charconvtable) - .space 1024 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/loaders.S linux/arch/arm/lib/loaders.S --- v2.2.17/arch/arm/lib/loaders.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/loaders.S Thu Jan 1 01:00:00 1970 @@ -1,53 +0,0 @@ -/* - * linux/arch/arm/lib/loaders.S - * - * This file contains the ROM loaders for buggy cards - */ -#include -#include - -/* - * Oak SCSI - */ - -ENTRY(oak_scsi_loader) - b Loak_scsi_read - .word 0 -Loak_scsi_reset: bic r10, r11, #0x00ff0000 - ldr r2, [r10] - RETINSTR(mov,pc,lr) - -Loak_scsi_read: mov r2, r1, lsr #3 - and r2, r2, #15 << 9 - bic r10, r11, #0x00ff0000 - ldr r2, [r10, r2] - mov r2, r1, lsl #20 - ldrb r0, [r11, r2, lsr #18] - ldr r2, [r10] - RETINSTR(mov,pc,lr) - -ENTRY(atomwide_serial_loader) - b Latomwide_serial_read - .word 0 -Latomwide_serial_reset: mov r2, #0x3c00 - strb r2, [r11, r2] - RETINSTR(mov,pc,lr) - -Latomwide_serial_read: cmp r1, #0x8000 - RETINSTR(movhi,pc,lr) - add r0, r1, #0x800 - mov r0, r0, lsr #11 - mov r3, #0x3c00 - strb r0, [r11, r3] - mov r2, r1, lsl #21 - ldrb r0, [r11, r2, lsr #19] - strb r2, [r11, r3] - RETINSTR(mov,pc,lr) - -/* - * Cards we don't know about yet - */ -ENTRY(noloader) - mov r0, r0 - mov r0, #0 - RETINSTR(mov,pc,lr) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/memchr.S linux/arch/arm/lib/memchr.S --- v2.2.17/arch/arm/lib/memchr.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/memchr.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,33 @@ +/* + * linux/arch/arm/lib/memchr.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text + +@ I have this hunch that this one can be optimised further. +@ Beware false optimisation of ldrb the byte BEYOND the end of buffer (could +@ be beyond end of memory) before testing to see if length had been exhausted +@ on the previous byte. +ENTRY(memchr) @ 2nd argument char + stmfd sp!, {lr} + and r1, r1, #0xff @ cast 2nd argument to char + add r2, r2, r0 @ Point to end (exclusive) + +1: teq r0, r2 + beq 2f @ No more to do + ldrb r3, [r0], #1 + teq r3, r1 + bne 1b + sub r0, r0, #1 + LOADREGS(fd, sp!, {pc}) + +2: mov r0, #0 @ Got to end and not found. + LOADREGS(fd, sp!, {pc}) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S --- v2.2.17/arch/arm/lib/memcpy.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/memcpy.S Fri Sep 15 23:28:37 2000 @@ -1,20 +1,17 @@ /* - * linux/arch/arm/lib/segment.S + * linux/arch/arm/lib/memcpy.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions * - * Copyright (C) 1995, 1996 Russell King - * Except memcpy/memmove routine. */ - -#include #include - -#ifndef ENTRY -#define ENTRY(x...) \ - .globl _##x; \ -_##x: -#endif +#include +#include "constants.h" .text + #define ENTER \ mov ip,sp ;\ stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ @@ -26,9 +23,10 @@ #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!!! - +/* + * Prototype: void memcpy(void *to,const void *from,unsigned long n); + * ARM3: cant use memcopy here!!! + */ ENTRY(memcpy) ENTRY(memmove) ENTER @@ -316,4 +314,5 @@ b 24b .align + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/memset.S linux/arch/arm/lib/memset.S --- v2.2.17/arch/arm/lib/memset.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/memset.S Fri Sep 15 23:28:37 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 + 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) + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/memzero.S linux/arch/arm/lib/memzero.S --- v2.2.17/arch/arm/lib/memzero.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/memzero.S Mon Oct 2 10:10:30 2000 @@ -0,0 +1,80 @@ +/* + * linux/arch/arm/lib/memzero.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + + .text + .align 5 + .word 0 +/* + * Align the pointer in r0. r3 contains the number of bytes that we are + * mis-aligned by, and r1 is the number of bytes. If r1 < 4, then we + * don't bother; we use byte stores instead. + */ +1: subs r1, r1, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r2, [r0], #1 @ 1 + strleb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + add r1, r1, r3 @ 1 (r1 = r1 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * memzero again. + */ + +ENTRY(__memzero) + mov r2, #0 @ 1 + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary. + */ + cmp r1, #16 @ 1 we can skip this chunk if we + blt 4f @ 1 have < 16 bytes +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! @ 1 + mov ip, r2 @ 1 + mov lr, r2 @ 1 + +3: subs r1, r1, #64 @ 1 write 32 bytes out per loop + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + bgt 3b @ 1 + LOADREGS(eqfd, sp!, {pc}) @ 1/2 quick exit +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r1, #32 @ 1 + stmneia r0!, {r2, r3, ip, lr} @ 4 + stmneia r0!, {r2, r3, ip, lr} @ 4 + tst r1, #16 @ 1 16 bytes or more? + stmneia r0!, {r2, r3, ip, lr} @ 4 + ldr lr, [sp], #4 @ 1 + +4: tst r1, #8 @ 1 8 bytes or more? + stmneia r0!, {r2, r3} @ 2 + tst r1, #4 @ 1 4 bytes or more? + strne r2, [r0], #4 @ 1 +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r1, #2 @ 1 2 bytes or more? + strneb r2, [r0], #1 @ 1 + strneb r2, [r0], #1 @ 1 + tst r1, #1 @ 1 a byte left over + strneb r2, [r0], #1 @ 1 + RETINSTR(mov,pc,lr) @ 1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/semaphore.S linux/arch/arm/lib/semaphore.S --- v2.2.17/arch/arm/lib/semaphore.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/semaphore.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,34 @@ +/* + * linux/arch/arm/lib/semaphore.S + * + * Idea from i386 code, Copyright Linus Torvalds. + * Converted for ARM by Russell King + */ +#include +#include + +/* + * The semaphore operations have a special calling sequence + * that allows us to keep the distruption of the main code + * path to a minimum. These routines save and restore the + * registers that will be touched by __down etc. + */ +ENTRY(__down_failed) + stmfd sp!, {r0 - r3, ip, lr} + bl SYMBOL_NAME(__down) + LOADREGS(fd, sp!, {r0 - r3, ip, pc}) + +ENTRY(__down_interruptible_failed) + stmfd sp!, {r1 - r3, ip, lr} + bl SYMBOL_NAME(__down_interruptible) + LOADREGS(fd, sp!, {r1 - r3, ip, pc}) + +ENTRY(__down_trylock_failed) + stmfd sp!, {r1 - r3, ip, lr} + bl SYMBOL_NAME(__down_trylock) + LOADREGS(fd, sp!, {r1 - r3, ip, pc}) + +ENTRY(__up_wakeup) + stmfd sp!, {r0 - r3, ip, lr} + bl SYMBOL_NAME(__up) + LOADREGS(fd, sp!, {r0 - r3, ip, pc}) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/setbit.S linux/arch/arm/lib/setbit.S --- v2.2.17/arch/arm/lib/setbit.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/setbit.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/strchr.S linux/arch/arm/lib/strchr.S --- v2.2.17/arch/arm/lib/strchr.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/strchr.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/strchr.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text + +ENTRY(strchr) + ldrb r2, [r0], #1 + stmfd sp!,{lr} @ StrongARM: LDR not followed by use +1: teq r2, r1 + teqne r2, #0 + ldrneb r2, [r0], #1 + bne 1b + teq r2, r1 @ If they are the same we found char. + movne r0, #0 + subeq r0, r0, #1 @ Even if we were looking for 0 :-) + LOADREGS(fd, sp!, {pc}) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/string.S linux/arch/arm/lib/string.S --- v2.2.17/arch/arm/lib/string.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/string.S Thu Jan 1 01:00:00 1970 @@ -1,170 +0,0 @@ -/* - * linux/arch/arm/lib/string.S - * - * Copyright (C) 1995-1998 Russell King - * - * This is commonly used to clear the frame buffer and the frame - * backing buffer. As such, it will be rarely called with r2 < 32. - * - * Optimisations by Matthew Wilcox - */ -#include -#include - .text -# Prototype: char *strrchr(const char *s,char c); - -/* - * Prototype: void memzero(void *d, size_t n) - */ -ENTRY(memzero) - mov r2, r1 - mov r1, #0 -/* - * Prototype: void memsetl(unsigned long *d, unsigned long c, size_t n) - */ -ENTRY(memsetl) - teq r2, #0 - RETINSTR(moveq,pc,lr) - stmfd sp!, {lr} - mov lr, r1 - mov r3, r1 - mov ip, r1 - - @ r2 = {32 ... 4} - -1: subs r2, r2, #32 - stmgeia r0!, {r1, r3, ip, lr} - stmgeia r0!, {r1, r3, ip, lr} - bgt 1b - LOADREGS(eqfd, sp!, {pc}) - - @ r2 can be {-4 ... -28} - - cmp r2, #-16 - stmgeia r0!, {r1, r3, ip, lr} - addlts r2, r2, #16 - LOADREGS(eqfd, sp!, {pc}) - - @ r2 can be {-4 ... -12} - - cmp r2, #-8 - stmgeia r0!, {r1, r3} - strne r1, [r0] - LOADREGS(fd, sp!, {pc}) - - .global __page_memcpy -__page_memcpy: stmfd sp!, {r4, r5, lr} -1: subs r2, r2, #4*8 - ldmgeia r1!, {r3, r4, r5, ip} - stmgeia r0!, {r3, r4, r5, ip} - ldmgeia r1!, {r3, r4, r5, ip} - stmgeia r0!, {r3, r4, r5, ip} - bgt 1b - LOADREGS(fd, sp!, {r4, r5, pc}) - - .global memset -memset: mov r3, r0 - cmp r2, #16 - blt 6f - ands ip, r3, #3 - beq 1f - cmp ip, #2 - strltb r1, [r3], #1 @ Align destination - strleb r1, [r3], #1 - strb r1, [r3], #1 - rsb ip, ip, #4 - sub r2, r2, ip -1: orr r1, r1, r1, lsl #8 - orr r1, r1, r1, lsl #16 - cmp r2, #256 - blt 4f - stmfd sp!, {r4, r5, lr} - mov r4, r1 - mov r5, r1 - mov lr, r1 - mov ip, r2, lsr #6 - sub r2, r2, ip, lsl #6 -2: stmia r3!, {r1, r4, r5, lr} @ 64 bytes at a time. - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - stmia r3!, {r1, r4, r5, lr} - subs ip, ip, #1 - bne 2b - teq r2, #0 - LOADREGS(eqfd, sp!, {r4, r5, pc}) @ Now <64 bytes to go. - tst r2, #32 - stmneia r3!, {r1, r4, r5, lr} - stmneia r3!, {r1, r4, r5, lr} - tst r2, #16 - stmneia r3!, {r1, r4, r5, lr} - ldmia sp!, {r4, r5} -3: tst r2, #8 - stmneia r3!, {r1, lr} - tst r2, #4 - strne r1, [r3], #4 - tst r2, #2 - strneb r1, [r3], #1 - strneb r1, [r3], #1 - tst r2, #1 - strneb r1, [r3], #1 - LOADREGS(fd, sp!, {pc}) - -4: movs ip, r2, lsr #3 - beq 3b - sub r2, r2, ip, lsl #3 - stmfd sp!, {lr} - mov lr, r1 - subs ip, ip, #4 -5: stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - stmgeia r3!, {r1, lr} - subges ip, ip, #4 - bge 5b - tst ip, #2 - stmneia r3!, {r1, lr} - stmneia r3!, {r1, lr} - tst ip, #1 - stmneia r3!, {r1, lr} - teq r2, #0 - LOADREGS(eqfd, sp!, {pc}) - b 3b - -6: subs r2, r2, #1 - strgeb r1, [r3], #1 - bgt 6b - RETINSTR(mov, pc, lr) - -ENTRY(strrchr) - stmfd sp!, {lr} - mov r3, #0 -1: ldrb r2, [r0], #1 - teq r2, r1 - moveq r3, r0 - teq r2, #0 - bne 1b - mov r0, r3 - LOADREGS(fd, sp!, {pc}) - -ENTRY(strchr) - stmfd sp!,{lr} - mov r3, #0 -1: ldrb r2, [r0], #1 - teq r2, r1 - teqne r2, #0 - bne 1b - teq r2, #0 - moveq r0, #0 - subne r0, r0, #1 - LOADREGS(fd, sp!, {pc}) - -ENTRY(memchr) - stmfd sp!, {lr} -1: ldrb r3, [r0], #1 - teq r3, r1 - beq 2f - subs r2, r2, #1 - bpl 1b -2: movne r0, #0 - subeq r0, r0, #1 - LOADREGS(fd, sp!, {pc}) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/strrchr.S linux/arch/arm/lib/strrchr.S --- v2.2.17/arch/arm/lib/strrchr.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/strrchr.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,29 @@ +/* + * linux/arch/arm/lib/strrchr.S + * + * Copyright (C) 1995-1999 Russell King + * + * ASM optimised string functions + * + */ +#include +#include +#include "constants.h" + + .text + + @ Technically this will fail a regression test that tries + @ strrchr (buffer, 0), by returning NULL rather than + @ buffer + strlen (buffer). But even glibc doesnt test this +ENTRY(strrchr) @ 2nd argument is int not char + stmfd sp!, {lr} + mov r3, r0 + ldrb r2, [r3], #1 + mov r0, #0 @ prime return result. +1: teq r2, r1 @ Found one? + subeq r0, r3, #1 + teq r2, #0 + ldrneb r2, [r3], #1 @ Assume that well be looping at least + bne 1b @ twice, so put LDM outside loop. + LOADREGS(fd, sp!, {pc}) + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/testchangebit.S linux/arch/arm/lib/testchangebit.S --- v2.2.17/arch/arm/lib/testchangebit.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/testchangebit.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/testclearbit.S linux/arch/arm/lib/testclearbit.S --- v2.2.17/arch/arm/lib/testclearbit.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/testclearbit.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/testsetbit.S linux/arch/arm/lib/testsetbit.S --- v2.2.17/arch/arm/lib/testsetbit.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/lib/testsetbit.S Fri Sep 15 23:28:37 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/uaccess-armo.S linux/arch/arm/lib/uaccess-armo.S --- v2.2.17/arch/arm/lib/uaccess-armo.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/uaccess-armo.S Fri Sep 15 23:28:37 2000 @@ -30,7 +30,7 @@ .word __arch_copy_to_user .word __arch_clear_user .word __arch_strncpy_from_user - .word __arch_strlen_user + .word __arch_strnlen_user @ In : r0 = x, r1 = addr, r2 = error @@ -99,7 +99,7 @@ .word uaccess_kernel_copy .word uaccess_kernel_clear .word uaccess_kernel_strncpy_from - .word uaccess_kernel_strlen + .word uaccess_kernel_strnlen @ In : r0 = x, r1 = addr, r2 = error @ Out: r2 = error @@ -214,17 +214,20 @@ 2: subs r0, ip, r2 ldmfd sp!, {pc}^ -/* Prototype: int uaccess_kernel_strlen(char *str) +/* Prototype: int uaccess_kernel_strnlen(char *str, long n) * Purpose : get length of a string in kernel memory * Params : str - address of string in kernel memory * Returns : length of string *including terminator*, or zero on error */ -uaccess_kernel_strlen: +uaccess_kernel_strnlen: stmfd sp!, {lr} mov r2, r0 -1: ldrb r1, [r0], #1 - teq r1, #0 +1: ldrb r3, [r0], #1 + teq r3, #0 + beq 2f + subs r1, r1, #1 bne 1b - sub r0, r0, r2 + add r0, r0, #1 +2: sub r0, r0, r2 ldmfd sp!, {pc}^ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S --- v2.2.17/arch/arm/lib/uaccess.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/lib/uaccess.S Fri Sep 15 23:28:37 2000 @@ -42,11 +42,11 @@ rsb ip, ip, #4 cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault sub r2, r2, ip b .c2u_dest_aligned @@ -69,8 +69,8 @@ addmi ip, r2, #4 bmi .c2u_0nowords ldr r3, [r1], #4 -USER( strt r3, [r0], #4) // May fault - mov ip, r0, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction +USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT beq .c2u_0fupi @@ -84,31 +84,31 @@ blt .c2u_0rem8lp .c2u_0cpy8lp: ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault ldmia r1!, {r3 - r6} - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #32 bpl .c2u_0cpy8lp .c2u_0rem8lp: cmn ip, #16 ldmgeia r1!, {r3 - r6} - stmgeia r0!, {r3 - r6} // Shouldn't fault + stmgeia r0!, {r3 - r6} @ Shouldn't fault tst ip, #8 ldmneia r1!, {r3 - r4} - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 ldrne r3, [r1], #4 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_0fupi .c2u_0nowords: teq ip, #0 beq .c2u_finished .c2u_nowords: cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_not_enough: @@ -129,7 +129,7 @@ mov r3, r7, lsr #8 ldr r7, [r1], #4 orr r3, r3, r7, lsl #24 -USER( strt r3, [r0], #4) // May fault +USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -149,7 +149,7 @@ orr r5, r5, r6, lsl #24 mov r6, r6, lsr #8 orr r6, r6, r7, lsl #24 - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #16 bpl .c2u_1cpy8lp .c2u_1rem8lp: tst ip, #8 @@ -158,23 +158,23 @@ orrne r3, r3, r4, lsl #24 movne r4, r4, lsr #8 orrne r4, r4, r7, lsl #24 - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 movne r3, r7, lsr #8 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #24 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_1fupi .c2u_1nowords: mov r3, r7, lsr #8 teq ip, #0 beq .c2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault movge r3, r3, lsr #8 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault movgt r3, r3, lsr #8 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_2fupi: subs r2, r2, #4 @@ -183,7 +183,7 @@ mov r3, r7, lsr #16 ldr r7, [r1], #4 orr r3, r3, r7, lsl #16 -USER( strt r3, [r0], #4) // May fault +USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -203,7 +203,7 @@ orr r5, r5, r6, lsl #16 mov r6, r6, lsr #16 orr r6, r6, r7, lsl #16 - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #16 bpl .c2u_2cpy8lp .c2u_2rem8lp: tst ip, #8 @@ -212,23 +212,23 @@ orrne r3, r3, r4, lsl #16 movne r4, r4, lsr #16 orrne r4, r4, r7, lsl #16 - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 movne r3, r7, lsr #16 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #16 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_2fupi .c2u_2nowords: mov r3, r7, lsr #16 teq ip, #0 beq .c2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault movge r3, r3, lsr #8 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished .c2u_3fupi: subs r2, r2, #4 @@ -237,7 +237,7 @@ mov r3, r7, lsr #24 ldr r7, [r1], #4 orr r3, r3, r7, lsl #8 -USER( strt r3, [r0], #4) // May fault +USER( strt r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -257,7 +257,7 @@ orr r5, r5, r6, lsl #8 mov r6, r6, lsr #24 orr r6, r6, r7, lsl #8 - stmia r0!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} @ Shouldn't fault subs ip, ip, #16 bpl .c2u_3cpy8lp .c2u_3rem8lp: tst ip, #8 @@ -266,23 +266,23 @@ orrne r3, r3, r4, lsl #8 movne r4, r4, lsr #24 orrne r4, r4, r7, lsl #8 - stmneia r0!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} @ Shouldn't fault tst ip, #4 movne r3, r7, lsr #24 ldrne r7, [r1], #4 orrne r3, r3, r7, lsl #8 - strnet r3, [r0], #4 // Shouldn't fault + strnet r3, [r0], #4 @ Shouldn't fault ands ip, ip, #3 beq .c2u_3fupi .c2u_3nowords: mov r3, r7, lsr #24 teq ip, #0 beq .c2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) // May fault +USER( strbt r3, [r0], #1) @ May fault ldrge r3, [r1], #0 -USER( strgebt r3, [r0], #1) // May fault +USER( strgebt r3, [r0], #1) @ May fault movgt r3, r3, lsr #8 -USER( strgtbt r3, [r0], #1) // May fault +USER( strgtbt r3, [r0], #1) @ May fault b .c2u_finished #ifndef TESTING @@ -302,11 +302,11 @@ .cfu_dest_not_aligned: rsb ip, ip, #4 cmp ip, #2 -USER( ldrbt r3, [r1], #1) // May fault +USER( ldrbt r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) // May fault +USER( ldrgebt r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) // May fault +USER( ldrgtbt r3, [r1], #1) @ May fault strgtb r3, [r0], #1 sub r2, r2, ip b .cfu_dest_aligned @@ -330,7 +330,7 @@ bmi .cfu_0nowords USER( ldrt r3, [r1], #4) str r3, [r0], #4 - mov ip, r1, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction + mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT beq .cfu_0fupi @@ -343,31 +343,31 @@ subs ip, ip, #32 blt .cfu_0rem8lp -.cfu_0cpy8lp: ldmia r1!, {r3 - r6} // Shouldn't fault +.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldn't fault stmia r0!, {r3 - r6} - ldmia r1!, {r3 - r6} // Shouldn't fault + ldmia r1!, {r3 - r6} @ Shouldn't fault stmia r0!, {r3 - r6} subs ip, ip, #32 bpl .cfu_0cpy8lp .cfu_0rem8lp: cmn ip, #16 - ldmgeia r1!, {r3 - r6} // Shouldn't fault + ldmgeia r1!, {r3 - r6} @ Shouldn't fault stmgeia r0!, {r3 - r6} tst ip, #8 - ldmneia r1!, {r3 - r4} // Shouldn't fault + ldmneia r1!, {r3 - r4} @ Shouldn't fault stmneia r0!, {r3 - r4} tst ip, #4 - ldrnet r3, [r1], #4 // Shouldn't fault + ldrnet r3, [r1], #4 @ Shouldn't fault strne r3, [r0], #4 ands ip, ip, #3 beq .cfu_0fupi .cfu_0nowords: teq ip, #0 beq .cfu_finished .cfu_nowords: cmp ip, #2 -USER( ldrbt r3, [r1], #1) // May fault +USER( ldrbt r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) // May fault +USER( ldrgebt r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) // May fault +USER( ldrgtbt r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .cfu_finished @@ -380,7 +380,7 @@ .cfu_src_not_aligned: bic r1, r1, #3 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault cmp ip, #2 bgt .cfu_3fupi beq .cfu_2fupi @@ -388,7 +388,7 @@ addmi ip, r2, #4 bmi .cfu_1nowords mov r3, r7, lsr #8 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault orr r3, r3, r7, lsl #24 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -402,7 +402,7 @@ blt .cfu_1rem8lp .cfu_1cpy8lp: mov r3, r7, lsr #8 - ldmia r1!, {r4 - r7} // Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldn't fault orr r3, r3, r4, lsl #24 mov r4, r4, lsr #8 orr r4, r4, r5, lsl #24 @@ -415,14 +415,14 @@ bpl .cfu_1cpy8lp .cfu_1rem8lp: tst ip, #8 movne r3, r7, lsr #8 - ldmneia r1!, {r4, r7} // Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldn't fault orrne r3, r3, r4, lsl #24 movne r4, r4, lsr #8 orrne r4, r4, r7, lsl #24 stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, lsr #8 -USER( ldrnet r7, [r1], #4) // May fault +USER( ldrnet r7, [r1], #4) @ May fault orrne r3, r3, r7, lsl #24 strne r3, [r0], #4 ands ip, ip, #3 @@ -442,7 +442,7 @@ addmi ip, r2, #4 bmi .cfu_2nowords mov r3, r7, lsr #16 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault orr r3, r3, r7, lsl #16 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -456,7 +456,7 @@ blt .cfu_2rem8lp .cfu_2cpy8lp: mov r3, r7, lsr #16 - ldmia r1!, {r4 - r7} // Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldn't fault orr r3, r3, r4, lsl #16 mov r4, r4, lsr #16 orr r4, r4, r5, lsl #16 @@ -469,14 +469,14 @@ bpl .cfu_2cpy8lp .cfu_2rem8lp: tst ip, #8 movne r3, r7, lsr #16 - ldmneia r1!, {r4, r7} // Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldn't fault orrne r3, r3, r4, lsl #16 movne r4, r4, lsr #16 orrne r4, r4, r7, lsl #16 stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, lsr #16 -USER( ldrnet r7, [r1], #4) // May fault +USER( ldrnet r7, [r1], #4) @ May fault orrne r3, r3, r7, lsl #16 strne r3, [r0], #4 ands ip, ip, #3 @@ -488,7 +488,7 @@ strb r3, [r0], #1 movge r3, r3, lsr #8 strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #0) // May fault +USER( ldrgtbt r3, [r1], #0) @ May fault strgtb r3, [r0], #1 b .cfu_finished @@ -496,7 +496,7 @@ addmi ip, r2, #4 bmi .cfu_3nowords mov r3, r7, lsr #24 -USER( ldrt r7, [r1], #4) // May fault +USER( ldrt r7, [r1], #4) @ May fault orr r3, r3, r7, lsl #8 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -510,7 +510,7 @@ blt .cfu_3rem8lp .cfu_3cpy8lp: mov r3, r7, lsr #24 - ldmia r1!, {r4 - r7} // Shouldn't fault + ldmia r1!, {r4 - r7} @ Shouldn't fault orr r3, r3, r4, lsl #8 mov r4, r4, lsr #24 orr r4, r4, r5, lsl #8 @@ -523,14 +523,14 @@ bpl .cfu_3cpy8lp .cfu_3rem8lp: tst ip, #8 movne r3, r7, lsr #24 - ldmneia r1!, {r4, r7} // Shouldn't fault + ldmneia r1!, {r4, r7} @ Shouldn't fault orrne r3, r3, r4, lsl #8 movne r4, r4, lsr #24 orrne r4, r4, r7, lsl #8 stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, lsr #24 -USER( ldrnet r7, [r1], #4) // May fault +USER( ldrnet r7, [r1], #4) @ May fault orrne r3, r3, r7, lsl #8 strne r3, [r0], #4 ands ip, ip, #3 @@ -540,7 +540,7 @@ beq .cfu_finished cmp ip, #2 strb r3, [r0], #1 -USER( ldrget r3, [r1], #0) // May fault +USER( ldrget r3, [r1], #0) @ May fault strgeb r3, [r0], #1 movgt r3, r3, lsr #8 strgtb r3, [r0], #1 @@ -553,7 +553,8 @@ data was copied. */ 9001: ldr r0, [sp], #4 ldr r1, [sp] - bl SYMBOL_NAME(memzero) + teq r1, #0 + blne SYMBOL_NAME(__memzero) LOADREGS(fd,sp!, {r0, r4 - r7, pc}) .previous #endif @@ -597,19 +598,22 @@ 9001: LOADREGS(fd,sp!, {r0, pc}) .previous -/* Prototype: int __arch_strlen_user(char *str) +/* Prototype: int __arch_strnlen_user(char *str, long n) * Purpose : get length of a string in user memory * Params : str - address of string in user memory * Returns : length of string *including terminator*, or zero on error */ -ENTRY(__arch_strlen_user) +ENTRY(__arch_strnlen_user) stmfd sp!, {lr} mov r2, r0 1: -USER( ldrbt r1, [r0], #1) - teq r1, #0 +USER( ldrbt r3, [r0], #1) + teq r3, #0 + beq 2f + subs r1, r1, #1 bne 1b - sub r0, r0, r2 + add r0, r0, #1 +2: sub r0, r0, r2 LOADREGS(fd,sp!, {pc}) .section .fixup,"ax" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.2.17/arch/arm/mm/Makefile Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/Makefile Fri Sep 15 23:28:37 2000 @@ -7,13 +7,11 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -all: lib first_rule - -O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o +O_TARGET := mm.o +O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o ifeq ($(PROCESSOR),armo) - O_OBJS += proc-arm2,3.o + O_OBJS += proc-arm2,3.o endif ifeq ($(PROCESSOR),armv) @@ -22,11 +20,8 @@ include $(TOPDIR)/Rules.make -%.o: %.S - $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< - -.PHONY: lib -lib:; @$(MAKE) -C ../lib constants.h +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_$@) -traditional -c -o $*.o $< # Special dependencies fault-armv.o: fault-common.c diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c --- v2.2.17/arch/arm/mm/fault-armo.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/fault-armo.c Fri Sep 15 23:28:37 2000 @@ -23,7 +23,6 @@ #define FAULT_CODE_FORCECOW 0x80 #define FAULT_CODE_PREFETCH 0x04 #define FAULT_CODE_WRITE 0x02 -#define FAULT_CODE_USER 0x01 #define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) #define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) @@ -96,11 +95,11 @@ do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { #if 0 - if (the memc mapping for this page exists - can check now...) { + if (the memc mapping for this page exists) { printk ("Page in, but got abort (undefined instruction?)\n"); return 0; } #endif - do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs); + do_page_fault(addr, FAULT_CODE_PREFETCH, regs); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.2.17/arch/arm/mm/fault-armv.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/fault-armv.c Fri Sep 15 23:28:37 2000 @@ -25,7 +25,6 @@ #include #define FAULT_CODE_READ 0x02 -#define FAULT_CODE_USER 0x01 #define DO_COW(m) (!((m) & FAULT_CODE_READ)) #define READ_FAULT(m) ((m) & FAULT_CODE_READ) @@ -377,16 +376,30 @@ #endif +#define BUG_PROC_MSG \ + "Weirdness detected (%08X)\n" \ + "Please read 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) { - if (user_mode(regs)) - error_code |= FAULT_CODE_USER; + 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; + } + return; + } + } #define DIE(signr,nam)\ force_sig(signr, current);\ die(nam, regs, fsr);\ - do_exit(signr);\ break switch (fsr & 15) { @@ -395,10 +408,8 @@ */ case 0: force_sig(SIGSEGV, current); - if (!user_mode(regs)) { + if (!user_mode(regs)) die("vector exception", regs, fsr); - do_exit(SIGSEGV); - } break; /* @@ -415,10 +426,9 @@ */ case 13: force_sig(SIGSEGV, current); - if (!user_mode(regs)) { + if (!user_mode(regs)) die("section permission fault", regs, fsr); - do_exit(SIGSEGV); - } else { + else { #ifdef CONFIG_DEBUG_USER printk("%s: permission fault on section, " "address=0x%08lx, code %d\n", @@ -476,6 +486,6 @@ asmlinkage int do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { - do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs); + do_page_fault(addr, FAULT_CODE_READ, regs); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.2.17/arch/arm/mm/fault-common.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/fault-common.c Fri Sep 15 23:28:37 2000 @@ -26,25 +26,14 @@ set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); } -static void -kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs, - struct task_struct *tsk, struct mm_struct *mm) +/* + * This is useful to dump out the page tables associated with + * 'addr' in mm 'mm'. + */ +void show_pte(struct mm_struct *mm, unsigned long addr) { - char *reason; - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ pgd_t *pgd; - if (addr < PAGE_SIZE) - reason = "NULL pointer dereference"; - else - reason = "paging request"; - - printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n", - reason, addr); - printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd); pgd = pgd_offset(mm, addr); printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd)); @@ -73,11 +62,34 @@ pte = pte_offset(pmd, addr); printk(", *pte = %08lx", pte_val(*pte)); +#ifdef CONFIG_CPU_32 printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE])); +#endif } while(0); printk("\n"); - die("Oops", regs, mode); +} + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ +static void +kernel_page_fault(unsigned long addr, int write_access, struct pt_regs *regs, + struct task_struct *tsk, struct mm_struct *mm) +{ + char *reason; + + if (addr < PAGE_SIZE) + reason = "NULL pointer dereference"; + else + reason = "paging request"; + + printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n", + reason, addr); + printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd); + show_pte(mm, addr); + die("Oops", regs, write_access); do_exit(SIGKILL); } @@ -88,6 +100,7 @@ struct mm_struct *mm; struct vm_area_struct *vma; unsigned long fixup; + int fault; tsk = current; mm = tsk->mm; @@ -126,8 +139,12 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ - if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode))) +survive: + fault = handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode)); + if (!fault) goto do_sigbus; + if (fault < 0) + goto out_of_memory; up(&mm->mmap_sem); return; @@ -140,7 +157,7 @@ up(&mm->mmap_sem); /* User mode accesses just cause a SIGSEGV */ - if (mode & FAULT_CODE_USER) { + if (user_mode(regs)) { tsk->tss.error_code = mode; tsk->tss.trap_no = 14; #ifdef CONFIG_DEBUG_USER @@ -165,6 +182,23 @@ kernel_page_fault(addr, mode, regs, tsk, mm); return; +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + if (tsk->pid == 1) { + tsk->policy |= SCHED_YIELD; + schedule(); + goto survive; + } + up(&mm->mmap_sem); + if (user_mode(regs)) { + printk("VM: killing process %s\n", tsk->comm); + do_exit(SIGKILL); + } + goto no_context; + do_sigbus: /* * We ran out of memory, or some other thing happened to us that made @@ -181,7 +215,7 @@ force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ - if (!(mode & FAULT_CODE_USER)) + if (!user_mode(regs)) goto no_context; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.2.17/arch/arm/mm/init.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/init.c Fri Sep 15 23:28:37 2000 @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/init.c * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995-1999 Russell King */ #include @@ -248,7 +248,7 @@ (unsigned long)(&__netwinder_end), "netwinder"); - if (!machine_is_ebsa285() && !machine_is_cats()) + if (!machine_is_ebsa285() && !machine_is_cats() && !machine_is_co285()) free_area((unsigned long)(&__ebsa285_begin), (unsigned long)(&__ebsa285_end), "ebsa285/cats"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c --- v2.2.17/arch/arm/mm/ioremap.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/ioremap.c Fri Sep 15 23:28:37 2000 @@ -28,7 +28,11 @@ * flush this - flushing the area causes the bus to lock. */ +#include #include + +#include +#include #include static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, @@ -111,23 +115,23 @@ * 'flags' are the extra L_PTE_ flags that you want to specify for this * mapping. See include/asm-arm/proc-armv/pgtable.h for more information. */ -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +void * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags) { void * addr; struct vm_struct * area; - unsigned long offset; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; /* * Mappings have to be page-aligned */ offset = phys_addr & ~PAGE_MASK; - size = PAGE_ALIGN(size + offset); - - /* - * Don't allow mappings that wrap.. - */ - if (!size || size > phys_addr + size) - return NULL; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; /* * Ok, go for it.. @@ -143,7 +147,7 @@ return (void *) (offset + (char *)addr); } -void iounmap(void *addr) +void __iounmap(void *addr) { - return vfree((void *) (PAGE_MASK & (unsigned long) addr)); + vfree((void *) (PAGE_MASK & (unsigned long) addr)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.2.17/arch/arm/mm/mm-armv.c Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/mm-armv.c Fri Sep 15 23:28:37 2000 @@ -70,3 +70,27 @@ return start_mem; } + +/* + * In order to soft-boot, we need to insert a 1:1 mapping in place of + * the user-mode pages. This will then ensure that we have predictable + * results when turning the mmu off + */ +void setup_mm_for_reboot(char mode) +{ + pgd_t *pgd; + pmd_t pmd; + int i; + + if (current->mm && current->mm->pgd) + pgd = current->mm->pgd; + else + pgd = init_mm.pgd; + + for (i = 0; i < USER_PTRS_PER_PGD; i++) { + pmd_val(pmd) = (i << PAGE_SHIFT) | + PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | + PMD_TYPE_SECT; + set_pmd(pmd_offset(pgd + i, i << PGDIR_SHIFT), pmd); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S --- v2.2.17/arch/arm/mm/proc-arm2,3.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/proc-arm2,3.S Fri Sep 15 23:28:37 2000 @@ -202,21 +202,17 @@ LC0: .word SYMBOL_NAME(page_nr) /* * Function: arm2_switch_to (struct task_struct *prev, struct task_struct *next) - * * Params : prev Old task structure * : next New task structure for process to run - * * Returns : prev - * * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. - * * Notes : We don't fiddle with the FP registers here - we postpone this until * the new task actually uses FP. This way, we don't swap FP for tasks * that do not require it. */ _arm2_switch_to: - stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + stmfd sp!, {r4 - r10, fp, lr} @ Store most regs on stack str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC mov r4, r1 @@ -235,7 +231,7 @@ strb r6, [r6] subs r1, r1, #8 bhi 1b - ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously + ldmfd sp!, {r4 - r10, fp, pc}^ @ Load all regs saved previously /* * Function: arm2_remap_memc (struct task_struct *tsk) @@ -316,15 +312,11 @@ _arm2_proc_fin: movs pc, lr /* * Function: arm3_switch_to (struct task_struct *prev, struct task_struct *next) - * * Params : prev Old task structure * : next New task structure for process to run - * * Returns : prev - * * Purpose : Perform a task switch, saving the old processes state, and restoring * the new. - * * Notes : We don't fiddle with the FP registers here - we postpone this until * the new task actually uses FP. This way, we don't swap FP for tasks * that do not require it. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.2.17/arch/arm/mm/proc-arm6,7.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/proc-arm6,7.S Fri Sep 15 23:28:37 2000 @@ -1,13 +1,15 @@ /* - * linux/arch/arm/mm/arm6.S: MMU functions for ARM6 + * linux/arch/arm/mm/proc-arm6,7.S: MMU functions for ARM6 * - * (C) 1997 Russell King + * (C) 1997-1999 Russell King * * These are the low level assembler for performing cache and TLB * functions on the ARM6 & ARM7. */ #include #include +#include +#include #include "../lib/constants.h" /* @@ -68,24 +70,21 @@ * that do not require it. */ _arm6_7_switch_to: - stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + stmfd sp!, {r4 - r10, fp, lr} @ Store most regs on stack mrs ip, cpsr stmfd sp!, {ip} @ Save cpsr_SVC str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r2, [r1, #TSK_ADDR_LIMIT] - teq r2, #0 - moveq r2, #DOM_KERNELDOMAIN - movne r2, #DOM_USERDOMAIN + ldr r2, [r1, #TSS_DOMAIN] + ldr r3, [r1, #TSS_MEMMAP] @ Page table pointer mcr p15, 0, r2, c3, c0 @ Set domain reg - ldr r2, [r1, #TSS_MEMMAP] @ Page table pointer mov r1, #0 mcr p15, 0, r1, c7, c0, 0 @ flush cache - mcr p15, 0, r2, c2, c0, 0 @ update page table ptr + mcr p15, 0, r3, c2, c0, 0 @ update page table ptr mcr p15, 0, r1, c5, c0, 0 @ flush TLBs ldmfd sp!, {ip} msr spsr, ip @ Save tasks CPSR into SPSR for this return - ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously + ldmfd sp!, {r4 - r10, fp, pc}^ @ Load all regs saved previously /* * Function: arm6_7_data_abort () @@ -109,40 +108,44 @@ _arm6_data_abort: ldr r4, [r0] @ read instruction causing problem mov r2, r4, lsr #19 @ r2 b1 = L - and r1, r4, #15 << 24 - add pc, pc, r1, lsr #22 @ Now branch to the relevent processing routine - movs pc, lr - b Ldata_unknown - b Ldata_unknown - b Ldata_unknown - b Ldata_unknown - b Ldata_earlyldrpost @ ldr rd, [rn], #m - b Ldata_simple @ ldr rd, [rn, #m] @ RegVal - b Ldata_earlyldrpost @ ldr rd, [rn], rm - b Ldata_simple @ ldr rd, [rn, rm] - b Ldata_ldmstm @ ldm*a rn, - b Ldata_ldmstm @ ldm*b rn, - b Ldata_unknown - b Ldata_unknown - b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m - b Ldata_simple @ ldc rd, [rn, #m] - b Ldata_unknown -Ldata_unknown: @ Part of jumptable - ldr r3, [sp, #15 * 4] @ Get PC - str r3, [sp, #-4]! - mov r1, r1, lsr #2 - mov r3, r4 - mov r2, r0 - adr r0, Lukabttxt - bl SYMBOL_NAME(panic) -Lstop: b Lstop + and r1, r4, #14 << 24 + and r2, r2, #2 @ check read/write bit + teq r1, #8 << 24 + bne Ldata_simple + +Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple + mov r7, #0x11 + orr r7, r7, r7, lsl #8 + and r0, r4, r7 + and r1, r4, r7, lsl #1 + add r0, r0, r1, lsr #1 + and r1, r4, r7, lsl #2 + add r0, r0, r1, lsr #2 + and r1, r4, r7, lsl #3 + add r0, r0, r1, lsr #3 + add r0, r0, r0, lsr #8 + add r0, r0, r0, lsr #4 + and r7, r0, #15 @ r7 = no. of registers to transfer. + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] @ Get register + tst r4, #1 << 23 @ U bit + subne r7, r0, r7, lsl #2 + addeq r7, r0, r7, lsl #2 @ Do correction (signed) +Ldata_saver7: str r7, [sp, r5, lsr #14] @ Put register +Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r1, c5, c0, 0 @ get FSR + and r1, r1, #255 + mov pc, lr _arm7_data_abort: ldr r4, [r0] @ read instruction causing problem mov r2, r4, lsr #19 @ r2 b1 = L and r1, r4, #15 << 24 + and r2, r2, #2 @ check read/write bit add pc, pc, r1, lsr #22 @ Now branch to the relevent processing routine movs pc, lr + b Ldata_unknown b Ldata_unknown b Ldata_unknown @@ -158,123 +161,26 @@ b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m b Ldata_simple @ ldc rd, [rn, #m] b Ldata_unknown +Ldata_unknown: @ Part of jumptable b Ldata_unknown -Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit +Ldata_lateldrpreconst: + tst r4, #1 << 21 @ check writeback bit beq Ldata_simple - - mov r7, #0x11 - orr r7, r7, r7, lsl #8 - and r0, r4, r7 - and r1, r4, r7, lsl #1 - add r0, r0, r1, lsr #1 - and r1, r4, r7, lsl #2 - add r0, r0, r1, lsr #2 - and r1, r4, r7, lsl #3 - add r0, r0, r1, lsr #3 - add r0, r0, r0, lsr #8 - add r0, r0, r0, lsr #4 - and r7, r0, #15 @ r7 = no. of registers to transfer. - and r5, r4, #15 << 16 @ Get Rn - ldr r0, [sp, r5, lsr #14] @ Get register - eor r6, r4, r4, lsl #2 - tst r6, #1 << 23 @ Check inc/dec ^ writeback - rsbeq r7, r7, #0 - add r7, r0, r7, lsl #2 @ Do correction (signed) - str r7, [sp, r5, lsr #14] @ Put register - -Ldata_simple: and r2, r2, #2 @ check read/write bit - mrc p15, 0, r0, c6, c0, 0 @ get FAR - mrc p15, 0, r1, c5, c0, 0 @ get FSR - and r1, r1, #15 - mov pc, lr - -Ldata_earlyldrpost: - tst r2, #4 - and r2, r2, #2 @ check read/write bit - orrne r2, r2, #1 @ T bit - mrc p15, 0, r0, c6, c0, 0 @ get FAR - mrc p15, 0, r1, c5, c0, 0 @ get FSR - and r1, r1, #15 - mov pc, lr - Ldata_lateldrpostconst: movs r1, r4, lsl #20 @ Get offset - beq Ldata_earlyldrpost @ if offset is zero, no effect - and r5, r4, #15 << 16 @ Get Rn - ldr r0, [sp, r5, lsr #14] - tst r4, #1 << 23 @ U bit - subne r0, r0, r1, lsr #20 - addeq r0, r0, r1, lsr #20 - str r0, [sp, r5, lsr #14] @ Put register - b Ldata_earlyldrpost - -Ldata_lateldrpreconst: - tst r4, #1 << 21 @ check writeback bit - movnes r1, r4, lsl #20 @ Get offset beq Ldata_simple and r5, r4, #15 << 16 @ Get Rn ldr r0, [sp, r5, lsr #14] tst r4, #1 << 23 @ U bit - subne r0, r0, r1, lsr #20 - addeq r0, r0, r1, lsr #20 - str r0, [sp, r5, lsr #14] @ Put register - b Ldata_simple - -Ldata_lateldrpostreg: - and r5, r4, #15 - ldr r1, [sp, r5, lsl #2] @ Get Rm - mov r3, r4, lsr #7 - ands r3, r3, #31 - and r6, r4, #0x70 - orreq r6, r6, #8 - add pc, pc, r6 - mov r0, r0 - - mov r1, r1, lsl r3 @ 0: LSL #!0 - b 1f - b 1f @ 1: LSL #0 - mov r0, r0 - b 1f @ 2: MUL? - mov r0, r0 - b 1f @ 3: MUL? - mov r0, r0 - mov r1, r1, lsr r3 @ 4: LSR #!0 - b 1f - mov r1, r1, lsr #32 @ 5: LSR #32 - b 1f - b 1f @ 6: MUL? - mov r0, r0 - b 1f @ 7: MUL? - mov r0, r0 - mov r1, r1, asr r3 @ 8: ASR #!0 - b 1f - mov r1, r1, asr #32 @ 9: ASR #32 - b 1f - b 1f @ A: MUL? - mov r0, r0 - b 1f @ B: MUL? - mov r0, r0 - mov r1, r1, ror r3 @ C: ROR #!0 - b 1f - mov r1, r1, rrx @ D: RRX - b 1f - mov r0, r0 @ E: MUL? - mov r0, r0 - mov r0, r0 @ F: MUL? - - -1: and r5, r4, #15 << 16 @ Get Rn - ldr r0, [sp, r5, lsr #14] - tst r4, #1 << 23 @ U bit - subne r0, r0, r1 - addeq r0, r0, r1 - str r0, [sp, r5, lsr #14] @ Put register - b Ldata_earlyldrpost + subne r7, r0, r1, lsr #20 + addeq r7, r0, r1, lsr #20 + b Ldata_saver7 Ldata_lateldrprereg: tst r4, #1 << 21 @ check writeback bit beq Ldata_simple +Ldata_lateldrpostreg: and r5, r4, #15 ldr r1, [sp, r5, lsl #2] @ Get Rm mov r3, r4, lsr #7 @@ -320,10 +226,9 @@ 1: and r5, r4, #15 << 16 @ Get Rn ldr r0, [sp, r5, lsr #14] tst r4, #1 << 23 @ U bit - subne r0, r0, r1 - addeq r0, r0, r1 - str r0, [sp, r5, lsr #14] @ Put register - b Ldata_simple + subne r7, r0, r1 + addeq r7, r0, r1 + b Ldata_saver7 /* * Function: arm6_7_check_bugs (void) @@ -336,8 +241,22 @@ mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip + mov pc, lr + _arm6_7_proc_init: + mov pc, lr + _arm6_7_proc_fin: + mrs r0, cpsr + orr r0, r0, #F_BIT | I_BIT + msr cpsr, r0 + mov r0, #0x31 @ ....S..DP...M + mcr p15, 0, r0, c1, c0, 0 @ disable caches + mov pc, lr + +ENTRY(cpu_arm6_do_idle) +ENTRY(cpu_arm7_do_idle) + mov r0, #-EINVAL mov pc, lr /* @@ -379,23 +298,22 @@ _arm6_7_set_pte: str r1, [r0], #-1024 @ linux version + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + bic r2, r1, #0xff0 bic r2, r2, #3 orr r2, r2, #HPTE_TYPE_SMALL - tst r1, #LPTE_USER | LPTE_EXEC + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? orrne r2, r2, #HPTE_AP_READ - tst r1, #LPTE_WRITE - tstne r1, #LPTE_DIRTY - orrne r2, r2, #HPTE_AP_WRITE - - tst r1, #LPTE_PRESENT - tstne r1, #LPTE_YOUNG - moveq r2, #0 + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young + movne r2, #0 str r2, [r0] @ hardware version - mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) mov pc, lr /* @@ -403,24 +321,53 @@ * * Notes : This sets up everything for a reset */ -_arm6_7_reset: mrs r1, cpsr - orr r1, r1, #F_BIT|I_BIT - msr cpsr, r1 - mov r0, #0 - mcr p15, 0, r0, c7, c0, 0 @ flush cache - mcr p15, 0, r0, c5, c0, 0 @ flush TLB - mov r1, #F_BIT | I_BIT | 3 +_arm6_7_reset: + mov r1, #0 + mcr p15, 0, r1, c7, c0, 0 @ flush cache + mcr p15, 0, r1, c5, c0, 0 @ flush TLB + mov r1, #0x30 + mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc + mov pc, r0 + +cpu_armvlsi_name: + .asciz "ARM/VLSI" +cpu_arm6_name: .asciz "ARM 6" +cpu_arm610_name: + .asciz "ARM 610" +cpu_arm7_name: .asciz "ARM 7" +cpu_arm710_name: + .asciz "ARM 710" + .align + + .section ".text.init", #alloc, #execinstr + +__arm6_setup: mov r0, #0 + mcr p15, 0, r0, c7, c0 @ flush caches on v3 + mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mov r0, #0x3d @ ....S..DPWC.M + orr r0, r0, #0x100 + mov pc, lr + +__arm7_setup: mov r0, #0 + mcr p15, 0, r0, c7, c0 @ flush caches on v3 + mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mov r0, #0x7d @ ....S.LDPWC.M + orr r0, r0, #0x100 mov pc, lr /* * Purpose : Function pointers used to access above functions - all calls * come through these */ -_arm6_name: .ascii "arm6\0" - .align - -ENTRY(arm6_processor_functions) - .word _arm6_name @ 0 + .type arm6_processor_functions, #object +arm6_processor_functions: + .word cpu_arm6_name @ 0 .word _arm6_7_switch_to @ 4 .word _arm6_data_abort @ 8 .word _arm6_7_check_bugs @ 12 @@ -441,16 +388,17 @@ .word _arm6_7_flush_cache @ 68 .word _arm6_7_flush_cache @ 72 + .word 0 + .word cpu_arm6_do_idle + .size arm6_processor_functions, . - arm6_processor_functions /* * Purpose : Function pointers used to access above functions - all calls * come through these */ -_arm7_name: .ascii "arm7\0" - .align - -ENTRY(arm7_processor_functions) - .word _arm7_name @ 0 + .type arm7_processor_functions, #object +arm7_processor_functions: + .word cpu_arm7_name @ 0 .word _arm6_7_switch_to @ 4 .word _arm7_data_abort @ 8 .word _arm6_7_check_bugs @ 12 @@ -471,3 +419,93 @@ .word _arm6_7_flush_cache @ 68 .word _arm6_7_flush_cache @ 72 + .word 0 + .word cpu_arm7_do_idle + .size arm7_processor_functions, . - arm7_processor_functions + + .type cpu_arm6_info, #object +cpu_arm6_info: + .long cpu_armvlsi_name + .long cpu_arm6_name + .size cpu_arm6_info, . - cpu_arm6_info + + .type cpu_arm610_info, #object +cpu_arm610_info: + .long cpu_armvlsi_name + .long cpu_arm610_name + .size cpu_arm610_info, . - cpu_Arm610_info + + .type cpu_arm7_info, #object +cpu_arm7_info: + .long cpu_armvlsi_name + .long cpu_arm7_name + .size cpu_arm7_info, . - cpu_arm7_info + + .type cpu_arm710_info, #object +cpu_arm710_info: + .long cpu_armvlsi_name + .long cpu_arm710_name + .size cpu_arm710_info, . - cpu_arm710_info + + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv3" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v3" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm6_proc_info, #object +__arm6_proc_info: + .long 0x41560600 + .long 0xfffffff0 + .long 0x00000c12 + b __arm6_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm6_info + .long arm6_processor_functions + .size __arm6_proc_info, . - __arm6_proc_info + + .type __arm610_proc_info, #object +__arm610_proc_info: + .long 0x41560610 + .long 0xfffffff0 + .long 0x00000c12 + b __arm6_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm610_info + .long arm6_processor_functions + .size __arm610_proc_info, . - __arm610_proc_info + + .type __arm7_proc_info, #object +__arm7_proc_info: + .long 0x41007000 + .long 0xffffff00 + .long 0x00000c12 + b __arm7_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm7_info + .long arm7_processor_functions + .size __arm7_proc_info, . - __arm7_proc_info + + .type __arm710_proc_info, #object +__arm710_proc_info: + .long 0x41007100 + .long 0xfff8ff00 + .long 0x00000c12 + b __arm7_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_26BIT + .long cpu_arm710_info + .long arm7_processor_functions + .size __arm710_proc_info, . - __arm710_proc_info diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.2.17/arch/arm/mm/proc-sa110.S Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/mm/proc-sa110.S Fri Sep 15 23:28:37 2000 @@ -1,13 +1,14 @@ /* - * linux/arch/arm/mm/sa110.S: MMU functions for SA110 + * linux/arch/arm/mm/proc-sa110.S: MMU functions for SA110 * - * (C) 1997 Russell King + * (C) 1997-1999 Russell King * * These are the low level assembler for performing cache and TLB - * functions on the sa110. + * functions on the StrongARM-110. */ #include #include +#include #include #include "../lib/constants.h" @@ -15,6 +16,7 @@ * is larger than this, then we flush the whole cache */ #define MAX_AREA_SIZE 32768 +#define FLUSH_OFFSET 32768 .data Lclean_switch: .long 0 @@ -29,12 +31,12 @@ mov r2, #1 _sa110_flush_cache_all_r2: ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE ldr r1, [r3] ands r1, r1, #1 eor r1, r1, #1 str r1, [r3] - ldr ip, =FLUSH_BASE - addne ip, ip, #32768 + addne ip, ip, #FLUSH_OFFSET add r1, ip, #16384 @ only necessary for 16k 1: ldr r3, [ip], #32 teq r1, ip @@ -152,16 +154,17 @@ _sa110_flush_ram_page: mov r1, #4096 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c6, 1 @ flush D entry add r0, r0, #32 mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c6, 1 @ flush D entry add r0, r0, #32 - subs r1, r1, #64 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #32 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #32 + subs r1, r1, #128 bne 1b mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c7, c5, 0 @ flush I cache mov pc, lr /* @@ -179,7 +182,7 @@ * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags) * Params : address Area start address * : end Area end address - * : flags b0 = I cache as well + * : flags b0 = I-TLB as well * Purpose : flush a TLB entry */ .align 5 @@ -193,7 +196,7 @@ mcrlt p15, 0, r0, c8, c6, 1 @ flush D TLB entry addlt r0, r0, #4096 blt 1b - tst r2, #1 + teq r2, #0 mcrne p15, 0, r3, c8, c5, 0 @ flush I TLB mov pc, lr @@ -220,18 +223,15 @@ */ .align 5 _sa110_switch_to: - stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + stmfd sp!, {r4 - r10, fp, lr} @ Store most regs on stack mrs ip, cpsr stmfd sp!, {ip} @ Save cpsr_SVC ldr r2, [r0, #TSS_MEMMAP] @ Get old page tables str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r4, [r1, #TSK_ADDR_LIMIT] - teq r4, #0 - moveq r4, #DOM_KERNELDOMAIN - movne r4, #DOM_USERDOMAIN - mcr p15, 0, r4, c3, c0 @ Set segment + ldr r5, [r1, #TSS_DOMAIN] ldr r4, [r1, #TSS_MEMMAP] @ Page table pointer + mcr p15, 0, r5, c3, c0 @ Set segment /* * Flushing the cache is nightmarishly slow, so we take any excuse * to get out of it. If the old page table is the same as the new, @@ -247,7 +247,7 @@ eor r2, r2, #1 str r2, [r3] ldr r2, =FLUSH_BASE - addne r2, r2, #32768 + addne r2, r2, #FLUSH_OFFSET add r1, r2, #16384 @ only necessary for 16k 1: ldr r3, [r2], #32 teq r1, r2 @@ -259,7 +259,7 @@ mcr p15, 0, r1, c8, c7, 0 @ flush TLBs 2: ldmfd sp!, {ip} msr spsr, ip @ Save tasks CPSR into SPSR for this return - ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously + ldmfd sp!, {r4 - r10, fp, pc}^ @ Load all regs saved previously /* * Function: sa110_data_abort () @@ -288,7 +288,8 @@ */ .align 5 _sa110_set_pmd: str r1, [r0] - mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr /* @@ -317,7 +318,8 @@ str r2, [r0] @ hardware version mov r0, r0 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB mov pc, lr /* @@ -330,36 +332,83 @@ mrs ip, cpsr bic ip, ip, #F_BIT msr cpsr, ip + mov pc, lr _sa110_proc_init: + mov r0, #0 + mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching + mov pc, lr + _sa110_proc_fin: + stmfd sp!, {r1, lr} + mrs r0, cpsr + orr r0, r0, #F_BIT | I_BIT + msr cpsr, r0 + bl _sa110_flush_cache_all @ clean caches + mov r0, #0 + mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {r1, pc} + + .align 5 +ENTRY(cpu_sa110_do_idle) + mov r0, #0 + mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching + 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 /* * Function: sa110_reset * Notes : This sets up everything for a reset */ -_sa110_reset: mrs r1, cpsr - orr r1, r1, #F_BIT | I_BIT - msr cpsr, r1 - stmfd sp!, {r1, lr} - mov r2, #1 - bl _sa110_flush_cache_all - bl _sa110_flush_tlb_all +_sa110_reset: + mov ip, #0 mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ flush I & D tlbs mrc p15, 0, r0, c1, c0, 0 @ ctrl register - bic r0, r0, #0x1800 - bic r0, r0, #0x000f - ldmfd sp!, {r1, pc} + bic r0, r0, #0x000f @ ............wcam + bic r0, r0, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 + mov pc, r0 /* * Purpose : Function pointers used to access above functions - all calls * come through these */ -_sa110_name: .ascii "sa110\0" + +cpu_manu_name: .asciz "Intel" +ENTRY(cpu_sa110_name) + .asciz "StrongARM-110" .align -ENTRY(sa110_processor_functions) - .word _sa110_name @ 0 + .section ".text.init", #alloc, #execinstr + +__sa110_setup: mov r0, #0 + mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ flush I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + orr r0, r0, #0x003d @ ..........DPWC.M + orr r0, r0, #0x1100 @ ...I...S........ + mov pc, lr + + .type sa110_processor_functions, #object +sa110_processor_functions: + .word cpu_sa110_name @ 0 .word _sa110_switch_to @ 4 .word _sa110_data_abort @ 8 .word _sa110_check_bugs @ 12 @@ -381,3 +430,38 @@ .word _sa110_cache_wback_area @ 68 .word _sa110_cache_purge_area @ 72 + .word 0 + .word cpu_sa110_do_idle + .size sa110_processor_functions, . - sa110_processor_functions + + .type cpu_sa110_info, #object +cpu_sa110_info: + .long cpu_manu_name + .long cpu_sa110_name + .size cpu_sa110_info, . - cpu_sa110_info + + .type cpu_arch_name, #object +cpu_arch_name: .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __sa110_proc_info,#object +__sa110_proc_info: + .long 0x4401a100 + .long 0xfffffff0 + .long 0x00000c02 + b __sa110_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_sa110_info + .long sa110_processor_functions + .size __sa110_proc_info, . - __sa110_proc_info + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/ARM-gcc.h linux/arch/arm/nwfpe/ARM-gcc.h --- v2.2.17/arch/arm/nwfpe/ARM-gcc.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/ARM-gcc.h Fri Sep 15 23:28:37 2000 @@ -0,0 +1,128 @@ + +/* +------------------------------------------------------------------------------- +One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined. +------------------------------------------------------------------------------- +*/ +#define LITTLEENDIAN + +/* +------------------------------------------------------------------------------- +The macro `BITS64' can be defined to indicate that 64-bit integer types are +supported by the compiler. +------------------------------------------------------------------------------- +*/ +#define BITS64 + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines the most convenient type that holds +integers of at least as many bits as specified. For example, `uint8' should +be the most convenient type that can hold unsigned integers of as many as +8 bits. The `flag' type must be able to hold either a 0 or 1. For most +implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +to the same as `int'. +------------------------------------------------------------------------------- +*/ +typedef char flag; +typedef unsigned char uint8; +typedef signed char int8; +typedef int uint16; +typedef int int16; +typedef unsigned int uint32; +typedef signed int int32; +#ifdef BITS64 +typedef unsigned long long int bits64; +typedef signed long long int sbits64; +#endif + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines a type that holds integers +of _exactly_ the number of bits specified. For instance, for most +implementation of C, `bits16' and `sbits16' should be `typedef'ed to +`unsigned short int' and `signed short int' (or `short int'), respectively. +------------------------------------------------------------------------------- +*/ +typedef unsigned char bits8; +typedef signed char sbits8; +typedef unsigned short int bits16; +typedef signed short int sbits16; +typedef unsigned int bits32; +typedef signed int sbits32; +#ifdef BITS64 +typedef unsigned long long int uint64; +typedef signed long long int int64; +#endif + +#ifdef BITS64 +/* +------------------------------------------------------------------------------- +The `LIT64' macro takes as its argument a textual integer literal and if +necessary ``marks'' the literal as having a 64-bit integer type. For +example, the Gnu C Compiler (`gcc') requires that 64-bit literals be +appended with the letters `LL' standing for `long long', which is `gcc's +name for the 64-bit integer type. Some compilers may allow `LIT64' to be +defined as the identity macro: `#define LIT64( a ) a'. +------------------------------------------------------------------------------- +*/ +#define LIT64( a ) a##LL +#endif + +/* +------------------------------------------------------------------------------- +The macro `INLINE' can be used before functions that should be inlined. If +a compiler does not support explicit inlining, this macro should be defined +to be `static'. +------------------------------------------------------------------------------- +*/ +#define INLINE extern __inline__ + + +/* For use as a GCC soft-float library we need some special function names. */ + +#ifdef __LIBFLOAT__ + +/* Some 32-bit ops can be mapped straight across by just changing the name. */ +#define float32_add __addsf3 +#define float32_sub __subsf3 +#define float32_mul __mulsf3 +#define float32_div __divsf3 +#define int32_to_float32 __floatsisf +#define float32_to_int32_round_to_zero __fixsfsi +#define float32_to_uint32_round_to_zero __fixunssfsi + +/* These ones go through the glue code. To avoid namespace pollution + we rename the internal functions too. */ +#define float32_eq ___float32_eq +#define float32_le ___float32_le +#define float32_lt ___float32_lt + +/* All the 64-bit ops have to go through the glue, so we pull the same + trick. */ +#define float64_add ___float64_add +#define float64_sub ___float64_sub +#define float64_mul ___float64_mul +#define float64_div ___float64_div +#define int32_to_float64 ___int32_to_float64 +#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero +#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero +#define float64_to_float32 ___float64_to_float32 +#define float32_to_float64 ___float32_to_float64 +#define float64_eq ___float64_eq +#define float64_le ___float64_le +#define float64_lt ___float64_lt + +#if 0 +#define float64_add __adddf3 +#define float64_sub __subdf3 +#define float64_mul __muldf3 +#define float64_div __divdf3 +#define int32_to_float64 __floatsidf +#define float64_to_int32_round_to_zero __fixdfsi +#define float64_to_uint32_round_to_zero __fixunsdfsi +#define float64_to_float32 __truncdfsf2 +#define float32_to_float64 __extendsfdf2 +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/ChangeLog linux/arch/arm/nwfpe/ChangeLog --- v2.2.17/arch/arm/nwfpe/ChangeLog Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/ChangeLog Fri Sep 15 23:28:37 2000 @@ -0,0 +1,20 @@ +1998-11-23 Scott Bambrough + + * README.FPE - fix typo in description of lfm/sfm instructions + * NOTES - Added file to describe known bugs/problems + * fpmodule.c - Changed version number to 0.94 + +1998-11-20 Scott Bambrough + + * README.FPE - fix description of URD, NRM instructions + * TODO - remove URD, NRM instructions from TODO list + * single_cpdo.c - implement URD, NRM + * double_cpdo.c - implement URD, NRM + * extended_cpdo.c - implement URD, NRM + +1998-11-19 Scott Bambrough + + * ChangeLog - Added this file to track changes made. + * fpa11.c - added code to initialize register types to typeNone + * fpa11_cpdt.c - fixed bug in storeExtended (typeExtended changed to + typeDouble in switch statement) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/Makefile linux/arch/arm/nwfpe/Makefile --- v2.2.17/arch/arm/nwfpe/Makefile Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/Makefile Fri Sep 15 23:28:37 2000 @@ -0,0 +1,31 @@ +# +# linux/arch/arm/nwfpe/Makefile +# +# Copyright (C) 1998, 1999 Philip Blundell +# + +NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ + fpmodule.o fpopcode.o softfloat.o \ + single_cpdo.o double_cpdo.o extended_cpdo.o + +ifeq ($(CONFIG_CPU_26),y) +NWFPE_OBJS += entry26.o +else +NWFPE_OBJS += entry.o +endif + +L_TARGET := math-emu.a + +ifeq ($(CONFIG_NWFPE),y) +L_OBJS = $(NWFPE_OBJS) +else + ifeq ($(CONFIG_NWFPE),m) + M_OBJS = nwfpe.o + MI_OBJS = $(NWFPE_OBJS) + endif +endif + +include $(TOPDIR)/Rules.make + +nwfpe.o: $(MI_OBJS) $(MIX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/config.h linux/arch/arm/nwfpe/config.h --- v2.2.17/arch/arm/nwfpe/config.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/config.h Fri Sep 15 23:28:37 2000 @@ -0,0 +1,31 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 __CONFIG_H__ +#define __CONFIG_H__ + +#if 1 +#define C_SYMBOL_NAME(foo) foo +#else +#define C_SYMBOL_NAME(foo) _##foo +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/double_cpdo.c linux/arch/arm/nwfpe/double_cpdo.c --- v2.2.17/arch/arm/nwfpe/double_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/double_cpdo.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,293 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" + +extern FPA11 *fpa11; + +float64 getDoubleConstant(unsigned int); + +float64 float64_exp(float64 Fm); +float64 float64_ln(float64 Fm); +float64 float64_sin(float64 rFm); +float64 float64_cos(float64 rFm); +float64 float64_arcsin(float64 rFm); +float64 float64_arctan(float64 rFm); +float64 float64_log(float64 rFm); +float64 float64_tan(float64 rFm); +float64 float64_arccos(float64 rFm); +float64 float64_pow(float64 rFn,float64 rFm); +float64 float64_pol(float64 rFn,float64 rFm); + +unsigned int DoubleCPDO(const unsigned int opcode) +{ + float64 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //fp_printk("DoubleCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getDoubleConstant(Fm); + } + else + { + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + rFm = float32_to_float64(fpa11->fpreg[Fm].fValue.fSingle); + break; + + case typeDouble: + rFm = fpa11->fpreg[Fm].fValue.fDouble; + break; + + case typeExtended: + // !! patb + //fp_printk("not implemented! why not?\n"); + //!! ScottB + // should never get here, if extended involved + // then other operand should be promoted then + // ExtendedCPDO called. + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + rFn = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + rFn = fpa11->fpreg[Fn].fValue.fDouble; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fValue.fDouble = rFm; + break; + + case MNF_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] ^= 0x80000000; + fpa11->fpreg[Fd].fValue.fDouble = rFm; + } + break; + + case ABS_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] &= 0x7fffffff; + fpa11->fpreg[Fd].fValue.fDouble = rFm; + } + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fValue.fDouble = + int32_to_float64(float64_to_int32(rFm)); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fValue.fDouble = float64_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fpreg[Fd].fType = typeDouble; + return nRc; +} + +#if 0 +float64 float64_exp(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_ln(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_sin(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_cos(float64 rFm) +{ + return rFm; + //series +} + +#if 0 +float64 float64_arcsin(float64 rFm) +{ +//series +} + +float64 float64_arctan(float64 rFm) +{ + //series +} +#endif + +float64 float64_log(float64 rFm) +{ + return float64_div(float64_ln(rFm),getDoubleConstant(7)); +} + +float64 float64_tan(float64 rFm) +{ + return float64_div(float64_sin(rFm),float64_cos(rFm)); +} + +float64 float64_arccos(float64 rFm) +{ +return rFm; + //return float64_sub(halfPi,float64_arcsin(rFm)); +} + +float64 float64_pow(float64 rFn,float64 rFm) +{ + return float64_exp(float64_mul(rFm,float64_ln(rFn))); +} + +float64 float64_pol(float64 rFn,float64 rFm) +{ + return float64_arctan(float64_div(rFn,rFm)); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/entry.S linux/arch/arm/nwfpe/entry.S --- v2.2.17/arch/arm/nwfpe/entry.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/entry.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,126 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell 1998-1999 + + Direct questions, comments to Scott Bambrough + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* This is the kernel's entry point into the floating point emulator. +It is called from the kernel with code similar to this: + + adrsvc al, r9, ret_from_exception @ r9 = normal FP return + adrsvc al, lr, fpundefinstr @ lr = undefined instr return + + get_current_task r10 + mov r8, #1 + strb r8, [r10, #TSK_USED_MATH] @ set current->used_math + add r10, r10, #TSS_FPESAVE @ r10 = workspace + ldr r4, .LC2 + ldr pc, [r4] @ Call FP emulator entry point + +The kernel expects the emulator to return via one of two possible +points of return it passes to the emulator. The emulator, if +successful in its emulation, jumps to ret_from_exception (passed in +r9) and the kernel takes care of returning control from the trap to +the user code. If the emulator is unable to emulate the instruction, +it returns via _fpundefinstr (passed via lr) and the kernel halts the +user program with a core dump. + +On entry to the emulator r10 points to an area of private FP workspace +reserved in the thread structure for this process. This is where the +emulator saves its registers across calls. The first word of this area +is used as a flag to detect the first time a process uses floating point, +so that the emulator startup cost can be avoided for tasks that don't +want it. + +This routine does three things: + +1) It saves SP into a variable called userRegisters. The kernel has +created a struct pt_regs on the stack and saved the user registers +into it. See /usr/include/asm/proc/ptrace.h for details. The +emulator code uses userRegisters as the base of an array of words from +which the contents of the registers can be extracted. + +2) It calls EmulateAll to emulate a floating point instruction. +EmulateAll returns 1 if the emulation was successful, or 0 if not. + +3) If an instruction has been emulated successfully, it looks ahead at +the next instruction. If it is a floating point instruction, it +executes the instruction, without returning to user space. In this +way it repeatedly looks ahead and executes floating point instructions +until it encounters a non floating point instruction, at which time it +returns via _fpreturn. + +This is done to reduce the effect of the trap overhead on each +floating point instructions. GCC attempts to group floating point +instructions to allow the emulator to spread the cost of the trap over +several floating point instructions. */ + + .globl nwfpe_enter +nwfpe_enter: + /* ?? Could put userRegisters and fpa11 into fixed regs during + emulation. This would reduce load/store overhead at the expense + of stealing two regs from the register allocator. Not sure if + it's worth it. */ + ldr r4, =userRegisters + str sp, [r4] @ save pointer to user regs + ldr r4, =fpa11 + str r10, [r4] @ store pointer to our state + mov r4, sp @ use r4 for local pointer + mov r10, lr @ save the failure-return addresses + + ldr r5, [r4, #60] @ get contents of PC; + ldr r0, [r5, #-4] @ get actual instruction into r0 +emulate: + bl EmulateAll @ emulate the instruction + cmp r0, #0 @ was emulation successful + moveq pc, r10 @ no, return failure + +next: +__x1: ldrt r6, [r5], #4 @ get the next instruction and + @ increment PC + + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + movne pc, r9 @ return ok if not a fp insn + + str r5, [r4, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + ldr r1, [r4, #64] @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + b emulate @ if r0 != 0, goto EmulateAll + + @ We need to be prepared for the instruction at __x1 to fault. + @ Emit the appropriate exception gunk to fix things up. + .section .fixup,"ax" + .align +__f1: mov pc, r9 + .previous + .section __ex_table,"a" + .align 3 + .long __x1, __f1 + .previous diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/entry26.S linux/arch/arm/nwfpe/entry26.S --- v2.2.17/arch/arm/nwfpe/entry26.S Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/entry26.S Fri Sep 15 23:28:37 2000 @@ -0,0 +1,112 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell 1998-1999 + + Direct questions, comments to Scott Bambrough + + 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 "../lib/constants.h" + +/* This is the kernel's entry point into the floating point emulator. +It is called from the kernel with code similar to this: + + mov fp, #0 + teqp pc, #I_BIT | MODE_SVC + ldr r4, .LC2 + ldr pc, [r4] @ Call FP module USR entry point + +The kernel expects the emulator to return via one of two possible +points of return it passes to the emulator. The emulator, if +successful in its emulation, jumps to ret_from_exception and the +kernel takes care of returning control from the trap to the user code. +If the emulator is unable to emulate the instruction, it returns to +fpundefinstr and the kernel halts the user program with a core dump. + +This routine does four things: + +1) It saves SP into a variable called userRegisters. The kernel has +created a struct pt_regs on the stack and saved the user registers +into it. See /usr/include/asm/proc/ptrace.h for details. The +emulator code uses userRegisters as the base of an array of words from +which the contents of the registers can be extracted. + +2) It locates the FP emulator work area within the TSS structure and +points `fpa11' to it. + +3) It calls EmulateAll to emulate a floating point instruction. +EmulateAll returns 1 if the emulation was successful, or 0 if not. + +4) If an instruction has been emulated successfully, it looks ahead at +the next instruction. If it is a floating point instruction, it +executes the instruction, without returning to user space. In this +way it repeatedly looks ahead and executes floating point instructions +until it encounters a non floating point instruction, at which time it +returns via _fpreturn. + +This is done to reduce the effect of the trap overhead on each +floating point instructions. GCC attempts to group floating point +instructions to allow the emulator to spread the cost of the trap over +several floating point instructions. */ + + .globl nwfpe_enter +nwfpe_enter: + ldr r4, =userRegisters + str sp, [r4] @ save pointer to user regs + + mov r10, sp, lsr #13 @ find workspace + mov r10, r10, lsl #13 + add r10, r10, #TSS_FPESAVE + + ldr r4, =fpa11 + str r10, [r4] @ store pointer to our state + mov r4, sp @ use r4 for local pointer + + ldr r5, [r4, #60] @ get contents of PC + bic r5, r5, #0xfc000003 + ldr r0, [r5, #-4] @ get actual instruction into r0 + bl EmulateAll @ emulate the instruction +1: cmp r0, #0 @ was emulation successful + beq fpundefinstr @ no, return failure + +next: + ldrt r6, [r5], #4 @ get the next instruction and + @ increment PC + + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + bne ret_from_exception @ return ok if not a fp insn + + ldr r9, [r4, #60] @ get new condition codes + and r9, r9, #0xfc000003 + orr r7, r5, r9 + str r7, [r4, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + mov r1, r9 @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + adr lr, 1b + orr lr, lr, #3 + b EmulateAll @ if r0 != 0, goto EmulateAll diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/extended_cpdo.c linux/arch/arm/nwfpe/extended_cpdo.c --- v2.2.17/arch/arm/nwfpe/extended_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/extended_cpdo.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,276 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" + +floatx80 getExtendedConstant(unsigned int); + +floatx80 floatx80_exp(floatx80 Fm); +floatx80 floatx80_ln(floatx80 Fm); +floatx80 floatx80_sin(floatx80 rFm); +floatx80 floatx80_cos(floatx80 rFm); +floatx80 floatx80_arcsin(floatx80 rFm); +floatx80 floatx80_arctan(floatx80 rFm); +floatx80 floatx80_log(floatx80 rFm); +floatx80 floatx80_tan(floatx80 rFm); +floatx80 floatx80_arccos(floatx80 rFm); +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); + +unsigned int ExtendedCPDO(const unsigned int opcode) +{ + floatx80 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //fp_printk("ExtendedCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getExtendedConstant(Fm); + } + else + { + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle); + break; + + case typeDouble: + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble); + break; + + case typeExtended: + rFm = fpa11->fpreg[Fm].fValue.fExtended; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + break; + + case typeExtended: + rFn = fpa11->fpreg[Fn].fValue.fExtended; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fValue.fExtended = rFm; + break; + + case MNF_CODE: + rFm.high ^= 0x8000; + fpa11->fpreg[Fd].fValue.fExtended = rFm; + break; + + case ABS_CODE: + rFm.high &= 0x7fff; + fpa11->fpreg[Fd].fValue.fExtended = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fValue.fExtended = + int32_to_floatx80(floatx80_to_int32(rFm)); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fValue.fExtended = floatx80_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fpreg[Fd].fType = typeExtended; + return nRc; +} + +#if 0 +floatx80 floatx80_exp(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_ln(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_sin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_cos(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arcsin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arctan(floatx80 rFm) +{ + //series +} + +floatx80 floatx80_log(floatx80 rFm) +{ + return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); +} + +floatx80 floatx80_tan(floatx80 rFm) +{ + return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); +} + +floatx80 floatx80_arccos(floatx80 rFm) +{ + //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); +} + +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) +{ + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); +} + +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) +{ + return floatx80_arctan(floatx80_div(rFn,rFm)); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpa11.c linux/arch/arm/nwfpe/fpa11.c --- v2.2.17/arch/arm/nwfpe/fpa11.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpa11.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,206 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "fpa11.h" +#include "milieu.h" +#include "fpopcode.h" + +#include "fpmodule.h" +#include "fpmodule.inl" + +/* forward declarations */ +unsigned int EmulateCPDO(const unsigned int); +unsigned int EmulateCPDT(const unsigned int); +unsigned int EmulateCPRT(const unsigned int); + +/* Emulator registers */ +FPA11 *fpa11; + +/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ +void resetFPA11(void) +{ + int i; + /* initialize the registers */ + for (i=0;i<=7;i++) + { + fpa11->fpreg[i].fType = typeNone; + } + + /* FPSR: set system id to FP_EMULATOR, clear all other bits */ + fpa11->fpsr = FP_EMULATOR; + + /* FPCR: set SB, AB and DA bits, clear all others */ +#if MAINTAIN_FPCR + fpa11->fpcr = MASK_RESET; +#endif +} + +void SetRoundingMode(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + fpa11->fpcr &= ~MASK_ROUNDING_MODE; +#endif + switch (opcode & MASK_ROUNDING_MODE) + { + default: + case ROUND_TO_NEAREST: + float_rounding_mode = float_round_nearest_even; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_NEAREST; +#endif + break; + + case ROUND_TO_PLUS_INFINITY: + float_rounding_mode = float_round_up; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; +#endif + break; + + case ROUND_TO_MINUS_INFINITY: + float_rounding_mode = float_round_down; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; +#endif + break; + + case ROUND_TO_ZERO: + float_rounding_mode = float_round_to_zero; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_ZERO; +#endif + break; + } +} + +void SetRoundingPrecision(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; +#endif + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + floatx80_rounding_precision = 32; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_SINGLE; +#endif + break; + + case ROUND_DOUBLE: + floatx80_rounding_precision = 64; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_DOUBLE; +#endif + break; + + case ROUND_EXTENDED: + floatx80_rounding_precision = 80; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_EXTENDED; +#endif + break; + + default: floatx80_rounding_precision = 80; + } +} + +/* Emulate the instruction in the opcode. */ +unsigned int EmulateAll(unsigned int opcode) +{ + unsigned int nRc = 0; + + if (fpa11->initflag == 0) /* good place for __builtin_expect */ + { + resetFPA11(); + SetRoundingMode(ROUND_TO_NEAREST); + SetRoundingPrecision(ROUND_EXTENDED); + fpa11->initflag = 1; + } + + if (TEST_OPCODE(opcode,MASK_CPRT)) + { + /* Emulate conversion opcodes. */ + /* Emulate register transfer opcodes. */ + /* Emulate comparison opcodes. */ + nRc = EmulateCPRT(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDO)) + { + /* Emulate monadic arithmetic opcodes. */ + /* Emulate dyadic arithmetic opcodes. */ + nRc = EmulateCPDO(opcode); + } + else if (TEST_OPCODE(opcode,MASK_CPDT)) + { + /* Emulate load/store opcodes. */ + /* Emulate load/store multiple opcodes. */ + nRc = EmulateCPDT(opcode); + } + else + { + /* Invalid instruction detected. Return FALSE. */ + nRc = 0; + } + + return(nRc); +} + +#if 0 +unsigned int EmulateAll1(unsigned int opcode) +{ + switch ((opcode >> 24) & 0xf) + { + case 0xc: + case 0xd: + if ((opcode >> 20) & 0x1) + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformLDF(opcode); break; + case 0x2: return PerformLFM(opcode); break; + default: return 0; + } + } + else + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformSTF(opcode); break; + case 0x2: return PerformSFM(opcode); break; + default: return 0; + } + } + break; + + case 0xe: + if (opcode & 0x10) + return EmulateCPDO(opcode); + else + return EmulateCPRT(opcode); + break; + + default: return 0; + } +} +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpa11.h linux/arch/arm/nwfpe/fpa11.h --- v2.2.17/arch/arm/nwfpe/fpa11.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpa11.h Fri Sep 15 23:28:37 2000 @@ -0,0 +1,61 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 __FPA11_H__ +#define __FPA11_H__ + +/* includes */ +#include "fpsr.h" /* FP control and status register definitions */ +#include "softfloat.h" + +#define typeNone 0x00 +#define typeSingle 0x01 +#define typeDouble 0x02 +#define typeExtended 0x03 + +typedef struct tagFPREG { + unsigned int fType; + union { + float32 fSingle; + float64 fDouble; + floatx80 fExtended; + } fValue; +} FPREG; + +/* FPA11 device model */ +typedef struct tagFPA11 { + int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ + FPREG fpreg[8]; /* 8 floating point registers */ + FPSR fpsr; /* floating point status register */ + FPCR fpcr; /* floating point control register */ +} FPA11; + +extern void resetFPA11(void); +extern void SetRoundingMode(const unsigned int); +extern void SetRoundingPrecision(const unsigned int); + +extern FPA11 *fpa11; + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpa11.inl linux/arch/arm/nwfpe/fpa11.inl --- v2.2.17/arch/arm/nwfpe/fpa11.inl Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpa11.inl Fri Sep 15 23:28:37 2000 @@ -0,0 +1,47 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "fpa11.h" + +/* Read and write floating point status register */ +extern __inline__ unsigned int readFPSR(void) +{ + return(fpa11->fpsr); +} + +extern __inline__ void writeFPSR(FPSR reg) +{ + /* the sysid byte in the status register is readonly */ + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); +} + +/* Read and write floating point control register */ +extern __inline__ FPCR readFPCR(void) +{ + /* clear SB, AB and DA bits before returning FPCR */ + return(fpa11->fpcr & ~MASK_RFC); +} + +extern __inline__ void writeFPCR(FPCR reg) +{ + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpa11_cpdo.c linux/arch/arm/nwfpe/fpa11_cpdo.c --- v2.2.17/arch/arm/nwfpe/fpa11_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpa11_cpdo.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,117 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "fpa11.h" +#include "fpopcode.h" + +unsigned int SingleCPDO(const unsigned int opcode); +unsigned int DoubleCPDO(const unsigned int opcode); +unsigned int ExtendedCPDO(const unsigned int opcode); + +unsigned int EmulateCPDO(const unsigned int opcode) +{ + unsigned int Fd, nType, nDest, nRc = 1; + + //fp_printk("EmulateCPDO(0x%08x)\n",opcode); + + /* Get the destination size. If not valid let Linux perform + an invalid instruction trap. */ + nDest = getDestinationSize(opcode); + if (typeNone == nDest) return 0; + + SetRoundingMode(opcode); + + /* Compare the size of the operands in Fn and Fm. + Choose the largest size and perform operations in that size, + in order to make use of all the precision of the operands. + If Fm is a constant, we just grab a constant of a size + matching the size of the operand in Fn. */ + if (MONADIC_INSTRUCTION(opcode)) + nType = nDest; + else + nType = fpa11->fpreg[getFn(opcode)].fType; + + if (!CONSTANT_FM(opcode)) + { + register unsigned int Fm = getFm(opcode); + if (nType < fpa11->fpreg[Fm].fType) + { + nType = fpa11->fpreg[Fm].fType; + } + } + + switch (nType) + { + case typeSingle : nRc = SingleCPDO(opcode); break; + case typeDouble : nRc = DoubleCPDO(opcode); break; + case typeExtended : nRc = ExtendedCPDO(opcode); break; + default : nRc = 0; + } + + /* If the operation succeeded, check to see if the result in the + destination register is the correct size. If not force it + to be. */ + Fd = getFd(opcode); + nType = fpa11->fpreg[Fd].fType; + if ((0 != nRc) && (nDest != nType)) + { + switch (nDest) + { + case typeSingle: + { + if (typeDouble == nType) + fpa11->fpreg[Fd].fValue.fSingle = + float64_to_float32(fpa11->fpreg[Fd].fValue.fDouble); + else + fpa11->fpreg[Fd].fValue.fSingle = + floatx80_to_float32(fpa11->fpreg[Fd].fValue.fExtended); + } + break; + + case typeDouble: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fValue.fDouble = + float32_to_float64(fpa11->fpreg[Fd].fValue.fSingle); + else + fpa11->fpreg[Fd].fValue.fDouble = + floatx80_to_float64(fpa11->fpreg[Fd].fValue.fExtended); + } + break; + + case typeExtended: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fValue.fExtended = + float32_to_floatx80(fpa11->fpreg[Fd].fValue.fSingle); + else + fpa11->fpreg[Fd].fValue.fExtended = + float64_to_floatx80(fpa11->fpreg[Fd].fValue.fDouble); + } + break; + } + + fpa11->fpreg[Fd].fType = nDest; + } + + return nRc; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpa11_cpdt.c linux/arch/arm/nwfpe/fpa11_cpdt.c --- v2.2.17/arch/arm/nwfpe/fpa11_cpdt.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpa11_cpdt.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,330 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" +#include "fpmodule.h" +#include "fpmodule.inl" + +#include + +extern __inline__ +void loadSingle(const unsigned int Fn,const unsigned int *pMem) +{ + fpa11->fpreg[Fn].fType = typeSingle; + get_user(fpa11->fpreg[Fn].fValue.fSingle, pMem); +} + +extern __inline__ +void loadDouble(const unsigned int Fn,const unsigned int *pMem) +{ + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fDouble; + fpa11->fpreg[Fn].fType = typeDouble; + get_user(p[0], &pMem[1]); + get_user(p[1], &pMem[0]); /* sign & exponent */ +} + +extern __inline__ +void loadExtended(const unsigned int Fn,const unsigned int *pMem) +{ + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fValue.fExtended; + fpa11->fpreg[Fn].fType = typeExtended; + get_user(p[0], &pMem[0]); /* sign & exponent */ + get_user(p[1], &pMem[2]); /* ls bits */ + get_user(p[2], &pMem[1]); /* ms bits */ +} + +extern __inline__ +void loadMultiple(const unsigned int Fn,const unsigned int *pMem) +{ + register unsigned int *p; + unsigned long x; + + p = (unsigned int*)&(fpa11->fpreg[Fn].fValue); + get_user(x, &pMem[0]); + fpa11->fpreg[Fn].fType = (x >> 14) & 0x00000003; + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + case typeDouble: + { + get_user(p[0], &pMem[2]); /* Single */ + get_user(p[1], &pMem[1]); /* double msw */ + p[2] = 0; /* empty */ + } + break; + + case typeExtended: + { + get_user(p[1], &pMem[2]); + get_user(p[2], &pMem[1]); /* msw */ + p[0] = (x & 0x80003fff); + } + break; + } +} + +extern __inline__ +void storeSingle(const unsigned int Fn,unsigned int *pMem) +{ + float32 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fpreg[Fn].fType) + { + case typeDouble: + val = float64_to_float32(fpa11->fpreg[Fn].fValue.fDouble); + break; + + case typeExtended: + val = floatx80_to_float32(fpa11->fpreg[Fn].fValue.fExtended); + break; + + default: val = fpa11->fpreg[Fn].fValue.fSingle; + } + + put_user(p[0], pMem); +} + +extern __inline__ +void storeDouble(const unsigned int Fn,unsigned int *pMem) +{ + float64 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + val = float32_to_float64(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeExtended: + val = floatx80_to_float64(fpa11->fpreg[Fn].fValue.fExtended); + break; + + default: val = fpa11->fpreg[Fn].fValue.fDouble; + } + put_user(p[1], &pMem[0]); /* msw */ + put_user(p[0], &pMem[1]); /* lsw */ +} + +extern __inline__ +void storeExtended(const unsigned int Fn,unsigned int *pMem) +{ + floatx80 val; + register unsigned int *p = (unsigned int*)&val; + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + val = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + val = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + break; + + default: val = fpa11->fpreg[Fn].fValue.fExtended; + } + + put_user(p[0], &pMem[0]); /* sign & exp */ + put_user(p[1], &pMem[2]); + put_user(p[2], &pMem[1]); /* msw */ +} + +extern __inline__ +void storeMultiple(const unsigned int Fn,unsigned int *pMem) +{ + register unsigned int nType, *p; + + p = (unsigned int*)&(fpa11->fpreg[Fn].fValue); + nType = fpa11->fpreg[Fn].fType; + + switch (nType) + { + case typeSingle: + case typeDouble: + { + put_user(p[0], &pMem[2]); /* single */ + put_user(p[1], &pMem[1]); /* double msw */ + put_user(nType << 14, &pMem[0]); + } + break; + + case typeExtended: + { + put_user(p[2], &pMem[1]); /* msw */ + put_user(p[1], &pMem[2]); + put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); + } + break; + } +} + +unsigned int PerformLDF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1; + + //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformSTF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1; + + //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + SetRoundingMode(ROUND_TO_NEAREST); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformLFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal; + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + loadMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +unsigned int PerformSFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal; + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) pBase += 2; + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + storeMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (WRITE_BACK(opcode)) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +#if 1 +unsigned int EmulateCPDT(const unsigned int opcode) +{ + unsigned int nRc = 0; + + //fp_printk("EmulateCPDT(0x%08x)\n",opcode); + + if (LDF_OP(opcode)) + { + nRc = PerformLDF(opcode); + } + else if (LFM_OP(opcode)) + { + nRc = PerformLFM(opcode); + } + else if (STF_OP(opcode)) + { + nRc = PerformSTF(opcode); + } + else if (SFM_OP(opcode)) + { + nRc = PerformSFM(opcode); + } + else + { + nRc = 0; + } + + return nRc; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpa11_cprt.c linux/arch/arm/nwfpe/fpa11_cprt.c --- v2.2.17/arch/arm/nwfpe/fpa11_cprt.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpa11_cprt.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,313 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell, 1999 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "milieu.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" +#include "fpa11.inl" +#include "fpmodule.h" +#include "fpmodule.inl" + +extern flag floatx80_is_nan(floatx80); +extern flag float64_is_nan( float64); +extern flag float32_is_nan( float32); + +void SetRoundingMode(const unsigned int opcode); + +unsigned int PerformFLT(const unsigned int opcode); +unsigned int PerformFIX(const unsigned int opcode); + +static unsigned int +PerformComparison(const unsigned int opcode); + +unsigned int EmulateCPRT(const unsigned int opcode) +{ + unsigned int nRc = 1; + + //fp_printk("EmulateCPRT(0x%08x)\n",opcode); + + if (opcode & 0x800000) + { + /* This is some variant of a comparison (PerformComparison will + sort out which one). Since most of the other CPRT + instructions are oddball cases of some sort or other it makes + sense to pull this out into a fast path. */ + return PerformComparison(opcode); + } + + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ + switch ((opcode & 0x700000) >> 20) + { + case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; + case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; + + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; + case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; + +#if 0 + /* ?? Not at all sure about the mode checks here. Linux never + calls the emulator from a non-USR fault but we always run in SVC + mode. Is there even any point trying to emulate the way FPA11 + behaves in this respect? + + No - and I quote: 'The FPCR may only be present in some + implementations: it is there to control the hardware in an + implementation-specific manner, ... The user mode of the + ARM is not permitted to use this register, and the WFC and + RFC instructions will trap if tried from user mode.' + Therefore, we do not provide the RFC and WFC instructions. + (rmk, 3/05/1999) + */ + case WFC_CODE >> 20: + { + int mode = 0; + __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode)); + nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */ + if (nRc) writeFPCR(readRegister(getRd(opcode))); + } + break; + + case RFC_CODE >> 20: + { + int mode = 0; + __asm__ volatile ("mrs %0, cpsr; and %0, %0, #0x1f;" : : "g" (mode)); + nRc = (0x13 == mode) ? 1 : 0; /* in SVC processor mode? */ + if (nRc) writeRegister(getRd(opcode),readFPCR()); break; + } + break; +#endif + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFLT(const unsigned int opcode) +{ + unsigned int nRc = 1; + SetRoundingMode(opcode); + SetRoundingPrecision(opcode); + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + { + fpa11->fpreg[getFn(opcode)].fType = typeSingle; + fpa11->fpreg[getFn(opcode)].fValue.fSingle = + int32_to_float32(readRegister(getRd(opcode))); + } + break; + + case ROUND_DOUBLE: + { + fpa11->fpreg[getFn(opcode)].fType = typeDouble; + fpa11->fpreg[getFn(opcode)].fValue.fDouble = + int32_to_float64(readRegister(getRd(opcode))); + } + break; + + case ROUND_EXTENDED: + { + fpa11->fpreg[getFn(opcode)].fType = typeExtended; + fpa11->fpreg[getFn(opcode)].fValue.fExtended = + int32_to_floatx80(readRegister(getRd(opcode))); + } + break; + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFIX(const unsigned int opcode) +{ + unsigned int nRc = 1; + unsigned int Fn = getFm(opcode); + + SetRoundingMode(opcode); + + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + { + writeRegister(getRd(opcode), + float32_to_int32(fpa11->fpreg[Fn].fValue.fSingle)); + } + break; + + case typeDouble: + { + writeRegister(getRd(opcode), + float64_to_int32(fpa11->fpreg[Fn].fValue.fDouble)); + } + break; + + case typeExtended: + { + writeRegister(getRd(opcode), + floatx80_to_int32(fpa11->fpreg[Fn].fValue.fExtended)); + } + break; + + default: nRc = 0; + } + + return nRc; +} + + +static unsigned int __inline__ +PerformComparisonOperation(floatx80 Fn, floatx80 Fm) +{ + unsigned int flags = 0; + + /* test for less than condition */ + if (floatx80_lt(Fn,Fm)) + { + flags |= CC_NEGATIVE; + } + + /* test for equal condition */ + if (floatx80_eq(Fn,Fm)) + { + flags |= CC_ZERO; + } + + /* test for greater than or equal condition */ + if (floatx80_lt(Fm,Fn)) + { + flags |= CC_CARRY; + } + + writeConditionCodes(flags); + return 1; +} + +/* This instruction sets the flags N, Z, C, V in the FPSR. */ + +static unsigned int PerformComparison(const unsigned int opcode) +{ + unsigned int Fn, Fm; + floatx80 rFn, rFm; + int e_flag = opcode & 0x400000; /* 1 if CxFE */ + int n_flag = opcode & 0x200000; /* 1 if CNxx */ + unsigned int flags = 0; + + //fp_printk("PerformComparison(0x%08x)\n",opcode); + + Fn = getFn(opcode); + Fm = getFm(opcode); + + /* Check for unordered condition and convert all operands to 80-bit + format. + ?? Might be some mileage in avoiding this conversion if possible. + Eg, if both operands are 32-bit, detect this and do a 32-bit + comparison (cheaper than an 80-bit one). */ + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + //fp_printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fn].fValue.fSingle)) + goto unordered; + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fValue.fSingle); + break; + + case typeDouble: + //fp_printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fn].fValue.fDouble)) + goto unordered; + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fValue.fDouble); + break; + + case typeExtended: + //fp_printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fn].fValue.fExtended)) + goto unordered; + rFn = fpa11->fpreg[Fn].fValue.fExtended; + break; + + default: return 0; + } + + if (CONSTANT_FM(opcode)) + { + //fp_printk("Fm is a constant: #%d.\n",Fm); + rFm = getExtendedConstant(Fm); + if (floatx80_is_nan(rFm)) + goto unordered; + } + else + { + //fp_printk("Fm = r%d which contains a ",Fm); + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + //fp_printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fm].fValue.fSingle)) + goto unordered; + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fValue.fSingle); + break; + + case typeDouble: + //fp_printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fm].fValue.fDouble)) + goto unordered; + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fValue.fDouble); + break; + + case typeExtended: + //fp_printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fm].fValue.fExtended)) + goto unordered; + rFm = fpa11->fpreg[Fm].fValue.fExtended; + break; + + default: return 0; + } + } + + if (n_flag) + { + rFm.high ^= 0x8000; + } + + return PerformComparisonOperation(rFn,rFm); + + unordered: + /* ?? The FPA data sheet is pretty vague about this, in particular + about whether the non-E comparisons can ever raise exceptions. + This implementation is based on a combination of what it says in + the data sheet, observation of how the Acorn emulator actually + behaves (and how programs expect it to) and guesswork. */ + flags |= CC_OVERFLOW; + + if (BIT_AC & readFPSR()) flags |= CC_CARRY; + + if (e_flag) float_raise(float_flag_invalid); + + writeConditionCodes(flags); + return 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c --- v2.2.17/arch/arm/nwfpe/fpmodule.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpmodule.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,185 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + (c) Philip Blundell, 1998-1999 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" + +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +/* XXX */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +/* XXX */ + +#include "softfloat.h" +#include "fpopcode.h" +#include "fpmodule.h" +#include "fpa11.h" +#include "fpa11.inl" + +/* external data */ +extern FPA11 *fpa11; + +/* kernel symbols required for signal handling */ +typedef struct task_struct* PTASK; + +#ifdef MODULE +int fp_printk(const char *,...); +void fp_send_sig(unsigned long sig, PTASK p, int priv); +#if LINUX_VERSION_CODE > 0x20115 +MODULE_AUTHOR("Scott Bambrough "); +MODULE_DESCRIPTION("NWFPE floating point emulator"); +#endif + +#else +#define fp_printk printk +#define fp_send_sig send_sig +#define kern_fp_enter fp_enter +#endif + +/* kernel function prototypes required */ +void C_SYMBOL_NAME(fp_setup)(void); + +/* external declarations for saved kernel symbols */ +extern unsigned int C_SYMBOL_NAME(kern_fp_enter); + +/* forward declarations */ +extern void nwfpe_enter(void); + +/* Original value of fp_enter from kernel before patched by fpe_init. */ +static unsigned int orig_fp_enter; + +/* Address of user registers on the kernel stack. */ +unsigned int *userRegisters; + +void __init C_SYMBOL_NAME(fpe_version)(void) +{ + static const char szTitle[] = "<4>NetWinder Floating Point Emulator "; + static const char szVersion[] = "V0.94.1 "; + static const char szCopyright[] = "(c) 1998 Corel Computer Corp.\n"; + C_SYMBOL_NAME(fp_printk)(szTitle); + C_SYMBOL_NAME(fp_printk)(szVersion); + C_SYMBOL_NAME(fp_printk)(szCopyright); +} + +int __init fpe_init(void) +{ + /* Display title, version and copyright information. */ + C_SYMBOL_NAME(fpe_version)(); + + /* Save pointer to the old FP handler and then patch ourselves in */ + orig_fp_enter = C_SYMBOL_NAME(kern_fp_enter); + C_SYMBOL_NAME(kern_fp_enter) = (unsigned int)C_SYMBOL_NAME(nwfpe_enter); + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return(fpe_init()); +} + +void cleanup_module(void) +{ + /* Restore the values we saved earlier. */ + C_SYMBOL_NAME(kern_fp_enter) = orig_fp_enter; +} +#endif + +#define _ARM_pc 60 +#define _ARM_cpsr 64 + +/* +ScottB: November 4, 1998 + +Moved this function out of softfloat-specialize into fpmodule.c. +This effectively isolates all the changes required for integrating with the +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying +fpmodule.c to integrate with the NetBSD kernel (I hope!). + +[1/1/99: Not quite true any more unfortunately. There is Linux-specific +code to access data in user space in some other source files at the +moment. --philb] + +float_exception_flags is a global variable in SoftFloat. + +This function is called by the SoftFloat routines to raise a floating +point exception. We check the trap enable byte in the FPSR, and raise +a SIGFPE exception if necessary. If not the relevant bits in the +cumulative exceptions flag byte are set and we return. +*/ + +void float_raise(signed char flags) +{ + register unsigned int fpsr, cumulativeTraps; + +#if 0 + printk(KERN_DEBUG "NWFPE: exception %08x at %08x from %08x\n", flags, + __builtin_return_address(0), userRegisters[15]); +#endif + + /* Keep SoftFloat exception flags up to date. */ + float_exception_flags |= flags; + + /* Read fpsr and initialize the cumulativeTraps. */ + fpsr = readFPSR(); + cumulativeTraps = 0; + + /* For each type of exception, the cumulative trap exception bit is only + set if the corresponding trap enable bit is not set. */ + if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC)) + cumulativeTraps |= BIT_IXC; + if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC)) + cumulativeTraps |= BIT_UFC; + if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC)) + cumulativeTraps |= BIT_OFC; + if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC)) + cumulativeTraps |= BIT_DZC; + if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC)) + cumulativeTraps |= BIT_IOC; + + /* Set the cumulative exceptions flags. */ + if (cumulativeTraps) + writeFPSR(fpsr | cumulativeTraps); + + /* Raise an exception if necessary. */ + if (fpsr & (flags << 16)) + fp_send_sig(SIGFPE, current, 1); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpmodule.h linux/arch/arm/nwfpe/fpmodule.h --- v2.2.17/arch/arm/nwfpe/fpmodule.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpmodule.h Fri Sep 15 23:28:37 2000 @@ -0,0 +1,53 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 __FPMODULE_H__ +#define __FPMODULE_H__ + +#include + +#ifdef CONFIG_CPU_32 +#define REG_ORIG_R0 17 +#define REG_CPSR 16 +#else +#define REG_ORIG_R0 16 +#define REG_CPSR 15 +#endif + +#define REG_PC 15 +#define REG_LR 14 +#define REG_SP 13 +#define REG_IP 12 +#define REG_FP 11 +#define REG_R10 10 +#define REG_R9 9 +#define REG_R9 9 +#define REG_R8 8 +#define REG_R7 7 +#define REG_R6 6 +#define REG_R5 5 +#define REG_R4 4 +#define REG_R3 3 +#define REG_R2 2 +#define REG_R1 1 +#define REG_R0 0 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpmodule.inl linux/arch/arm/nwfpe/fpmodule.inl --- v2.2.17/arch/arm/nwfpe/fpmodule.inl Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpmodule.inl Fri Sep 15 23:28:37 2000 @@ -0,0 +1,88 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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. + */ + +/* Address of user registers on the kernel stack. */ +extern unsigned int *userRegisters; + +extern __inline__ +unsigned int readRegister(const unsigned int nReg) +{ + /* Note: The CPU thinks it has dealt with the current instruction. As + a result the program counter has been advanced to the next + instruction, and points 4 bytes beyond the actual instruction + that caused the invalid instruction trap to occur. We adjust + for this in this routine. LDF/STF instructions with Rn = PC + depend on the PC being correct, as they use PC+8 in their + address calculations. */ + unsigned int val = userRegisters[nReg]; + + if (REG_PC == nReg) + val -= 4; + + return val; +} + +extern __inline__ +void writeRegister(const unsigned int nReg, const unsigned int val) +{ + userRegisters[nReg] = val; +} + +extern __inline__ +unsigned int readCPSR(void) +{ + return (readRegister(REG_CPSR)); +} + +extern __inline__ +void writeCPSR(const unsigned int val) +{ + writeRegister(REG_CPSR, val); +} + +extern __inline__ +unsigned int readConditionCodes(void) +{ +#ifdef __FPEM_TEST__ + return (0); +#else + return (readCPSR() & CC_MASK); +#endif +} + +extern __inline__ +void writeConditionCodes(const unsigned int val) +{ + unsigned int rval; + + /* + * Operate directly on userRegisters since + * the CPSR may be the PC register itself. + */ + rval = userRegisters[REG_CPSR] & ~CC_MASK; + userRegisters[REG_CPSR] = rval | (val & CC_MASK); +} + +extern __inline__ +unsigned int readMemoryInt(unsigned int *pMem) +{ + return *pMem; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpopcode.c linux/arch/arm/nwfpe/fpopcode.c --- v2.2.17/arch/arm/nwfpe/fpopcode.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpopcode.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,164 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpsr.h" +#include "fpa11.h" +#include "fpmodule.h" +#include "fpmodule.inl" + +static floatx80 floatx80Constant[] = { + { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ + { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ + { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ + { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ + { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ + { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ + { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ + { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ +}; + +static float64 float64Constant[] = { + 0x0000000000000000ULL, /* double 0.0 */ + 0x3ff0000000000000ULL, /* double 1.0 */ + 0x4000000000000000ULL, /* double 2.0 */ + 0x4008000000000000ULL, /* double 3.0 */ + 0x4010000000000000ULL, /* double 4.0 */ + 0x4014000000000000ULL, /* double 5.0 */ + 0x3fe0000000000000ULL, /* double 0.5 */ + 0x4024000000000000ULL /* double 10.0 */ +}; + +static float32 float32Constant[] = { + 0x00000000, /* single 0.0 */ + 0x3f800000, /* single 1.0 */ + 0x40000000, /* single 2.0 */ + 0x40400000, /* single 3.0 */ + 0x40800000, /* single 4.0 */ + 0x40a00000, /* single 5.0 */ + 0x3f000000, /* single 0.5 */ + 0x41200000 /* single 10.0 */ +}; + +floatx80 getExtendedConstant(const unsigned int nIndex) +{ + return floatx80Constant[nIndex]; +} + +float64 getDoubleConstant(const unsigned int nIndex) +{ + return float64Constant[nIndex]; +} + +float32 getSingleConstant(const unsigned int nIndex) +{ + return float32Constant[nIndex]; +} + +unsigned int getTransferLength(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case 0x00000000: nRc = 1; break; /* single precision */ + case 0x00008000: nRc = 2; break; /* double precision */ + case 0x00400000: nRc = 3; break; /* extended precision */ + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRegisterCount(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_REGISTER_COUNT) + { + case 0x00000000: nRc = 4; break; + case 0x00008000: nRc = 1; break; + case 0x00400000: nRc = 2; break; + case 0x00408000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRoundingPrecision(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case 0x00000000: nRc = 1; break; + case 0x00000080: nRc = 2; break; + case 0x00080000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getDestinationSize(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_DESTINATION_SIZE) + { + case 0x00000000: nRc = typeSingle; break; + case 0x00000080: nRc = typeDouble; break; + case 0x00080000: nRc = typeExtended; break; + default: nRc = typeNone; + } + + return(nRc); +} + +/* contition code lookup table + index into the table is test code: EQ, NE, ... LT, GT, AL, NV + bit position in short is condition code: NZCV */ +unsigned short aCC[16] = { + 0xF0F0, // EQ == Z set + 0x0F0F, // NE + 0xCCCC, // CS == C set + 0x3333, // CC + 0xFF00, // MI == N set + 0x00FF, // PL + 0xAAAA, // VS == V set + 0x5555, // VC + 0x0C0C, // HI == C set && Z clear + 0xF3F3, // LS == C clear || Z set + 0xAA55, // GE == (N==V) + 0x55AA, // LT == (N!=V) + 0x0A05, // GT == (!Z && (N==V)) + 0xF5FA, // LE == (Z || (N!=V)) + 0xFFFF, // AL always + 0 // NV +}; + +unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) +{ + return (aCC[opcode>>28] >> (ccodes>>28)) & 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpopcode.h linux/arch/arm/nwfpe/fpopcode.h --- v2.2.17/arch/arm/nwfpe/fpopcode.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpopcode.h Fri Sep 15 23:28:37 2000 @@ -0,0 +1,376 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 __FPOPCODE_H__ +#define __FPOPCODE_H__ + +/* +ARM Floating Point Instruction Classes +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO +|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT +|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + +CPDT data transfer instructions + LDF, STF, LFM, SFM + +CPDO dyadic arithmetic instructions + ADF, MUF, SUF, RSF, DVF, RDF, + POW, RPW, RMF, FML, FDV, FRD, POL + +CPDO monadic arithmetic instructions + MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, + SIN, COS, TAN, ASN, ACS, ATN, URD, NRM + +CPRT joint arithmetic/data transfer instructions + FIX (arithmetic followed by load/store) + FLT (load/store followed by arithmetic) + CMF, CNF CMFE, CNFE (comparisons) + WFS, RFS (write/read floating point status register) + WFC, RFC (write/read floating point control register) + +cond condition codes +P pre/post index bit: 0 = postindex, 1 = preindex +U up/down bit: 0 = stack grows down, 1 = stack grows up +W write back bit: 1 = update base register (Rn) +L load/store bit: 0 = store, 1 = load +Rn base register +Rd destination/source register +Fd floating point destination register +Fn floating point source register +Fm floating point source register or floating point constant + +uv transfer length (TABLE 1) +wx register count (TABLE 2) +abcd arithmetic opcode (TABLES 3 & 4) +ef destination size (rounding precision) (TABLE 5) +gh rounding mode (TABLE 6) +j dyadic/monadic bit: 0 = dyadic, 1 = monadic +i constant bit: 1 = constant (TABLE 6) +*/ + +/* +TABLE 1 ++-------------------------+---+---+---------+---------+ +| Precision | u | v | FPSR.EP | length | ++-------------------------+---+---+---------+---------+ +| Single | 0 ü 0 | x | 1 words | +| Double | 1 ü 1 | x | 2 words | +| Extended | 1 ü 1 | x | 3 words | +| Packed decimal | 1 ü 1 | 0 | 3 words | +| Expanded packed decimal | 1 ü 1 | 1 | 4 words | ++-------------------------+---+---+---------+---------+ +Note: x = don't care +*/ + +/* +TABLE 2 ++---+---+---------------------------------+ +| w | x | Number of registers to transfer | ++---+---+---------------------------------+ +| 0 ü 1 | 1 | +| 1 ü 0 | 2 | +| 1 ü 1 | 3 | +| 0 ü 0 | 4 | ++---+---+---------------------------------+ +*/ + +/* +TABLE 3: Dyadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | +| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | +| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | +| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | +| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | +| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | +| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | +| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | +| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | +| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | +| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | +| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | +| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | +| 1 | 1 | 0 | 1 | | undefined instruction | trap | +| 1 | 1 | 1 | 0 | | undefined instruction | trap | +| 1 | 1 | 1 | 1 | | undefined instruction | trap | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: POW, RPW, POL are deprecated, and are available for backwards + compatibility only. +*/ + +/* +TABLE 4: Monadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | +| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | +| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | +| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | +| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | +| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | +| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | +| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | +| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | +| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | +| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | +| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | +| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | +| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | +| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | +| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are + available for backwards compatibility only. +*/ + +/* +TABLE 5 ++-------------------------+---+---+ +| Rounding Precision | e | f | ++-------------------------+---+---+ +| IEEE Single precision | 0 ü 0 | +| IEEE Double precision | 0 ü 1 | +| IEEE Extended precision | 1 ü 0 | +| undefined (trap) | 1 ü 1 | ++-------------------------+---+---+ +*/ + +/* +TABLE 5 ++---------------------------------+---+---+ +| Rounding Mode | g | h | ++---------------------------------+---+---+ +| Round to nearest (default) | 0 ü 0 | +| Round toward plus infinity | 0 ü 1 | +| Round toward negative infinity | 1 ü 0 | +| Round toward zero | 1 ü 1 | ++---------------------------------+---+---+ +*/ + +/* +=== +=== Definitions for load and store instructions +=== +*/ + +/* bit masks */ +#define BIT_PREINDEX 0x01000000 +#define BIT_UP 0x00800000 +#define BIT_WRITE_BACK 0x00200000 +#define BIT_LOAD 0x00100000 + +/* masks for load/store */ +#define MASK_CPDT 0x0c000000 /* data processing opcode */ +#define MASK_OFFSET 0x000000ff +#define MASK_TRANSFER_LENGTH 0x00408000 +#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH +#define MASK_COPROCESSOR 0x00000f00 + +/* Tests for transfer length */ +#define TRANSFER_SINGLE 0x00000000 +#define TRANSFER_DOUBLE 0x00008000 +#define TRANSFER_EXTENDED 0x00400000 +#define TRANSFER_PACKED MASK_TRANSFER_LENGTH + +/* Get the coprocessor number from the opcode. */ +#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) + +/* Get the offset from the opcode. */ +#define getOffset(opcode) (opcode & MASK_OFFSET) + +/* Tests for specific data transfer load/store opcodes. */ +#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) + +#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) +#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) + +#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) +#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) + +#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) +#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) +#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) +#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) +#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) +#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) +#define STORE(opcode) ((opcode & BIT_LOAD) == 0) + +/* +=== +=== Definitions for arithmetic instructions +=== +*/ +/* bit masks */ +#define BIT_MONADIC 0x00008000 +#define BIT_CONSTANT 0x00000008 + +#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) +#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) + +/* instruction identification masks */ +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ +#define MASK_ARITHMETIC_OPCODE 0x00f08000 +#define MASK_DESTINATION_SIZE 0x00080080 + +/* dyadic arithmetic opcodes. */ +#define ADF_CODE 0x00000000 +#define MUF_CODE 0x00100000 +#define SUF_CODE 0x00200000 +#define RSF_CODE 0x00300000 +#define DVF_CODE 0x00400000 +#define RDF_CODE 0x00500000 +#define POW_CODE 0x00600000 +#define RPW_CODE 0x00700000 +#define RMF_CODE 0x00800000 +#define FML_CODE 0x00900000 +#define FDV_CODE 0x00a00000 +#define FRD_CODE 0x00b00000 +#define POL_CODE 0x00c00000 +/* 0x00d00000 is an invalid dyadic arithmetic opcode */ +/* 0x00e00000 is an invalid dyadic arithmetic opcode */ +/* 0x00f00000 is an invalid dyadic arithmetic opcode */ + +/* monadic arithmetic opcodes. */ +#define MVF_CODE 0x00008000 +#define MNF_CODE 0x00108000 +#define ABS_CODE 0x00208000 +#define RND_CODE 0x00308000 +#define SQT_CODE 0x00408000 +#define LOG_CODE 0x00508000 +#define LGN_CODE 0x00608000 +#define EXP_CODE 0x00708000 +#define SIN_CODE 0x00808000 +#define COS_CODE 0x00908000 +#define TAN_CODE 0x00a08000 +#define ASN_CODE 0x00b08000 +#define ACS_CODE 0x00c08000 +#define ATN_CODE 0x00d08000 +#define URD_CODE 0x00e08000 +#define NRM_CODE 0x00f08000 + +/* +=== +=== Definitions for register transfer and comparison instructions +=== +*/ + +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ +#define MASK_CPRT_CODE 0x00f00000 +#define FLT_CODE 0x00000000 +#define FIX_CODE 0x00100000 +#define WFS_CODE 0x00200000 +#define RFS_CODE 0x00300000 +#define WFC_CODE 0x00400000 +#define RFC_CODE 0x00500000 +#define CMF_CODE 0x00900000 +#define CNF_CODE 0x00b00000 +#define CMFE_CODE 0x00d00000 +#define CNFE_CODE 0x00f00000 + +/* +=== +=== Common definitions +=== +*/ + +/* register masks */ +#define MASK_Rd 0x0000f000 +#define MASK_Rn 0x000f0000 +#define MASK_Fd 0x00007000 +#define MASK_Fm 0x00000007 +#define MASK_Fn 0x00070000 + +/* condition code masks */ +#define CC_MASK 0xf0000000 +#define CC_NEGATIVE 0x80000000 +#define CC_ZERO 0x40000000 +#define CC_CARRY 0x20000000 +#define CC_OVERFLOW 0x10000000 +#define CC_EQ 0x00000000 +#define CC_NE 0x10000000 +#define CC_CS 0x20000000 +#define CC_HS CC_CS +#define CC_CC 0x30000000 +#define CC_LO CC_CC +#define CC_MI 0x40000000 +#define CC_PL 0x50000000 +#define CC_VS 0x60000000 +#define CC_VC 0x70000000 +#define CC_HI 0x80000000 +#define CC_LS 0x90000000 +#define CC_GE 0xa0000000 +#define CC_LT 0xb0000000 +#define CC_GT 0xc0000000 +#define CC_LE 0xd0000000 +#define CC_AL 0xe0000000 +#define CC_NV 0xf0000000 + +/* rounding masks/values */ +#define MASK_ROUNDING_MODE 0x00000060 +#define ROUND_TO_NEAREST 0x00000000 +#define ROUND_TO_PLUS_INFINITY 0x00000020 +#define ROUND_TO_MINUS_INFINITY 0x00000040 +#define ROUND_TO_ZERO 0x00000060 + +#define MASK_ROUNDING_PRECISION 0x00080080 +#define ROUND_SINGLE 0x00000000 +#define ROUND_DOUBLE 0x00000080 +#define ROUND_EXTENDED 0x00080000 + +/* Get the condition code from the opcode. */ +#define getCondition(opcode) (opcode >> 28) + +/* Get the source register from the opcode. */ +#define getRn(opcode) ((opcode & MASK_Rn) >> 16) + +/* Get the destination floating point register from the opcode. */ +#define getFd(opcode) ((opcode & MASK_Fd) >> 12) + +/* Get the first source floating point register from the opcode. */ +#define getFn(opcode) ((opcode & MASK_Fn) >> 16) + +/* Get the second source floating point register from the opcode. */ +#define getFm(opcode) (opcode & MASK_Fm) + +/* Get the destination register from the opcode. */ +#define getRd(opcode) ((opcode & MASK_Rd) >> 12) + +/* Get the rounding mode from the opcode. */ +#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) + +float32 getSingleConstant(const unsigned int nIndex); +float64 getDoubleConstant(const unsigned int nIndex); +floatx80 getExtendedConstant(const unsigned int nIndex); + +unsigned int getRegisterCount(const unsigned int opcode); +unsigned int getDestinationSize(const unsigned int opcode); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/fpsr.h linux/arch/arm/nwfpe/fpsr.h --- v2.2.17/arch/arm/nwfpe/fpsr.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/fpsr.h Fri Sep 15 23:28:37 2000 @@ -0,0 +1,108 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 __FPSR_H__ +#define __FPSR_H__ + +/* +The FPSR is a 32 bit register consisting of 4 parts, each exactly +one byte. + + SYSTEM ID + EXCEPTION TRAP ENABLE BYTE + SYSTEM CONTROL BYTE + CUMULATIVE EXCEPTION FLAGS BYTE + +The FPCR is a 32 bit register consisting of bit flags. +*/ + +/* SYSTEM ID +------------ +Note: the system id byte is read only */ + +typedef unsigned int FPSR; /* type for floating point status register */ +typedef unsigned int FPCR; /* type for floating point control register */ + +#define MASK_SYSID 0xff000000 +#define BIT_HARDWARE 0x80000000 +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ +#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ + +/* EXCEPTION TRAP ENABLE BYTE +----------------------------- */ + +#define MASK_TRAP_ENABLE 0x00ff0000 +#define MASK_TRAP_ENABLE_STRICT 0x001f0000 +#define BIT_IXE 0x00100000 /* inexact exception enable */ +#define BIT_UFE 0x00080000 /* underflow exception enable */ +#define BIT_OFE 0x00040000 /* overflow exception enable */ +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ + +/* SYSTEM CONTROL BYTE +---------------------- */ + +#define MASK_SYSTEM_CONTROL 0x0000ff00 +#define MASK_TRAP_STRICT 0x00001f00 + +#define BIT_AC 0x00001000 /* use alternative C-flag definition + for compares */ +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ +#define BIT_NE 0x00000200 /* NaN exception bit */ +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ + +/* CUMULATIVE EXCEPTION FLAGS BYTE +---------------------------------- */ + +#define MASK_EXCEPTION_FLAGS 0x000000ff +#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f + +#define BIT_IXC 0x00000010 /* inexact exception flag */ +#define BIT_UFC 0x00000008 /* underflow exception flag */ +#define BIT_OFC 0x00000004 /* overfloat exception flag */ +#define BIT_DZC 0x00000002 /* divide by zero exception flag */ +#define BIT_IOC 0x00000001 /* invalid operation exception flag */ + +/* Floating Point Control Register +----------------------------------*/ + +#define BIT_RU 0x80000000 /* rounded up bit */ +#define BIT_IE 0x10000000 /* inexact bit */ +#define BIT_MO 0x08000000 /* mantissa overflow bit */ +#define BIT_EO 0x04000000 /* exponent overflow bit */ +#define BIT_SB 0x00000800 /* store bounce */ +#define BIT_AB 0x00000400 /* arithmetic bounce */ +#define BIT_RE 0x00000200 /* rounding exception */ +#define BIT_DA 0x00000100 /* disable FPA */ + +#define MASK_OP 0x00f08010 /* AU operation code */ +#define MASK_PR 0x00080080 /* AU precision */ +#define MASK_S1 0x00070000 /* AU source register 1 */ +#define MASK_S2 0x00000007 /* AU source register 2 */ +#define MASK_DS 0x00007000 /* AU destination register */ +#define MASK_RM 0x00000060 /* AU rounding mode */ +#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ +#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ +#define MASK_WFC MASK_RESET +#define MASK_RFC ~MASK_RESET + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/milieu.h linux/arch/arm/nwfpe/milieu.h --- v2.2.17/arch/arm/nwfpe/milieu.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/milieu.h Fri Sep 15 23:28:37 2000 @@ -0,0 +1,48 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Include common integer types and flags. +------------------------------------------------------------------------------- +*/ +#include "ARM-gcc.h" + +/* +------------------------------------------------------------------------------- +Symbolic Boolean literals. +------------------------------------------------------------------------------- +*/ +enum { + FALSE = 0, + TRUE = 1 +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/single_cpdo.c linux/arch/arm/nwfpe/single_cpdo.c --- v2.2.17/arch/arm/nwfpe/single_cpdo.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/single_cpdo.c Fri Sep 15 23:28:37 2000 @@ -0,0 +1,259 @@ +/* + NetWinder Floating Point Emulator + (c) Corel Computer Corporation, 1998 + + Direct questions, comments to Scott Bambrough + + 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 "config.h" +#include "milieu.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.h" + +float32 getSingleConstant(unsigned int); + +float32 float32_exp(float32 Fm); +float32 float32_ln(float32 Fm); +float32 float32_sin(float32 rFm); +float32 float32_cos(float32 rFm); +float32 float32_arcsin(float32 rFm); +float32 float32_arctan(float32 rFm); +float32 float32_log(float32 rFm); +float32 float32_tan(float32 rFm); +float32 float32_arccos(float32 rFm); +float32 float32_pow(float32 rFn,float32 rFm); +float32 float32_pol(float32 rFn,float32 rFm); + +unsigned int SingleCPDO(const unsigned int opcode) +{ + float32 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getSingleConstant(Fm); + } + else + { + switch (fpa11->fpreg[Fm].fType) + { + case typeSingle: + rFm = fpa11->fpreg[Fm].fValue.fSingle; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fpreg[Fn].fType) + { + case typeSingle: + rFn = fpa11->fpreg[Fn].fValue.fSingle; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fValue.fSingle = rFm; + break; + + case MNF_CODE: + rFm ^= 0x80000000; + fpa11->fpreg[Fd].fValue.fSingle = rFm; + break; + + case ABS_CODE: + rFm &= 0x7fffffff; + fpa11->fpreg[Fd].fValue.fSingle = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fValue.fSingle = + int32_to_float32(float32_to_int32(rFm)); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fValue.fSingle = float32_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fpreg[Fd].fType = typeSingle; + return nRc; +} + +#if 0 +float32 float32_exp(float32 Fm) +{ +//series +} + +float32 float32_ln(float32 Fm) +{ +//series +} + +float32 float32_sin(float32 rFm) +{ +//series +} + +float32 float32_cos(float32 rFm) +{ +//series +} + +float32 float32_arcsin(float32 rFm) +{ +//series +} + +float32 float32_arctan(float32 rFm) +{ + //series +} + +float32 float32_arccos(float32 rFm) +{ + //return float32_sub(halfPi,float32_arcsin(rFm)); +} + +float32 float32_log(float32 rFm) +{ + return float32_div(float32_ln(rFm),getSingleConstant(7)); +} + +float32 float32_tan(float32 rFm) +{ + return float32_div(float32_sin(rFm),float32_cos(rFm)); +} + +float32 float32_pow(float32 rFn,float32 rFm) +{ + return float32_exp(float32_mul(rFm,float32_ln(rFn))); +} + +float32 float32_pol(float32 rFn,float32 rFm) +{ + return float32_arctan(float32_div(rFn,rFm)); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/softfloat-macros linux/arch/arm/nwfpe/softfloat-macros --- v2.2.17/arch/arm/nwfpe/softfloat-macros Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/softfloat-macros Fri Sep 15 23:28:37 2000 @@ -0,0 +1,740 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 32, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 64, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +{ + bits64 z; + + __asm__("@shift64RightJamming -- start"); + if ( count == 0 ) { + z = a; + } + else if ( count < 64 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + __asm__("@shift64RightJamming -- end"); + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 +_plus_ the number of bits given in `count'. The shifted result is at most +64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The +bits shifted off form a second 64-bit result as follows: The _last_ bit +shifted off is the most-significant bit of the extra result, and the other +63 bits of the extra result are all zero if and only if _all_but_the_last_ +bits shifted off were all zero. This extra result is stored in the location +pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. + (This routine makes more sense if `a0' and `a1' are considered to form a +fixed-point value with binary point between `a0' and `a1'. This fixed-point +value is shifted right by the number of bits given in `count', and the +integer part of the result is returned at the location pointed to by +`z0Ptr'. The fractional part of the result may be slightly corrupted as +described above, and is returned at the location pointed to by `z1Ptr'.) +------------------------------------------------------------------------------- +*/ +INLINE void + shift64ExtraRightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' can be arbitrarily large; in particular, if `count' is greater +than 128, the result will be 0. The result is broken into two 64-bit pieces +which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128Right( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. If any nonzero bits are shifted off, they +are ``jammed'' into the least significant bit of the result by setting the +least significant bit to 1. The value of `count' can be arbitrarily large; +in particular, if `count' is greater than 128, the result will be either 0 +or 1, depending on whether the concatenation of `a0' and `a1' is zero or +nonzero. The result is broken into two 64-bit pieces which are stored at +the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128RightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<>count ) | ( ( a1<>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 128 ) { + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<>count ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 128 ) { + z2 = a0<>( count & 63 ); + } + else { + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' must be less than 64. The result is broken into two 64-bit +pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift128Left( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1<>( ( - count ) & 63 ) ); + +} + +/* +------------------------------------------------------------------------------- +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left +by the number of bits given in `count'. Any bits shifted off are lost. +The value of `count' must be less than 64. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift192Left( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount; + + z2 = a2<>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit +value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so +any carry out is lost. The result is broken into two 64-bit pieces which +are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +/* +------------------------------------------------------------------------------- +Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +modulo 2^192, so any carry out is lost. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +2^128, so any borrow out (carry out) is lost. The result is broken into two +64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +`z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' +from the 192-bit value formed by concatenating `a0', `a1', and `a2'. +Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The +result is broken into three 64-bit pieces which are stored at the locations +pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies `a' by `b' to obtain a 128-bit product. The product is broken +into two 64-bit pieces which are stored at the locations pointed to by +`z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits32 aHigh, aLow, bHigh, bLow; + bits64 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>32; + bLow = b; + bHigh = b>>32; + z1 = ( (bits64) aLow ) * bLow; + zMiddleA = ( (bits64) aLow ) * bHigh; + zMiddleB = ( (bits64) aHigh ) * bLow; + z0 = ( (bits64) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + zMiddleA <<= 32; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to +obtain a 192-bit product. The product is broken into three 64-bit pieces +which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +`z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128By64To192( + bits64 a0, + bits64 a1, + bits64 b, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2, more1; + + mul64To128( a1, b, &z1, &z2 ); + mul64To128( a0, b, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the +128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit +product. The product is broken into four 64-bit pieces which are stored at +the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128To256( + bits64 a0, + bits64 a1, + bits64 b0, + bits64 b1, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr, + bits64 *z3Ptr + ) +{ + bits64 z0, z1, z2, z3; + bits64 more1, more2; + + mul64To128( a1, b1, &z2, &z3 ); + mul64To128( a1, b0, &z1, &more2 ); + add128( z1, more2, 0, z2, &z1, &z2 ); + mul64To128( a0, b0, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + mul64To128( a0, b1, &more1, &more2 ); + add128( more1, more2, 0, z2, &more1, &z2 ); + add128( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the 64-bit integer quotient obtained by dividing +`b' into the 128-bit value formed by concatenating `a0' and `a1'. The +divisor `b' must be at least 2^63. If q is the exact quotient truncated +toward zero, the approximation returned lies between q and q + 2 inclusive. +If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +unsigned integer is returned. +------------------------------------------------------------------------------- +*/ +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +{ + bits64 b0, b1; + bits64 rem0, rem1, term0, term1; + bits64 z; + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); + b0 = b>>32; + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; + mul64To128( b, z, &term0, &term1 ); + sub128( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits64) rem0 ) < 0 ) { + z -= LIT64( 0x100000000 ); + b1 = b<<32; + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<32 ) | ( rem1>>32 ); + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the square root of the 32-bit significand given +by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +`aExp' (the least significant bit) is 1, the integer returned approximates +2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +case, the approximation returned lies strictly within +/-2 of the exact +value. +------------------------------------------------------------------------------- +*/ +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 32 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 64 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros64( bits64 a ) +{ + int8 shiftCount; + + shiftCount = 0; + if ( a < ( (bits64) 1 )<<32 ) { + shiftCount += 32; + } + else { + a >>= 32; + } + shiftCount += countLeadingZeros32( a ); + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' +is equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than or equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, +returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is +not equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/softfloat-specialize linux/arch/arm/nwfpe/softfloat-specialize --- v2.2.17/arch/arm/nwfpe/softfloat-specialize Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/softfloat-specialize Fri Sep 15 23:28:37 2000 @@ -0,0 +1,471 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Underflow tininess-detection mode, statically initialized to default value. +(The declaration in `softfloat.h' must match the `int8' type here.) +------------------------------------------------------------------------------- +*/ +int8 float_detect_tininess = float_tininess_after_rounding; + +/* +------------------------------------------------------------------------------- +Raises the exceptions specified by `flags'. Floating-point traps can be +defined here if desired. It is currently not possible for such a trap to +substitute a result value. If traps are not implemented, this routine +should be simply `float_exception_flags |= flags;'. + +ScottB: November 4, 1998 +Moved this function out of softfloat-specialize into fpmodule.c. +This effectively isolates all the changes required for integrating with the +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying +fpmodule.c to integrate with the NetBSD kernel (I hope!). +------------------------------------------------------------------------------- +void float_raise( int8 flags ) +{ + float_exception_flags |= flags; +} +*/ + +/* +------------------------------------------------------------------------------- +Internal canonical NaN format. +------------------------------------------------------------------------------- +*/ +typedef struct { + flag sign; + bits64 high, low; +} commonNaNT; + +/* +------------------------------------------------------------------------------- +The pattern for a default generated single-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float32_default_nan 0xFFFFFFFF + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_nan( float32 a ) +{ + + return ( 0xFF000000 < (bits32) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_signaling_nan( float32 a ) +{ + + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float32ToCommonNaN( float32 a ) +{ + commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>31; + z.low = 0; + z.high = ( (bits64) a )<<41; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the single- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float32 commonNaNToFloat32( commonNaNT a ) +{ + + return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two single-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float32 propagateFloat32NaN( float32 a, float32 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + a |= 0x00400000; + b |= 0x00400000; + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +/* +------------------------------------------------------------------------------- +The pattern for a default generated double-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_nan( float64 a ) +{ + + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_signaling_nan( float64 a ) +{ + + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float64ToCommonNaN( float64 a ) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>63; + z.low = 0; + z.high = a<<12; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the double- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float64 commonNaNToFloat64( commonNaNT a ) +{ + + return + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF8000000000000 ) + | ( a.high>>12 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two double-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float64 propagateFloat64NaN( float64 a, float64 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + a |= LIT64( 0x0008000000000000 ); + b |= LIT64( 0x0008000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +The pattern for a default generated extended double-precision NaN. The +`high' and `low' values hold the most- and least-significant bits, +respectively. +------------------------------------------------------------------------------- +*/ +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_nan( floatx80 a ) +{ + + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +signaling NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_signaling_nan( floatx80 a ) +{ + //register int lr; + bits64 aLow; + + //__asm__("mov %0, lr" : : "g" (lr)); + //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr); + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the +invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT floatx80ToCommonNaN( floatx80 a ) +{ + commonNaNT z; + + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a.high>>15; + z.low = 0; + z.high = a.low<<1; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the extended +double-precision floating-point format. +------------------------------------------------------------------------------- +*/ +static floatx80 commonNaNToFloatx80( commonNaNT a ) +{ + floatx80 z; + + z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + return z; + +} + +/* +------------------------------------------------------------------------------- +Takes two extended double-precision floating-point values `a' and `b', one +of which is a NaN, and returns the appropriate NaN result. If either `a' or +`b' is a signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = floatx80_is_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsNaN = floatx80_is_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); + a.low |= LIT64( 0xC000000000000000 ); + b.low |= LIT64( 0xC000000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +The pattern for a default generated quadruple-precision NaN. The `high' and +`low' values hold the most- and least-significant bits, respectively. +------------------------------------------------------------------------------- +*/ +#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF ) +#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float128_is_nan( float128 a ) +{ + + return + ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is a +signaling NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float128_is_signaling_nan( float128 a ) +{ + + return + ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE ) + && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the quadruple-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float128ToCommonNaN( float128 a ) +{ + commonNaNT z; + + if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a.high>>63; + shortShift128Left( a.high, a.low, 16, &z.high, &z.low ); + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the quadruple- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float128 commonNaNToFloat128( commonNaNT a ) +{ + float128 z; + + shift128Right( a.high, a.low, 16, &z.high, &z.low ); + z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 ); + return z; + +} + +/* +------------------------------------------------------------------------------- +Takes two quadruple-precision floating-point values `a' and `b', one of +which is a NaN, and returns the appropriate NaN result. If either `a' or +`b' is a signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float128 propagateFloat128NaN( float128 a, float128 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float128_is_nan( a ); + aIsSignalingNaN = float128_is_signaling_nan( a ); + bIsNaN = float128_is_nan( b ); + bIsSignalingNaN = float128_is_signaling_nan( b ); + a.high |= LIT64( 0x0000800000000000 ); + b.high |= LIT64( 0x0000800000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/softfloat.c linux/arch/arm/nwfpe/softfloat.c --- v2.2.17/arch/arm/nwfpe/softfloat.c Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/softfloat.c Fri Sep 15 23:28:38 2000 @@ -0,0 +1,4877 @@ +/* +=============================================================================== + +This C source file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#include "milieu.h" +#include "softfloat.h" + +/* +------------------------------------------------------------------------------- +Floating-point rounding mode, extended double-precision rounding precision, +and exception flags. +------------------------------------------------------------------------------- +*/ +int8 float_rounding_mode = float_round_nearest_even; +int8 floatx80_rounding_precision = 80; +int8 float_exception_flags = 0; + +/* +------------------------------------------------------------------------------- +Primitive arithmetic functions, including multi-word arithmetic, and +division and square root approximations. (Can be specialized to target if +desired.) +------------------------------------------------------------------------------- +*/ +#include "softfloat-macros" + +/* +------------------------------------------------------------------------------- +Functions and definitions to determine: (1) whether tininess for underflow +is detected before or after rounding by default, (2) what (if anything) +happens when exceptions are raised, (3) how signaling NaNs are distinguished +from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs +are propagated from function inputs to output. These details are target- +specific. +------------------------------------------------------------------------------- +*/ +#include "softfloat-specialize" + +/* +------------------------------------------------------------------------------- +Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 +and 7, and returns the properly rounded 32-bit integer corresponding to the +input. If `zSign' is nonzero, the input is negated before being converted +to an integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point +input is simply rounded to an integer, with the inexact exception raised if +the input cannot be represented exactly as an integer. If the fixed-point +input is too large, however, the invalid exception is raised and the largest +positive or negative integer is returned. +------------------------------------------------------------------------------- +*/ +static int32 roundAndPackInt32( flag zSign, bits64 absZ ) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + int32 z; + + roundingMode = float_rounding_mode; + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = absZ & 0x7F; + absZ = ( absZ + roundIncrement )>>7; + absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + z = absZ; + if ( zSign ) z = - z; + if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { + float_exception_flags |= float_flag_invalid; + return zSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( roundBits ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the fraction bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return a & 0x007FFFFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the exponent bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( a>>23 ) & 0xFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat32Sign( float32 a ) +{ + + return a>>31; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal single-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper single-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat32' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<>52 ) & 0x7FF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the double-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat64Sign( float64 a ) +{ + + return a>>63; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal double-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ) - 11; + *zSigPtr = aSig<>10; + zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper double-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat64' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float64 + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( zSig ) - 1; + return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<>15; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal extended double-precision floating-point value +represented by the denormalized significand `aSig'. The normalized exponent +and significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ); + *zSigPtr = aSig<>48 ) & 0x7FFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the quadruple-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat128Sign( float128 a ) +{ + + return a.high>>63; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal quadruple-precision floating-point value +represented by the denormalized significand formed by the concatenation of +`aSig0' and `aSig1'. The normalized exponent is stored at the location +pointed to by `zExpPtr'. The most significant 49 bits of the normalized +significand are stored at the location pointed to by `zSig0Ptr', and the +least significant 64 bits of the normalized significand are stored at the +location pointed to by `zSig1Ptr'. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat128Subnormal( + bits64 aSig0, + bits64 aSig1, + int32 *zExpPtr, + bits64 *zSig0Ptr, + bits64 *zSig1Ptr + ) +{ + int8 shiftCount; + + if ( aSig0 == 0 ) { + shiftCount = countLeadingZeros64( aSig1 ) - 15; + if ( shiftCount < 0 ) { + *zSig0Ptr = aSig1>>( - shiftCount ); + *zSig1Ptr = aSig1<<( shiftCount & 63 ); + } + else { + *zSig0Ptr = aSig1<>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + float_exception_flags |= float_flag_inexact; + } + return aSign ? - z : z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the double-precision floating-point format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float32_to_float64( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) ); + return packFloat64( aSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the extended double-precision floating-point format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 float32_to_floatx80( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + aSig |= 0x00800000; + return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + +} + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the double-precision floating-point format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float32_to_float128( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) ); + return packFloat128( aSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 ); + +} + +#endif + +/* +------------------------------------------------------------------------------- +Rounds the single-precision floating-point value `a' to an integer, and +returns the result as a single-precision floating-point value. The +operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + float32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( a<<1 ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return aSign ? 0xBF800000 : 0; + case float_round_up: + return aSign ? 0x80000000 : 0x3F800000; + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the single-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the single- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the single-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_add( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign ); + } + else { + return subFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sub( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign ); + } + else { + return addFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_mul( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig; + bits64 zSig64; + bits32 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + zSig = zSig64; + if ( 0 <= (sbits32) ( zSig<<1 ) ) { + zSig <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the single-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_div( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = ( ( (bits64) aSig )<<32 ) / bSig; + if ( ( zSig & 0x3F ) == 0 ) { + zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 ); + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the single-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_rem( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig; + bits32 q; + bits64 aSig64, bSig64, q64; + bits32 alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig |= 0x00800000; + bSig |= 0x00800000; + if ( expDiff < 32 ) { + aSig <<= 8; + bSig <<= 8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + if ( 0 < expDiff ) { + q = ( ( (bits64) aSig )<<32 ) / bSig; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + } + else { + if ( bSig <= aSig ) aSig -= bSig; + aSig64 = ( (bits64) aSig )<<40; + bSig64 = ( (bits64) bSig )<<40; + expDiff -= 64; + while ( 0 < expDiff ) { + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + aSig64 = - ( ( bSig * q64 )<<38 ); + expDiff -= 62; + } + expDiff += 64; + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + q = q64>>( 64 - expDiff ); + bSig <<= 6; + aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the single-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sqrt( float32 a ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig; + bits64 rem, term; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, 0 ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0xFFFFFFFF; + } + else { + aSig >>= aExp & 1; + term = ( (bits64) zSig ) * zSig; + rem = ( ( (bits64) aSig )<<32 ) - term; + while ( (sbits64) rem < 0 ) { + --zSig; + rem += ( ( (bits64) zSig )<<1 ) | 1; + } + zSig |= ( rem != 0 ); + } + } + shift32RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat32( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq_signaling( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest integer with the same sign as `a' is +returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32_round_to_zero( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + shiftCount = 0x433 - aExp; + if ( shiftCount < 21 ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( 52 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the double-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 9; + bSig <<= 9; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= LIT64( 0x2000000000000000 ); + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits64) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the double- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 10; + bSig <<= 10; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat64( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign ^ 1, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + bSig |= LIT64( 0x4000000000000000 ); + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + aSig |= LIT64( 0x4000000000000000 ); + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the double-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_add( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign ); + } + else { + return subFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sub( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign ); + } + else { + return addFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_mul( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FF; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the double-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to +the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_div( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + bits64 rem0, rem1; + bits64 term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat64( zSign, 0x7FF, 0 ); + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FD; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv128To64( aSig, 0, bSig ); + if ( ( zSig & 0x1FF ) <= 2 ) { + mul64To128( bSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the double-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_rem( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits64 aSig, bSig; + bits64 q, alternateASig; + sbits64 sigMean; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits64) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits64) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the double-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sqrt( float64 a ) +{ + flag aSign; + int16 aExp, zExp; + bits64 aSig, zSig; + bits64 rem0, rem1, term0, term1; //, shiftedRem; + //float64 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, a ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig |= LIT64( 0x0010000000000000 ); + zSig = estimateSqrt32( aExp, aSig>>21 ); + zSig <<= 31; + aSig <<= 9 - ( aExp & 1 ); + zSig = estimateDiv128To64( aSig, 0, zSig ) + zSig + 2; + if ( ( zSig & 0x3FF ) <= 5 ) { + if ( zSig < 2 ) { + zSig = LIT64( 0xFFFFFFFFFFFFFFFF ); + } + else { + aSig <<= 2; + mul64To128( zSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + shortShift128Left( 0, zSig, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + } + shift64RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat64( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq_signaling( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic---which means in particular that the conversion +is rounded according to the current rounding mode. If `a' is a NaN, the +largest positive integer is returned. Otherwise, if the conversion +overflows, the largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + shiftCount = 0x4037 - aExp; + if ( shiftCount <= 0 ) shiftCount = 1; + shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic, except that the conversion is always rounded +toward zero. If `a' is a NaN, the largest positive integer is returned. +Otherwise, if the conversion overflows, the largest integer with the same +sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32_round_to_zero( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + shiftCount = 0x403E - aExp; + if ( shiftCount < 32 ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + goto invalid; + } + else if ( 63 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<>1; + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z.low += roundBitsMask; + } + } + z.low &= ~ roundBitsMask; + if ( z.low == 0 ) { + ++z.high; + z.low = LIT64( 0x8000000000000000 ); + } + if ( z.low != a.low ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the extended double- +precision floating-point values `a' and `b'. If `zSign' is true, the sum is +negated before being returned. `zSign' is ignored if the result is a NaN. +The addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + return a; + } + zSig1 = 0; + zSig0 = aSig + bSig; + if ( aExp == 0 ) { + normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); + goto roundAndPack; + } + zExp = aExp; + goto shiftRight1; + } + + zSig0 = aSig + bSig; + + if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= LIT64( 0x8000000000000000 ); + ++zExp; + roundAndPack: + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the extended +double-precision floating-point values `a' and `b'. If `zSign' is true, +the difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + zSig1 = 0; + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloatx80( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + bBigger: + sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + aBigger: + sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + return + normalizeRoundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the extended double-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_add( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return addFloatx80Sigs( a, b, aSign ); + } + else { + return subFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sub( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return subFloatx80Sigs( a, b, aSign ); + } + else { + return addFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_mul( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) goto invalid; + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FFE; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + if ( 0 < (sbits64) zSig0 ) { + shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); + --zExp; + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the extended double-precision floating-point +value `a' by the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_div( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + bits64 rem0, rem1, rem2, term0, term1, term2; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + goto invalid; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FFE; + rem1 = 0; + if ( bSig <= aSig ) { + shift128Right( aSig, 0, 1, &aSig, &rem1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig, rem1, bSig ); + mul64To128( bSig, zSig0, &term0, &term1 ); + sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, bSig ); + if ( (bits64) ( zSig1<<1 ) <= 8 ) { + mul64To128( bSig, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); + } + zSig1 |= ( ( rem1 | rem2 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the extended double-precision floating-point value +`a' with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_rem( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig; + bits64 q, term0, term1, alternateASig0, alternateASig1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + bSig |= LIT64( 0x8000000000000000 ); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); + expDiff = 0; + } + q = ( bSig <= aSig0 ); + if ( q ) aSig0 -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + mul64To128( bSig, q, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); + while ( le128( term0, term1, aSig0, aSig1 ) ) { + ++q; + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + } + } + else { + term1 = 0; + term0 = bSig; + } + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the extended double-precision floating-point +value `a'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sqrt( floatx80 a ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + bits64 shiftedRem0, shiftedRem1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; + zSig0 = estimateSqrt32( aExp, aSig0>>32 ); + zSig0 <<= 31; + aSig1 = 0; + shift128Right( aSig0, 0, ( aExp & 1 ) + 2, &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; + if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); + shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + shortShift128Left( 0, zSig0, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); + zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); + if ( (bits64) ( zSig1<<1 ) <= 10 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( zSig0, zSig1, &term1, &term2 ); + shortShift128Left( term1, term2, 1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); + term3 |= 1; + add192( + rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, 0, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than or equal to the corresponding value `b', and 0 otherwise. The +comparison is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than the corresponding value `b', and 0 otherwise. The comparison +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is equal +to the corresponding value `b', and 0 otherwise. The invalid exception is +raised if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq_signaling( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs +do not cause an exception. Otherwise, the comparison is performed according +to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause +an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the quadruple-precision floating-point +value `a' to the 32-bit two's complement integer format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 float128_to_int32( float128 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0; + if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 ); + aSig0 |= ( aSig1 != 0 ); + shiftCount = 0x4028 - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); + return roundAndPackInt32( aSign, aSig0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the quadruple-precision floating-point +value `a' to the 32-bit two's complement integer format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest integer with the same sign as `a' is +returned. +------------------------------------------------------------------------------- +*/ +int32 float128_to_int32_round_to_zero( float128 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig0, aSig1, savedASig; + int32 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + aSig0 |= ( aSig1 != 0 ); + shiftCount = 0x402F - aExp; + if ( shiftCount < 17 ) { + if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0; + goto invalid; + } + else if ( 48 < shiftCount ) { + if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig0 |= LIT64( 0x0001000000000000 ); + savedASig = aSig0; + aSig0 >>= shiftCount; + z = aSig0; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig0<>1, &z.high, &z.low ); + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else { + if ( (sbits64) z.low < 0 ) { + ++z.high; + if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; + } + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low ); + } + } + z.low &= ~ roundBitsMask; + } + else { + if ( aExp <= 0x3FFE ) { + if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat128Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) + && ( extractFloat128Frac0( a ) + | extractFloat128Frac1( a ) ) + ) { + return packFloat128( aSign, 0x3FFF, 0, 0 ); + } + break; + case float_round_down: + return + aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) + : packFloat128( 0, 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloat128( 1, 0, 0, 0 ) + : packFloat128( 0, 0x3FFF, 0, 0 ); + } + return packFloat128( aSign, 0, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x402F - aExp; + roundBitsMask = lastBitMask - 1; + z.low = 0; + z.high = a.high; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z.high += lastBitMask>>1; + if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { + z.high &= ~ lastBitMask; + } + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat128Sign( z ) + ^ ( roundingMode == float_round_up ) ) { + z.high |= ( a.low != 0 ); + z.high += roundBitsMask; + } + } + z.high &= ~ roundBitsMask; + } + if ( ( z.low != a.low ) || ( z.high != a.high ) ) { + float_exception_flags |= float_flag_inexact; + } + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the quadruple-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float128 addFloat128Sigs( float128 a, float128 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + int32 expDiff; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x0001000000000000 ); + } + shift128ExtraRightJamming( + aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b ); + } + return a; + } + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); + zSig2 = 0; + zSig0 |= LIT64( 0x0002000000000000 ); + zExp = aExp; + goto shiftRight1; + } + aSig0 |= LIT64( 0x0001000000000000 ); + add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + --zExp; + if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack; + ++zExp; + shiftRight1: + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + roundAndPack: + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the quadruple- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float128 subFloat128Sigs( float128 a, float128 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; + int32 expDiff; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + expDiff = aExp - bExp; + shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); + shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 | bSig0 | bSig1 ) { + return propagateFloat128NaN( a, b ); + } + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig0 < aSig0 ) goto aBigger; + if ( aSig0 < bSig0 ) goto bBigger; + if ( bSig1 < aSig1 ) goto aBigger; + if ( aSig1 < bSig1 ) goto bBigger; + return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + bSig0 |= LIT64( 0x4000000000000000 ); + bBigger: + sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig0 |= LIT64( 0x4000000000000000 ); + } + shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); + aSig0 |= LIT64( 0x4000000000000000 ); + aBigger: + sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the quadruple-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_add( float128 a, float128 b ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return addFloat128Sigs( a, b, aSign ); + } + else { + return subFloat128Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the quadruple-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_sub( float128 a, float128 b ) +{ + flag aSign, bSign; + + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign == bSign ) { + return subFloat128Sigs( a, b, aSign ); + } + else { + return addFloat128Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the quadruple-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_mul( float128 a, float128 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b ); + } + if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + zExp = aExp + bExp - 0x4000; + aSig0 |= LIT64( 0x0001000000000000 ); + shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); + mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); + add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); + zSig2 |= ( zSig3 != 0 ); + if ( LIT64( 0x0002000000000000 ) <= zSig0 ) { + shift128ExtraRightJamming( + zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); + ++zExp; + } + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the quadruple-precision floating-point value +`a' by the corresponding value `b'. The operation is performed according to +the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_div( float128 a, float128 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b ); + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + goto invalid; + } + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return packFloat128( zSign, 0, 0, 0 ); + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero ); + return packFloat128( zSign, 0x7FFF, 0, 0 ); + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = aExp - bExp + 0x3FFD; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { + shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); + mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); + sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); + } + zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); + if ( ( zSig1 & 0x3FFF ) <= 4 ) { + mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); + sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the quadruple-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_rem( float128 a, float128 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig0, bSig1; + bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1; + bits64 sigMean1; + sbits64 sigMean0; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + bSig1 = extractFloat128Frac1( b ); + bSig0 = extractFloat128Frac0( b ); + bExp = extractFloat128Exp( b ); + bSign = extractFloat128Sign( b ); + if ( aExp == 0x7FFF ) { + if ( ( aSig0 | aSig1 ) + || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { + return propagateFloat128NaN( a, b ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( ( bSig0 | bSig1 ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return a; + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + expDiff = aExp - bExp; + if ( expDiff < -1 ) return a; + shortShift128Left( + aSig0 | LIT64( 0x0001000000000000 ), + aSig1, + 15 - ( expDiff < 0 ), + &aSig0, + &aSig1 + ); + shortShift128Left( + bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 ); + q = le128( bSig0, bSig1, aSig0, aSig1 ); + if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero ); + shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero ); + sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 ); + expDiff -= 61; + } + if ( -64 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig0 ); + q = ( 4 < q ) ? q - 4 : 0; + q >>= - expDiff; + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + expDiff += 52; + if ( expDiff < 0 ) { + shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); + } + else { + shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 ); + } + mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 ); + sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 ); + } + else { + shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 ); + shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 ); + } + do { + alternateASig0 = aSig0; + alternateASig1 = aSig1; + ++q; + sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); + } while ( 0 <= (sbits64) aSig0 ); + add128( + aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); + if ( ( sigMean0 < 0 ) + || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + } + zSign = ( (sbits64) aSig0 < 0 ); + if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); + return + normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the quadruple-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float128 float128_sqrt( float128 a ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1, zSig2; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + bits64 shiftedRem0, shiftedRem1; + float128 z; + + aSig1 = extractFloat128Frac1( a ); + aSig0 = extractFloat128Frac0( a ); + aExp = extractFloat128Exp( a ); + aSign = extractFloat128Sign( a ); + if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid ); + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 ); + normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE; + aSig0 |= LIT64( 0x0001000000000000 ); + zSig0 = estimateSqrt32( aExp, aSig0>>17 ); + zSig0 <<= 31; + shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; + if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); + shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + shortShift128Left( 0, zSig0, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); + zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); + if ( ( zSig1 & 0x3FFF ) <= 5 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( zSig0, zSig1, &term1, &term2 ); + shortShift128Left( term1, term2, 1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); + term3 |= 1; + add192( + rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); + return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is equal to +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_eq( float128 a, float128 b ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +or equal to the corresponding value `b', and 0 otherwise. The comparison +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_le( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_lt( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is equal to +the corresponding value `b', and 0 otherwise. The invalid exception is +raised if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_eq_signaling( float128 a, float128 b ) +{ + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_le_quiet( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the quadruple-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float128_lt_quiet( float128 a, float128 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/nwfpe/softfloat.h linux/arch/arm/nwfpe/softfloat.h --- v2.2.17/arch/arm/nwfpe/softfloat.h Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/nwfpe/softfloat.h Fri Sep 15 23:28:38 2000 @@ -0,0 +1,290 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#ifndef __SOFTFLOAT_H__ +#define __SOFTFLOAT_H__ + +/* +------------------------------------------------------------------------------- +The macro `FLOATX80' must be defined to enable the extended double-precision +floating-point format `floatx80'. If this macro is not defined, the +`floatx80' type will not be defined, and none of the functions that either +input or output the `floatx80' type will be defined. The same applies to +the `FLOAT128' macro and the quadruple-precision format `float128'. +------------------------------------------------------------------------------- +*/ +#define FLOATX80 +/* #define FLOAT128 */ + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point types. +------------------------------------------------------------------------------- +*/ +typedef unsigned long int float32; +typedef unsigned long long float64; +#ifdef FLOATX80 +typedef struct { + unsigned short high; + unsigned long long low; +} floatx80; +#endif +#ifdef FLOAT128 +typedef struct { + unsigned long long high, low; +} float128; +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point underflow tininess-detection mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_detect_tininess; +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point rounding mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_rounding_mode; +enum { + float_round_nearest_even = 0, + float_round_to_zero = 1, + float_round_down = 2, + float_round_up = 3 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point exception flags. +------------------------------------------------------------------------------- +extern signed char float_exception_flags; +enum { + float_flag_inexact = 1, + float_flag_underflow = 2, + float_flag_overflow = 4, + float_flag_divbyzero = 8, + float_flag_invalid = 16 +}; + +ScottB: November 4, 1998 +Changed the enumeration to match the bit order in the FPA11. +*/ + +extern signed char float_exception_flags; +enum { + float_flag_invalid = 1, + float_flag_divbyzero = 2, + float_flag_overflow = 4, + float_flag_underflow = 8, + float_flag_inexact = 16 +}; + +/* +------------------------------------------------------------------------------- +Routine to raise any or all of the software IEC/IEEE floating-point +exception flags. +------------------------------------------------------------------------------- +*/ +void float_raise( signed char ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE integer-to-floating-point conversion routines. +------------------------------------------------------------------------------- +*/ +float32 int32_to_float32( signed int ); +float64 int32_to_float64( signed int ); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( signed int ); +#endif +#ifdef FLOAT128 +float128 int32_to_float128( signed int ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float32_to_int32( float32 ); +signed int float32_to_int32_round_to_zero( float32 ); +float64 float32_to_float64( float32 ); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 ); +#endif +#ifdef FLOAT128 +float128 float32_to_float128( float32 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision operations. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 ); +float32 float32_add( float32, float32 ); +float32 float32_sub( float32, float32 ); +float32 float32_mul( float32, float32 ); +float32 float32_div( float32, float32 ); +float32 float32_rem( float32, float32 ); +float32 float32_sqrt( float32 ); +char float32_eq( float32, float32 ); +char float32_le( float32, float32 ); +char float32_lt( float32, float32 ); +char float32_eq_signaling( float32, float32 ); +char float32_le_quiet( float32, float32 ); +char float32_lt_quiet( float32, float32 ); +char float32_is_signaling_nan( float32 ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float64_to_int32( float64 ); +signed int float64_to_int32_round_to_zero( float64 ); +float32 float64_to_float32( float64 ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 ); +#endif +#ifdef FLOAT128 +float128 float64_to_float128( float64 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision operations. +------------------------------------------------------------------------------- +*/ +float64 float64_round_to_int( float64 ); +float64 float64_add( float64, float64 ); +float64 float64_sub( float64, float64 ); +float64 float64_mul( float64, float64 ); +float64 float64_div( float64, float64 ); +float64 float64_rem( float64, float64 ); +float64 float64_sqrt( float64 ); +char float64_eq( float64, float64 ); +char float64_le( float64, float64 ); +char float64_lt( float64, float64 ); +char float64_eq_signaling( float64, float64 ); +char float64_le_quiet( float64, float64 ); +char float64_lt_quiet( float64, float64 ); +char float64_is_signaling_nan( float64 ); + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int floatx80_to_int32( floatx80 ); +signed int floatx80_to_int32_round_to_zero( floatx80 ); +float32 floatx80_to_float32( floatx80 ); +float64 floatx80_to_float64( floatx80 ); +#ifdef FLOAT128 +float128 floatx80_to_float128( floatx80 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision rounding precision. Valid +values are 32, 64, and 80. +------------------------------------------------------------------------------- +*/ +extern signed char floatx80_rounding_precision; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision operations. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_round_to_int( floatx80 ); +floatx80 floatx80_add( floatx80, floatx80 ); +floatx80 floatx80_sub( floatx80, floatx80 ); +floatx80 floatx80_mul( floatx80, floatx80 ); +floatx80 floatx80_div( floatx80, floatx80 ); +floatx80 floatx80_rem( floatx80, floatx80 ); +floatx80 floatx80_sqrt( floatx80 ); +char floatx80_eq( floatx80, floatx80 ); +char floatx80_le( floatx80, floatx80 ); +char floatx80_lt( floatx80, floatx80 ); +char floatx80_eq_signaling( floatx80, floatx80 ); +char floatx80_le_quiet( floatx80, floatx80 ); +char floatx80_lt_quiet( floatx80, floatx80 ); +char floatx80_is_signaling_nan( floatx80 ); + +#endif + +#ifdef FLOAT128 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE quadruple-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float128_to_int32( float128 ); +signed int float128_to_int32_round_to_zero( float128 ); +float32 float128_to_float32( float128 ); +float64 float128_to_float64( float128 ); +#ifdef FLOATX80 +floatx80 float128_to_floatx80( float128 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE quadruple-precision operations. +------------------------------------------------------------------------------- +*/ +float128 float128_round_to_int( float128 ); +float128 float128_add( float128, float128 ); +float128 float128_sub( float128, float128 ); +float128 float128_mul( float128, float128 ); +float128 float128_div( float128, float128 ); +float128 float128_rem( float128, float128 ); +float128 float128_sqrt( float128 ); +char float128_eq( float128, float128 ); +char float128_le( float128, float128 ); +char float128_lt( float128, float128 ); +char float128_eq_signaling( float128, float128 ); +char float128_le_quiet( float128, float128 ); +char float128_lt_quiet( float128, float128 ); +char float128_is_signaling_nan( float128 ); + +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/vmlinux-armo.lds linux/arch/arm/vmlinux-armo.lds --- v2.2.17/arch/arm/vmlinux-armo.lds Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/vmlinux-armo.lds Tue Sep 5 22:20:06 2000 @@ -41,8 +41,16 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(32768); __init_end = .; + __bss_start = .; /* BSS */ .bss : { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in --- v2.2.17/arch/arm/vmlinux-armo.lds.in Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/vmlinux-armo.lds.in Mon Oct 2 10:10:59 2000 @@ -0,0 +1,92 @@ +/* ld script to make ARM Linux kernel + * taken from the i386 version by Russell King + * Written by Martin Mares + */ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = TEXTADDR; + + .init : { + __init_begin = .; /* Init code and data */ + *(.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(32768); + __init_end = .; + } + + .init.task : { + *(.init.task) + } + + /DISCARD/ : { /* Exit code and data */ + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + .text : { + _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 */ + + _etext = .; /* End of text section */ + } + + .data : { /* Data */ + /* + * The cacheline aligned data + */ + . = ALIGN(32); + *(.data.cacheline_aligned) + + /* + * and the usual data section + */ + *(.data) + CONSTRUCTORS + + _edata = .; + } + + .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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/vmlinux-armv.lds linux/arch/arm/vmlinux-armv.lds --- v2.2.17/arch/arm/vmlinux-armv.lds Fri Apr 21 12:45:45 2000 +++ linux/arch/arm/vmlinux-armv.lds Tue Sep 5 22:20:06 2000 @@ -41,8 +41,17 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; + __bss_start = .; /* BSS */ .bss : { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in --- v2.2.17/arch/arm/vmlinux-armv.lds.in Thu Jan 1 01:00:00 1970 +++ linux/arch/arm/vmlinux-armv.lds.in Mon Oct 2 10:10:59 2000 @@ -0,0 +1,106 @@ +/* ld script to make ARM Linux kernel + * taken from the i386 version by Russell King + * Written by Martin Mares + */ +OUTPUT_ARCH(arm) +ENTRY(stext) +SECTIONS +{ + . = 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 = .; + } + + /DISCARD/ : { /* Exit code and data */ + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + __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 : { /* 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 */ + + _etext = .; /* End of text section */ + } + + . = ALIGN(8192); + + .data : { + /* + * first, the init task union, aligned + * to an 8192 byte boundary. + */ + *(.init.task) + + /* + * then the cacheline aligned data + */ + . = ALIGN(32); + *(.data.cacheline_aligned) + + /* + * and the usual data section + */ + *(.data) + CONSTRUCTORS + + _edata = .; + } + + .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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.2.17/arch/i386/boot/setup.S Fri Apr 21 12:45:45 2000 +++ linux/arch/i386/boot/setup.S Fri Sep 15 23:35:27 2000 @@ -30,6 +30,10 @@ ! Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david ! parsons) to avoid loadlin confusion, July 1997 ! +! +! A20 gating fiddled to work on AMD Elan AmSC4xx series by kira@linuxgrrls.org +! july 1999 +! #define __ASSEMBLY__ #include @@ -548,6 +552,14 @@ lgdt gdt_48 ! load gdt with whatever appropriate ! that was painless, now we enable A20 + +! if this is SC410 or a few other bits we need to do it with the 'fast' method + + in al,#0x92 ! read "System Control Port A" + or al,#0x02 ! Set "Alternate Gate A20" - Bit + out #0x92,al ! write "System Control Port A" + +! do it the normal way too, so as not to upset normal machines call empty_8042 mov al,#0xD1 ! command write diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/config.in linux/arch/i386/config.in --- v2.2.17/arch/i386/config.in Sat Sep 9 18:42:32 2000 +++ linux/arch/i386/config.in Mon Sep 11 18:14:04 2000 @@ -33,6 +33,10 @@ define_bool CONFIG_X86_GOOD_APIC y fi +tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE +tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR +tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID + choice 'Maximum Physical Memory' \ "1GB CONFIG_1GB \ 2GB CONFIG_2GB" 1GB @@ -109,7 +113,6 @@ bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK - 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 ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF @@ -176,7 +179,7 @@ source drivers/char/Config.in -# source drivers/usb/Config.in +source drivers/usb/Config.in source fs/Config.in diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/defconfig linux/arch/i386/defconfig --- v2.2.17/arch/i386/defconfig Fri Apr 21 12:45:45 2000 +++ linux/arch/i386/defconfig Sun Sep 3 14:00:02 2000 @@ -166,6 +166,7 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.2.17/arch/i386/kernel/Makefile Sat Sep 9 18:42:32 2000 +++ linux/arch/i386/kernel/Makefile Tue Nov 21 15:37:05 2000 @@ -15,7 +15,7 @@ O_TARGET := kernel.o O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \ - bluesmoke.o + bluesmoke.o dmi_scan.o OX_OBJS := i386_ksyms.o MX_OBJS := @@ -32,6 +32,30 @@ else ifeq ($(CONFIG_MTRR),m) MX_OBJS += mtrr.o + endif +endif + +ifeq ($(CONFIG_MICROCODE),y) +OX_OBJS += microcode.o +else + ifeq ($(CONFIG_MICROCODE),m) + MX_OBJS += microcode.o + endif +endif + +ifeq ($(CONFIG_X86_MSR),y) +OX_OBJS += msr.o +else + ifeq ($(CONFIG_X86_MSR),m) + MX_OBJS += msr.o + endif +endif + +ifeq ($(CONFIG_X86_CPUID),y) +OX_OBJS += cpuid.o +else + ifeq ($(CONFIG_X86_CPUID),m) + MX_OBJS += cpuid.o endif endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.2.17/arch/i386/kernel/apm.c Sun Jun 11 21:44:09 2000 +++ linux/arch/i386/kernel/apm.c Tue Nov 21 15:45:29 2000 @@ -129,6 +129,7 @@ * 1.13: Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS * is now the way life works). * Fix thinko in suspend() (wrong return). + * 1.13ac: Added apm_battery_horked() for Compal boards (Dell 5000e etc) * * APM 1.1 Reference: * @@ -170,18 +171,6 @@ #include #include -/* 2.2-2.3 Compatability defines */ -#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL} -#define __setup(x, y) -#define module_init(x) -#define set_current_state(a) current->state = (a) -#define create_proc_info_entry(n, m, b, g) \ - { \ - struct proc_dir_entry *r = create_proc_entry(n, m, b); \ - if (r) r->get_info = g; \ - } - EXPORT_SYMBOL(apm_register_callback); EXPORT_SYMBOL(apm_unregister_callback); @@ -337,6 +326,7 @@ #else static int power_off_enabled = 1; #endif +static int dell_crap = 0; /*Set if we find a 5000e */ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); @@ -1254,6 +1244,18 @@ return 0; } +/* + * This is called by the DMI code when it finds an Inspiron 5000e + * (aka compal reference board). We actually do the check by the BIOS + * vendor name, version and serial so we can extend it to try and catch + * non Dell stuff later. + */ + +void apm_battery_horked(void) +{ + dell_crap = 1; +} + static int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy) { char * p; @@ -1270,7 +1272,7 @@ p = buf; - if ((smp_num_cpus == 1) && + if ((smp_num_cpus == 1) && (!dell_crap) && !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; battery_status = bx & 0xff; @@ -1438,7 +1440,7 @@ return 0; } -void __init apm_setup(char *str, int *dummy) +static int __init apm_setup(char *str) { int invert; @@ -1458,6 +1460,7 @@ if (str != NULL) str += strspn(str, ", \t"); } + return 1; } __setup("apm=", apm_setup); @@ -1476,13 +1479,12 @@ &apm_bios_fops }; -#define APM_INIT_ERROR_RETURN return -void __init apm_init(void) +static int __init apm_init(void) { if (apm_bios_info.version == 0) { printk(KERN_INFO "apm: BIOS not found.\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } printk(KERN_INFO "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", @@ -1492,7 +1494,7 @@ driver_version); if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { printk(KERN_INFO "apm: no 32 bit BIOS support\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } /* @@ -1521,11 +1523,11 @@ if (apm_disabled) { printk(KERN_NOTICE "apm: disabled on user request.\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } if ((smp_num_cpus > 1) && !power_off_enabled) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } /* @@ -1573,7 +1575,7 @@ if (smp_num_cpus > 1) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe (power off active).\n"); - APM_INIT_ERROR_RETURN; + return 0; } init_timer(&apm_timer); @@ -1586,6 +1588,7 @@ #ifdef CONFIG_APM_CPU_IDLE acpi_idle = apm_cpu_idle; #endif + return 0; } module_init(apm_init) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.2.17/arch/i386/kernel/bios32.c Sun Jun 11 21:44:09 2000 +++ linux/arch/i386/kernel/bios32.c Sat Sep 2 23:44:17 2000 @@ -1055,7 +1055,6 @@ /* * Find and scan busses behind ServerWorks north bridge chips */ - struct pci_bus *bus; unsigned char busno, busmax; pci_probe |= PCI_NO_PEER_FIXUP; pci_read_config_byte(d, 0x44, &busno); @@ -1070,7 +1069,6 @@ /* * Find and scan busses behind RCC LE north bridge chips */ - struct pci_bus *bus; unsigned char busno, busmax; pci_probe |= PCI_NO_PEER_FIXUP; pci_read_config_byte(d, 0xc8, &busno); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c --- v2.2.17/arch/i386/kernel/bluesmoke.c Sat Sep 9 18:42:32 2000 +++ linux/arch/i386/kernel/bluesmoke.c Sun Sep 17 17:44:37 2000 @@ -22,7 +22,7 @@ if(mcgstl&(1<<0)) /* Recoverable ? */ recover=0; - printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x", smp_processor_id(), mcgstl, mcgsth); + printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); for(i=0;i +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_SMP + +struct cpuid_command { + int cpu; + u32 reg; + u32 *data; +}; + +static void cpuid_smp_cpuid(void *cmd_block) +{ + struct cpuid_command *cmd = (struct cpuid_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]); +} + +extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +{ + struct cpuid_command cmd; + + if ( cpu == smp_processor_id() ) { + cpuid(reg, &data[0], &data[1], &data[2], &data[3]); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + cmd.data = data; + + smp_call_function(cpuid_smp_cpuid, &cmd, 1, 1); + } +} +#else /* ! CONFIG_SMP */ + +extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +{ + cpuid(reg, &data[0], &data[1], &data[2], &data[3]); +} + +#endif /* ! CONFIG_SMP */ + +static loff_t cpuid_seek(struct file *file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; /* SEEK_END not supported */ + } +} + +static ssize_t cpuid_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + u32 *tmp = (u32 *)buf; + u32 data[4]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + + if ( count % 16 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 16 ) { + do_cpuid(cpu, reg, data); + if ( copy_to_user(tmp,&data,16) ) + return -EFAULT; + tmp += 4; + *ppos = reg++; + } + + return ((char *)tmp) - buf; +} + +static int cpuid_open(struct inode *inode, struct file *file) +{ + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + struct cpuinfo_x86 *c = &(cpu_data)[cpu]; + + if ( !(cpu_online_map & (1UL << cpu)) ) + return -ENXIO; /* No such CPU */ + if ( c->cpuid_level < 0 ) + return -EIO; /* CPUID not supported */ + + return 0; +} + +/* + * File operations we support + */ +static struct file_operations cpuid_fops = { + llseek: cpuid_seek, + read: cpuid_read, + open: cpuid_open, +}; + +int __init cpuid_init(void) +{ + if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) { + printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n", + CPUID_MAJOR); + return -EBUSY; + } + + return 0; +} + +static void cpuid_exit(void) +{ +} + +module_init(cpuid_init); +module_exit(cpuid_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("H. Peter Anvin "); +MODULE_DESCRIPTION("x86 generic CPUID driver"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c --- v2.2.17/arch/i386/kernel/dmi_scan.c Thu Jan 1 01:00:00 1970 +++ linux/arch/i386/kernel/dmi_scan.c Thu Dec 7 15:14:02 2000 @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include + +struct dmi_header +{ + u8 type; + u8 length; + u16 handle; +}; + +static char * __init dmi_string(struct dmi_header *dm, u8 s) +{ + u8 *bp=(u8 *)dm; + bp+=dm->length; + s--; + while(s>0) + { + bp+=strlen(bp); + bp++; + s--; + } + return bp; +} + +static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *)) +{ + u8 *buf; + struct dmi_header *dm; + u8 *data; + int i=1; + int last = 0; + + buf = ioremap(base, len); + if(buf==NULL) + return -1; + + data = buf; + while(itype < last) + break; + last = dm->type; + decode(dm); + data+=dm->length; + while(*data || data[1]) + data++; + data+=2; + i++; + } + iounmap(buf); + return 0; +} + + +int __init dmi_iterate(void (*decode)(struct dmi_header *)) +{ + unsigned char buf[20]; + long fp=0xE0000L; + fp -= 16; + + while( fp < 0xFFFFF) + { + fp+=16; + memcpy_fromio(buf, fp, 20); + if(memcmp(buf, "_DMI_", 5)==0) + { + u16 num=buf[13]<<8|buf[12]; + u16 len=buf[7]<<8|buf[6]; + u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; +#ifdef DUMP_DMI + printk(KERN_INFO "DMI %d.%d present.\n", + buf[14]>>4, buf[14]&0x0F); + printk(KERN_INFO "%d structures occupying %d bytes.\n", + buf[13]<<8|buf[12], + buf[7]<<8|buf[6]); + printk(KERN_INFO "DMI table at 0x%08X.\n", + buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]); +#endif + if(dmi_table(base,len, num, decode)==0) + return 0; + } + } + return -1; +} + + +/* + * Process a DMI table entry. Right now all we care about are the BIOS + * and machine entries. For 2.4 we should pull the smbus controller info + * out of here. + */ + +static void __init dmi_decode(struct dmi_header *dm) +{ + u8 *data = (u8 *)dm; + char *p; + + switch(dm->type) + { + case 0: +#ifdef DUMP_DMI + p=dmi_string(dm,data[4]); + if(*p && *p!=' ') + { + printk("BIOS Vendor: %s\n", p); + printk("BIOS Version: %s\n", + dmi_string(dm, data[5])); + printk("BIOS Release: %s\n", + dmi_string(dm, data[8])); + } +#endif + /* + * Check for clue free BIOS implementations who use + * the following QA technique + * + * [ Write BIOS Code ]<------ + * | ^ + * < Does it Compile >----N-- + * |Y ^ + * < Does it Boot Win98 >-N-- + * |Y + * [Ship It] + */ + + if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0 && + strcmp(dmi_string(dm, data[5]), "A04")==0 && + strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) + { +#ifdef CONFIG_APM + extern void apm_battery_horked(void); + apm_battery_horked(); + printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling battery reporting.\n"); +#endif + } + break; +#ifdef DUMP_DMI + case 1: + p=dmi_string(dm,data[4]); + + if(*p && *p!=' ') + { + printk("System Vendor: %s.\n",p); + printk("Product Name: %s.\n", + dmi_string(dm, data[5])); + printk("Version %s.\n", + dmi_string(dm, data[6])); + printk("Serial Number %s.\n", + dmi_string(dm, data[7])); + } + break; + case 2: + p=dmi_string(dm,data[4]); + + if(*p && *p!=' ') + { + printk("Board Vendor: %s.\n",p); + printk("Board Name: %s.\n", + dmi_string(dm, data[5])); + printk("Board Version: %s.\n", + dmi_string(dm, data[6])); + } + break; + case 3: + p=dmi_string(dm,data[8]); + if(*p && *p!=' ') + printk("Asset Tag: %s.\n", p); + break; +#endif + } +} + +int __init dmi_scan_machine(void) +{ + return dmi_iterate(dmi_decode); +} + +__initcall(dmi_scan_machine); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.2.17/arch/i386/kernel/i386_ksyms.c Fri Apr 21 12:45:45 2000 +++ linux/arch/i386/kernel/i386_ksyms.c Sat Oct 28 13:56:47 2000 @@ -20,6 +20,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); +extern spinlock_t rtc_lock; #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; @@ -41,7 +42,7 @@ EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(kernel_thread); - +EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL(init_mm); EXPORT_SYMBOL_NOVERS(__down_failed); @@ -119,3 +120,4 @@ #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c --- v2.2.17/arch/i386/kernel/microcode.c Thu Jan 1 01:00:00 1970 +++ linux/arch/i386/kernel/microcode.c Sat Oct 28 11:29:30 2000 @@ -0,0 +1,340 @@ +/* + * CPU Microcode Update interface for Linux + * + * Copyright (C) 2000 Tigran Aivazian + * + * This driver allows to upgrade microcode on Intel processors + * belonging to P6 family - PentiumPro, Pentium II, Pentium III etc. + * + * Reference: Section 8.10 of Volume III, Intel Pentium III Manual, + * Order Number 243192 or download from: + * + * http://developer.intel.com/design/pentiumii/manuals/243192.htm + * + * 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. + * + * 1.0 16 February 2000, Tigran Aivazian + * Initial release. + * 1.01 18 February 2000, Tigran Aivazian + * Added read() support + cleanups. + * 1.02 21 February 2000, Tigran Aivazian + * Added 'device trimming' support. open(O_WRONLY) zeroes + * and frees the saved copy of applied microcode. + * 1.03 29 February 2000, Tigran Aivazian + * Made to use devfs (/dev/cpu/microcode) + cleanups. + * 1.04 06 June 2000, Simon Trimmer + * Added misc device support (now uses both devfs and misc). + * Added MICROCODE_IOCFREE ioctl to clear memory. + * 1.05 09 June 2000, Simon Trimmer + * Messages for error cases (non intel & no suitable microcode). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MICROCODE_MINOR 184 +#define MICROCODE_IOCFREE _IO('6',0) +struct microcode { + unsigned int hdrver; + unsigned int rev; + unsigned int date; + unsigned int sig; + unsigned int cksum; + unsigned int ldrver; + unsigned int pf; + unsigned int reserved[5]; + unsigned int bits[500]; +}; + +#define MICROCODE_VERSION "1.05" + +MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver"); +MODULE_AUTHOR("Tigran Aivazian "); +EXPORT_NO_SYMBOLS; + +/* VFS interface */ +static int microcode_open(struct inode *, struct file *); +static int microcode_release(struct inode *, struct file *); +static ssize_t microcode_read(struct file *, char *, size_t, loff_t *); +static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *); +static int microcode_ioctl(struct inode *, struct file *, unsigned int, unsigned long); + + +/* internal helpers to do the work */ +static int do_microcode_update(void); +static void do_update_one(void *); + +/* + * Bits in microcode_status. (31 bits of room for future expansion) + */ +#define MICROCODE_IS_OPEN 0 /* set if device is in use */ + +static unsigned long microcode_status; + +/* the actual array of microcode blocks, each 2048 bytes */ +static struct microcode *microcode; +static unsigned int microcode_num; +static char *mc_applied; /* holds an array of applied microcode blocks */ +static unsigned int mc_fsize; + +static struct file_operations microcode_fops = { + read: microcode_read, + write: microcode_write, + ioctl: microcode_ioctl, + open: microcode_open, + release: microcode_release, +}; + +static struct miscdevice microcode_dev = { + minor: MICROCODE_MINOR, + name: "microcode", + fops: µcode_fops, +}; + +int __init microcode_init(void) +{ + int error = 0; + + if (misc_register(µcode_dev) < 0) { + printk(KERN_WARNING + "microcode: can't misc_register on minor=%d\n", + MICROCODE_MINOR); + error = 1; + } + printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", + MICROCODE_VERSION); + return 0; +} + +#ifdef MODULE +static void microcode_exit(void) +{ + misc_deregister(µcode_dev); + if (mc_applied) + kfree(mc_applied); + printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", + MICROCODE_VERSION); +} + +int init_module(void) +{ + return microcode_init(); +} +void cleanup_module(void) +{ + microcode_exit(); +} +#endif + +/* + * We enforce only one user at a time here with open/close. + */ +static int microcode_open(struct inode *inode, struct file *file) +{ + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* one at a time, please */ + if (test_and_set_bit(MICROCODE_IS_OPEN, µcode_status)) + return -EBUSY; + + return 0; +} + +static int microcode_release(struct inode *inode, struct file *file) +{ + clear_bit(MICROCODE_IS_OPEN, µcode_status); + return 0; +} + +/* a pointer to 'struct update_req' is passed to the IPI handler = do_update_one() + * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise + * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode + */ +struct update_req { + int err; + int slot; +} update_req[NR_CPUS]; + +static int do_microcode_update(void) +{ + int i, error = 0, err; + struct microcode *m; + + if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0) + panic("do_microcode_update(): timed out waiting for other CPUs\n"); + + do_update_one((void *)update_req); + + for (i=0; ierr = 1; /* be pessimistic */ + + if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6){ + printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num ); + return; + } + + sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8); + + if (c->x86_model >= 5) { + /* get processor flags from BBL_CR_OVRD MSR (0x17) */ + rdmsr(0x17, val[0], val[1]); + pf = 1 << ((val[1] >> 18) & 7); + } + + for (i=0; i= (unsigned int *)m) + sum += *sump; + if (sum != 0) { + printk(KERN_ERR "microcode: CPU%d aborting, " + "bad checksum\n", cpu_num); + break; + } + + wrmsr(0x79, (unsigned int)(m->bits), 0); + __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); + rdmsr(0x8B, val[0], val[1]); + + req->err = 0; + req->slot = i; + printk(KERN_ERR "microcode: CPU%d updated from revision " + "%d to %d, date=%08x\n", + cpu_num, rev, val[1], m->date); + } + break; + } + + if(!found) + printk(KERN_ERR "microcode: found no data for CPU%d (sig=%x, pflags=%d)\n", cpu_num, sig, pf); +} + +static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) +{ + if (*ppos >= mc_fsize) + return 0; + if (*ppos + len > mc_fsize) + len = mc_fsize - *ppos; + if (copy_to_user(buf, mc_applied + *ppos, len)) + return -EFAULT; + *ppos += len; + return len; +} + +static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos) +{ + ssize_t ret; + + if (len % sizeof(struct microcode) != 0) { + printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", + sizeof(struct microcode)); + return -EINVAL; + } + if (!mc_applied) { + mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode), + GFP_KERNEL); + if (!mc_applied) { + printk(KERN_ERR "microcode: out of memory for saved microcode\n"); + return -ENOMEM; + } + memset(mc_applied, 0, mc_fsize); + } + + lock_kernel(); + microcode_num = len/sizeof(struct microcode); + microcode = vmalloc(len); + if (!microcode) { + ret = -ENOMEM; + goto out_unlock; + } + if (copy_from_user(microcode, buf, len)) { + ret = -EFAULT; + goto out_fsize; + } + if(do_microcode_update()) { + ret = -EIO; + goto out_fsize; + } else { + mc_fsize = smp_num_cpus * sizeof(struct microcode); + ret = (ssize_t)len; + } +out_fsize: + vfree(microcode); +out_unlock: + unlock_kernel(); + return ret; +} + +static int microcode_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case MICROCODE_IOCFREE: + if (mc_applied) { + memset(mc_applied, 0, mc_fsize); + kfree(mc_applied); + mc_applied = NULL; + printk(KERN_WARNING + "microcode: freed %d bytes\n", mc_fsize); + mc_fsize = 0; + return 0; + } + return -ENODATA; + + default: + printk(KERN_ERR "microcode: unknown ioctl cmd=%d\n", + cmd); + return -EINVAL; + } + /* NOT REACHED */ + return -EINVAL; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c --- v2.2.17/arch/i386/kernel/msr.c Thu Jan 1 01:00:00 1970 +++ linux/arch/i386/kernel/msr.c Thu Oct 19 01:25:23 2000 @@ -0,0 +1,270 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2000 H. Peter Anvin - 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * msr.c + * + * x86 MSR access device + * + * This device is accessed by lseek() to the appropriate register number + * and then read/write in chunks of 8 bytes. A larger size means multiple + * reads or writes of the same register. + * + * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on + * an SMP box will direct the access to CPU %d. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Note: "err" is handled in a funny way below. Otherwise one version + of gcc or another breaks. */ + +extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) +{ + int err; + + asm volatile( + "1: wrmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "=&bDS" (err) + : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0)); + + return err; +} + +extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) +{ + int err; + + asm volatile( + "1: rdmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "=&bDS" (err), "=a" (*eax), "=d" (*edx) + : "c" (reg), "i" (-EIO), "0" (0)); + + return err; +} + +#ifdef CONFIG_SMP + +struct msr_command { + int cpu; + int err; + u32 reg; + u32 data[2]; +}; + +static void msr_smp_wrmsr(void *cmd_block) +{ + struct msr_command *cmd = (struct msr_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); +} + +static void msr_smp_rdmsr(void *cmd_block) +{ + struct msr_command *cmd = (struct msr_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); +} + +extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +{ + struct msr_command cmd; + + if ( cpu == smp_processor_id() ) { + return wrmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + cmd.data[0] = eax; + cmd.data[1] = edx; + + smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); + return cmd.err; + } +} + +extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +{ + struct msr_command cmd; + + if ( cpu == smp_processor_id() ) { + return rdmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + + smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); + + *eax = cmd.data[0]; + *edx = cmd.data[1]; + + return cmd.err; + } +} + +#else /* ! CONFIG_SMP */ + +extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +{ + return wrmsr_eio(reg, eax, edx); +} + +extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +{ + return rdmsr_eio(reg, eax, edx); +} + +#endif /* ! CONFIG_SMP */ + +static loff_t msr_seek(struct file *file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; /* SEEK_END not supported */ + } +} + +static ssize_t msr_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + u32 *tmp = (u32 *)buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int err; + + if ( count % 8 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 8 ) { + err = do_rdmsr(cpu, reg, &data[0], &data[1]); + if ( err ) + return err; + if ( copy_to_user(tmp,&data,8) ) + return -EFAULT; + tmp += 2; + } + + return ((char *)tmp) - buf; +} + +static ssize_t msr_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + const u32 *tmp = (const u32 *)buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int err; + + if ( count % 8 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 8 ) { + if ( copy_from_user(&data,tmp,8) ) + return -EFAULT; + err = do_wrmsr(cpu, reg, data[0], data[1]); + if ( err ) + return err; + tmp += 2; + } + + return ((char *)tmp) - buf; +} + +static int msr_open(struct inode *inode, struct file *file) +{ + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + struct cpuinfo_x86 *c = &(cpu_data)[cpu]; + + if ( !(cpu_online_map & (1UL << cpu)) ) + return -ENXIO; /* No such CPU */ + if ( !(c->x86_capability & X86_FEATURE_MSR) ) + return -EIO; /* MSR not supported */ + + return 0; +} + +/* + * File operations we support + */ +static struct file_operations msr_fops = { + llseek: msr_seek, + read: msr_read, + write: msr_write, + open: msr_open, +}; + +int __init msr_init(void) +{ + if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { + printk(KERN_ERR "msr: unable to get major %d for msr\n", + MSR_MAJOR); + return -EBUSY; + } + + return 0; +} + +static void msr_exit(void) +{ +} + +module_init(msr_init); +module_exit(msr_exit); + +MODULE_AUTHOR("H. Peter Anvin "); +MODULE_DESCRIPTION("x86 generic MSR driver"); +EXPORT_NO_SYMBOLS; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.2.17/arch/i386/kernel/mtrr.c Fri Apr 21 12:45:45 2000 +++ linux/arch/i386/kernel/mtrr.c Wed Sep 27 21:05:41 2000 @@ -305,7 +305,7 @@ static unsigned int ascii_buf_bytes = 0; #endif static unsigned int *usage_table = NULL; -static spinlock_t main_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t main_lock __attribute((unused)) = SPIN_LOCK_UNLOCKED; /* Private functions */ #ifdef CONFIG_PROC_FS @@ -337,7 +337,8 @@ if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ /* else fall through */ case X86_VENDOR_CENTAUR: - return; + if(boot_cpu_data.x86 != 6) + return; /*break;*/ } /* Save value of CR4 and clear Page Global Enable (bit 7) */ @@ -361,6 +362,7 @@ { case X86_VENDOR_AMD: case X86_VENDOR_INTEL: + case X86_VENDOR_CENTAUR: /* Disable MTRRs, and set the default type to uncached */ rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); @@ -384,8 +386,11 @@ if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ /* else fall through */ case X86_VENDOR_CENTAUR: - __restore_flags (ctxt->flags); - return; + if(boot_cpu_data.x86 != 6) + { + __restore_flags (ctxt->flags); + return; + } /*break;*/ } /* Flush caches and TLBs */ @@ -396,6 +401,7 @@ { case X86_VENDOR_AMD: case X86_VENDOR_INTEL: + case X86_VENDOR_CENTAUR: wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); break; case X86_VENDOR_CYRIX: @@ -434,9 +440,17 @@ /*break;*/ case X86_VENDOR_CYRIX: /* Cyrix have 8 ARRs */ + return 8; case X86_VENDOR_CENTAUR: /* and Centaur has 8 MCR's */ - return 8; + if(boot_cpu_data.x86==5) + return 8; + /* the cyrix III has intel compatible MTRR */ + if(boot_cpu_data.x86==6) + { + rdmsr (MTRRcap_MSR, config, dummy); + return (config & 0xff); + } /*break;*/ } return 0; @@ -452,12 +466,15 @@ case X86_VENDOR_AMD: if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */ /* else fall through */ + case X86_VENDOR_CENTAUR: + if (boot_cpu_data.x86 == 5) + return 1; /* C6 */ + /* CyrixIII is Intel like */ case X86_VENDOR_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & (1<<10)); /*break;*/ case X86_VENDOR_CYRIX: - case X86_VENDOR_CENTAUR: return 1; /*break;*/ } @@ -1135,7 +1152,7 @@ printk ("mtrr: size: %lx base: %lx\n", size, base); return -EINVAL; } - if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) + if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 5) { if (centaur_ctx->type_bits[type]==0) { printk ("mtrr: type not supported\n"); @@ -1758,8 +1775,16 @@ get_free_region = cyrix_get_free_region; break; case X86_VENDOR_CENTAUR: - get_mtrr = centaur_get_mcr; - set_mtrr_up = centaur_set_mcr_up; + if(boot_cpu_data.x86 == 5) + { + get_mtrr = centaur_get_mcr; + set_mtrr_up = centaur_set_mcr_up; + } + if(boot_cpu_data.x86 == 6) + { + get_mtrr = intel_get_mtrr; + set_mtrr_up = intel_set_mtrr_up; + } break; } } /* End Function mtrr_setup */ @@ -1783,8 +1808,11 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; - case X86_VENDOR_CENTAUR: - centaur_mcr_init (); + case X86_VENDOR_CENTAUR: /* C6 and Cyrix III have different ones */ + if(boot_cpu_data.x86 == 5) + centaur_mcr_init (); + if(boot_cpu_data.x86 == 6) + get_mtrr_state(&smp_mtrr_state); break; } } /* End Function mtrr_init_boot_cpu */ @@ -1856,7 +1884,8 @@ cyrix_arr_init (); break; case X86_VENDOR_CENTAUR: - centaur_mcr_init (); + if(boot_cpu_data.x86 == 5) + centaur_mcr_init (); break; } # endif /* !__SMP__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.2.17/arch/i386/kernel/process.c Fri Apr 21 12:45:45 2000 +++ linux/arch/i386/kernel/process.c Sat Nov 4 11:47:44 2000 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -253,8 +254,10 @@ */ void machine_real_restart(unsigned char *code, int length) { + unsigned long flags; + cli(); - + /* Write zero to CMOS register number 0x0f, which the BIOS POST routine will recognize as telling it to do a proper reboot. (Well that's what this book in front of me says -- it may only apply to @@ -264,8 +267,9 @@ `outb_p' is needed instead of just `outb'. Use it to be on the safe side. */ - outb_p (0x8f, 0x70); - outb_p (0x00, 0x71); + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0x00, 0x8f); + spin_unlock_irqrestore(&rtc_lock, flags); /* Remap the kernel at virtual address zero, as well as offset zero from the kernel segment. This assumes the kernel segment starts at diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.2.17/arch/i386/kernel/setup.c Sat Sep 9 18:42:32 2000 +++ linux/arch/i386/kernel/setup.c Wed Nov 22 16:39:42 2000 @@ -16,19 +16,29 @@ * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999. * * IDT Winchip tweaks, misc clean ups. - * Dave Jones , August 1999 + * Dave Jones , August 1999 * * Added proper L2 cache detection for Coppermine * Dragan Stancevic , October 1999 * * Improved Intel cache detection. - * Dave Jones , October 1999 + * Dave Jones , October 1999 * * Added proper Cascades CPU and L2 cache detection for Cascades * and 8-way type cache happy bunch from Intel:^) * Dragan Stancevic , May 2000 * * Transmeta CPU detection. H. Peter Anvin , May 2000 + * + * Cleaned up get_model_name(), AMD_model(), added display_cacheinfo(). + * Dave Jones , September 2000 + * + * Added Cyrix III initial detection code + * Alan Cox , Septembr 2000 + * + * Improve cache size calculation + * Asit Mallick , October 2000 + * Andrew Ip , October 2000 */ /* @@ -428,19 +438,16 @@ conswitchp = &dummy_con; #endif #endif - /* - * Check the bugs that will bite us before we get booting - */ - } + __initfunc(static int get_model_name(struct cpuinfo_x86 *c)) { - unsigned int n, dummy, *v, ecx, edx; + unsigned int n, dummy, *v; /* * Actually we must have cpuid or we could never have - * figured out that this was AMD/Cyrix/Transmeta + * figured out that this was AMD/Centaur/Cyrix/Transmeta * from the vendor info :-). */ @@ -454,49 +461,44 @@ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); c->x86_model_id[48] = 0; - switch(c->x86_vendor) - { - case X86_VENDOR_AMD: - /* Set MTRR capability flag if appropriate */ - if(boot_cpu_data.x86 == 5) { - if((boot_cpu_data.x86_model == 9) || - ((boot_cpu_data.x86_model == 8) && - (boot_cpu_data.x86_mask >= 8))) - c->x86_capability |= X86_FEATURE_MTRR; - } + return 1; +} - /* Fall through */ - case X86_VENDOR_TRANSMETA: - /* Cache information */ - if (n >= 0x80000005){ - cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); - printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", - ecx>>24, edx>>24); - c->x86_cache_size=(ecx>>24)+(edx>>24); - } - if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - boot_cpu_data.x86 == 6 && - boot_cpu_data.x86_model== 3 && - boot_cpu_data.x86_mask == 0) - { - /* AMD errata T13 (order #21922) */ - printk("CPU: L2 Cache: 64K\n"); - c->x86_cache_size = 64; - } - else if (n >= 0x80000006){ - cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); - printk("CPU: L2 Cache: %dK\n", ecx>>16); - c->x86_cache_size = ecx>>16; - } - break; +__initfunc (static void display_cacheinfo(struct cpuinfo_x86 *c)) +{ + unsigned int n, dummy, ecx, edx; - default: /* Cyrix */ - break; + cpuid(0x80000000, &n, &dummy, &dummy, &dummy); + + if (n >= 0x80000005){ + cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); + printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", + ecx>>24, edx>>24); + c->x86_cache_size=(ecx>>24)+(edx>>24); + } + + /* Yes this can occur - the CyrixIII just has a large L1 */ + if (n < 0x80000006) + return; /* No function to get L2 info */ + + cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); + c->x86_cache_size = ecx>>16; + + /* AMD errata T13 (order #21922) */ + if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model== 3 && + boot_cpu_data.x86_mask == 0) + { + c->x86_cache_size = 64; } - return 1; + + printk("CPU: L2 Cache: %dK\n", c->x86_cache_size); } + + __initfunc(static int amd_model(struct cpuinfo_x86 *c)) { u32 l, h; @@ -517,7 +519,7 @@ /* Anyone with a K5 want to fill this in */ break; } - + /* K6 with old style WHCR */ if( c->x86_model < 8 || (c->x86_model== 8 && c->x86_mask < 8)) @@ -537,16 +539,17 @@ restore_flags(flags); printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", mbytes); - + } break; } - if (c->x86_model == 8 || c->x86_model == 9) + if (c->x86_model == 8 || c->x86_model == 9 || c->x86_model == 13) { /* The more serious chips .. */ if(mbytes>4092) mbytes=4092; + rdmsr(0xC0000082, l, h); if((l&0xFFFF0000)==0) { @@ -559,17 +562,36 @@ printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", mbytes); } + + /* Set MTRR capability flag if appropriate */ + if((boot_cpu_data.x86_model == 13) || + (boot_cpu_data.x86_model == 9) || + ((boot_cpu_data.x86_model == 8) && + (boot_cpu_data.x86_mask >= 8))) + c->x86_capability |= X86_FEATURE_MTRR; break; } break; + case 6: /* An Athlon. We can trust the BIOS probably */ { break; } - } + + display_cacheinfo(c); return r; } + +__initfunc(static void intel_model(struct cpuinfo_x86 *c)) +{ + unsigned int *v = (unsigned int *) c->x86_model_id; + cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); + cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); + cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); + c->x86_model_id[48] = 0; + printk("CPU: %s\n", c->x86_model_id); +} /* @@ -691,18 +713,17 @@ */ #ifdef CONFIG_PCI_QUIRKS - /* It isnt really a PCI quirk directly, but the cure is the - same. The MediaGX has deep magic SMM stuff that handles the - SB emulation. It thows away the fifo on disable_dma() which - is wrong and ruins the audio. - - Bug2: VSA1 has a wrap bug so that using maximum sized DMA - causes bad things. According to NatSemi VSA2 has another - bug to do with 'hlt'. I've not seen any boards using VSA2 - and X doesn't seem to support it either so who cares 8). - VSA1 we work around however. + /* It isnt really a PCI quirk directly, but the cure is the + same. The MediaGX has deep magic SMM stuff that handles the + SB emulation. It thows away the fifo on disable_dma() which + is wrong and ruins the audio. - */ + Bug2: VSA1 has a wrap bug so that using maximum sized DMA + causes bad things. According to NatSemi VSA2 has another + bug to do with 'hlt'. I've not seen any boards using VSA2 + and X doesn't seem to support it either so who cares 8). + VSA1 we work around however. + */ printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bug.\n"); isa_dma_bridge_buggy = 2; @@ -759,12 +780,13 @@ __initfunc(static void transmeta_model(struct cpuinfo_x86 *c)) { - unsigned int cap_mask, uk, max, dummy, n, ecx, edx; + unsigned int cap_mask, uk, max, dummy; unsigned int cms_rev1, cms_rev2; unsigned int cpu_rev, cpu_freq, cpu_flags; char cpu_info[65]; get_model_name(c); /* Same as AMD/Cyrix */ + display_cacheinfo(c); /* Print CMS and CPU revision */ cpuid(0x80860000, &max, &dummy, &dummy, &dummy); @@ -895,8 +917,9 @@ { int i; char *p = NULL; - - c->loops_per_sec = loops_per_sec; + extern void mcheck_init(void); + + c->loops_per_jiffy = loops_per_jiffy; c->x86_cache_size = -1; get_cpu_vendor(c); @@ -917,7 +940,7 @@ printk(KERN_INFO "CPU serial number disabled.\n"); } - mcheck_init(c); + mcheck_init(); if (c->x86_vendor == X86_VENDOR_CYRIX) { cyrix_model(c); @@ -931,48 +954,110 @@ transmeta_model(c); return; } + + if(c->x86_vendor == X86_VENDOR_CENTAUR && c->x86==6) + { + /* The Cyrix III supports model naming and cache queries */ + get_model_name(c); + display_cacheinfo(c); + return; + } if (c->cpuid_level > 1) { /* supports eax=2 call */ - int edx, dummy; - - cpuid(2, &dummy, &dummy, &dummy, &edx); + int regs[4]; + int l1c=0, l1d=0, l2=0, l3=0; /* Cache sizes */ - /* We need only the LSB */ - edx &= 0xff; + cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]); - switch (edx) { - case 0x40: - c->x86_cache_size = 0; - break; + /* Least significant byte of eax says how many times + * to call cpuid with value 2 to get cache and TLB + * info. + */ + if ((regs[0] & 0xFF) != 1 ) + printk(KERN_WARNING "Multiple cache reports are not supported yet\n"); - case 0x41: /* 4-way 128 */ - c->x86_cache_size = 128; - break; + c->x86_cache_size = 0; - case 0x42: /* 4-way 256 */ - case 0x82: /* 8-way 256 */ - c->x86_cache_size = 256; - break; + for ( i = 0 ; i < 4 ; i++ ) { - case 0x43: /* 4-way 512 */ - c->x86_cache_size = 512; - break; + int j; - case 0x44: /* 4-way 1024 */ - case 0x84: /* 8-way 1024 */ - c->x86_cache_size = 1024; - break; + if ( regs[i] < 0 ) + continue; /* no useful data */ + + /* look at all the bytes returned */ + + for ( j = ( i == 0 ? 8:0 ) ; j < 25 ; j+=8 ) { + + unsigned char rh = regs[i]>>j; + unsigned char rl; + + rl = rh & 0x0F; + rh >>=4; + + switch(rh) { + + case 2: + if(rl) { + printk("%dK L3 cache\n", (rl-1)*512); + l3 += (rl-1)*512; + } + break; + + case 4: + case 8: + if(rl) { + printk("%dK L2 cache (%d way)\n",128<<(rl-1), rh); + l2 += 128<<(rl-1); + } + break; + + /* + * L1 caches do not count for SMP switching weights, + * they are shadowed by L2. + */ + + case 6: + if(rh==6 && rl > 5) { + printk("%dK L1 data cache\n", 8<<(rl - 6)); + l1d+=8<<(rl-6); + } + break; + + case 7: + printk("%dK L1 instruction cache\n", + rl?(16<<(rl-1)):12); + l1c+=rl?(16<<(rl-1)):12; + break; + } + } + } - case 0x45: /* 4-way 2048 */ - case 0x85: /* 8-way 2048 */ - c->x86_cache_size = 2048; - break; + if(l1c && l1d) + printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", l1c, l1d); + if(l2) + printk("CPU: L2 Cache: %dK\n", l2); + if(l3) + printk("CPU: L3 Cache: %dK\n", l3); - default: - c->x86_cache_size = 0; - break; - } + /* + * Assuming L3 is shared. The L1 cache is shadowed by L2 + * so doesn't need to be included. + */ + + c->x86_cache_size += l2; + } + + /* + * Intel finally adopted the AMD/Cyrix extended id naming + * stuff for the 'Pentium IV' + */ + + if(c->x86_vendor ==X86_VENDOR_INTEL && c->x86 == 15) + { + intel_model(c); + return; } for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) { @@ -981,19 +1066,18 @@ 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 */ if ((cpu_models[i].vendor == X86_VENDOR_INTEL) && (cpu_models[i].x86 == 6)){ if(c->x86_model == 6 && c->x86_cache_size == 128) { - p = "Celeron (Mendocino)"; - } - else { - if (c->x86_model == 5 && c->x86_cache_size == 0) { - p = "Celeron (Covington)"; - } - } - } + p = "Celeron (Mendocino)"; + } else { + if (c->x86_model == 5 && c->x86_cache_size == 0) { + p = "Celeron (Covington)"; + } + } + } } } @@ -1026,6 +1110,49 @@ "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; +__initfunc(void setup_centaur(struct cpuinfo_x86 *c)) +{ + u32 hv,lv; + + /* Centaur C6 Series */ + if(c->x86==5) + { + rdmsr(0x107, lv, hv); + printk("Centaur FSR was 0x%X ",lv); + lv|=(1<<1 | 1<<2 | 1<<7); + /* lv|=(1<<6); - may help too if the board can cope */ + printk("now 0x%X\n", lv); + wrmsr(0x107, lv, hv); + /* Emulate MTRRs using Centaur's MCR. */ + c->x86_capability |= X86_FEATURE_MTRR; + + /* Disable TSC on C6 as per errata. */ + if (c->x86_model ==4) { + printk ("Disabling bugged TSC.\n"); + c->x86_capability &= ~X86_FEATURE_TSC; + } + + /* Set 3DNow! on Winchip 2 and above. */ + if (c->x86_model >=8) + c->x86_capability |= X86_FEATURE_AMD3D; + + c->x86_capability |=X86_FEATURE_CX8; + } + /* Cyrix III 'Samuel' CPU */ + if(c->x86 == 6 && c->x86_model == 6) + { + rdmsr(0x1107, lv, hv); + lv|=(1<<1); /* Report CX8 */ + lv|=(1<<7); /* PGE enable */ + wrmsr(0x1107, lv, hv); + /* Cyrix III */ + c->x86_capability |= X86_FEATURE_CX8; + rdmsr(0x80000001, lv, hv); + if(hv&(1<<31)) + c->x86_capability |= X86_FEATURE_AMD3D; + } +} + __initfunc(void print_cpu_info(struct cpuinfo_x86 *c)) { char *vendor = NULL; @@ -1049,27 +1176,7 @@ printk("\n"); if(c->x86_vendor == X86_VENDOR_CENTAUR) { - u32 hv,lv; - rdmsr(0x107, lv, hv); - printk("Centaur FSR was 0x%X ",lv); - lv|=(1<<1 | 1<<2 | 1<<7); - /* lv|=(1<<6); - may help too if the board can cope */ - printk("now 0x%X\n", lv); - wrmsr(0x107, lv, hv); - /* Emulate MTRRs using Centaur's MCR. */ - c->x86_capability |= X86_FEATURE_MTRR; - - /* Disable TSC on C6 as per errata. */ - if (c->x86_model ==4) { - printk ("Disabling bugged TSC.\n"); - c->x86_capability &= ~X86_FEATURE_TSC; - } - - /* Set 3DNow! on Winchip 2 and above. */ - if (c->x86_model >=8) - c->x86_capability |= X86_FEATURE_AMD3D; - - c->x86_capability |=X86_FEATURE_CX8; + setup_centaur(c); } } @@ -1082,10 +1189,10 @@ char *p = buffer; int sep_bug; 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; @@ -1097,12 +1204,12 @@ #endif p += sprintf(p,"processor\t: %d\n" "vendor_id\t: %s\n" - "cpu family\t: %c\n" + "cpu family\t: %d\n" "model\t\t: %d\n" "model name\t: %s\n", n, c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", - c->x86 + '0', + c->x86, c->x86_model, c->x86_model_id[0] ? c->x86_model_id : "unknown"); @@ -1132,7 +1239,8 @@ x86_cap_flags[10] = "sep"; if (c->x86 < 6) x86_cap_flags[16] = "fcmov"; - x86_cap_flags[16] = "pat"; + else + x86_cap_flags[16] = "pat"; x86_cap_flags[22] = "mmxext"; x86_cap_flags[24] = "fxsr"; x86_cap_flags[30] = "3dnowext"; @@ -1140,19 +1248,19 @@ 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[19] = "cflush"; + x86_cap_flags[21] = "dtrace"; + x86_cap_flags[22] = "acpi"; x86_cap_flags[24] = "fxsr"; - x86_cap_flags[25] = "xmm"; + x86_cap_flags[26] = "xmm2"; + x86_cap_flags[27] = "ssnp"; + x86_cap_flags[29] = "acc"; break; case X86_VENDOR_CENTAUR: if (c->x86_model >=8) /* Only Winchip2 and above */ - x86_cap_flags[31] = "3dnow"; + x86_cap_flags[31] = "3dnow"; break; default: @@ -1191,8 +1299,8 @@ if ( c->x86_capability & (1 << i) ) p += sprintf(p, " %s", x86_cap_flags[i]); p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n", - (c->loops_per_sec+2500)/500000, - ((c->loops_per_sec+2500)/5000) % 100); + c->loops_per_jiffy/(500000/HZ), + (c->loops_per_jiffy/(5000/HZ)) % 100); } return p - buffer; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.2.17/arch/i386/kernel/smp.c Sat Sep 9 18:42:32 2000 +++ linux/arch/i386/kernel/smp.c Sat Nov 18 00:28:38 2000 @@ -220,6 +220,8 @@ return("Pentium(tm)"); if (family==0x0F && model==0x0F) return("Special controller"); + if (family==0x0F && model==0x00) + return("Pentium 4(tm)"); if (family==0x04 && model<9) return model_defs[model]; sprintf(n,"Unknown CPU [%d:%d]",family, model); @@ -364,13 +366,20 @@ (struct mpc_config_ioapic *)mpt; if (m->mpc_flags&MPC_APIC_USABLE) { - ioapics++; - printk("I/O APIC #%d Version %d at 0x%lX.\n", - m->mpc_apicid,m->mpc_apicver, - m->mpc_apicaddr); - mp_apics [mp_apic_entries] = *m; - if (++mp_apic_entries > MAX_IO_APICS) - --mp_apic_entries; + if(m->mpc_apicaddr == 0) + { + printk(KERN_ERR "Error - Non MP compliant BIOS. Skipping invalid io-apic!\n"); + } + else + { + ioapics++; + printk("I/O APIC #%d Version %d at 0x%lX.\n", + m->mpc_apicid,m->mpc_apicver, + m->mpc_apicaddr); + mp_apics [mp_apic_entries] = *m; + if (++mp_apic_entries > MAX_IO_APICS) + --mp_apic_entries; + } } mpt+=sizeof(*m); count+=sizeof(*m); @@ -408,6 +417,12 @@ printk("Warning: switching to non APIC mode.\n"); skip_ioapic_setup=1; } + if (ioapics == 0) + { + printk("Warning: BIOS table gives no I/O APIC.\n"); + printk("Warning: switching to non APIC mode.\n"); + skip_ioapic_setup=1; + } return num_processors; } @@ -658,7 +673,7 @@ return virt_to_phys(trampoline_base); } -extern unsigned long i386_endbase __initdata; +extern unsigned long i386_endbase; /* * We are called very early to get the low memory for the * SMP bootup trampoline page. @@ -1107,7 +1122,8 @@ */ smp_callin(); while (!atomic_read(&smp_commenced)) - /* nothing */ ; + rep_nop() /* bus friendly nothing */ ; + return cpu_idle(NULL); } @@ -1596,12 +1612,12 @@ for(i=0;i<32;i++) { if (cpu_online_map&(1<tv_usec -= do_gettimeoffset(); + tv->tv_usec -= lost_ticks * (1000000 / HZ); while (tv->tv_usec < 0) { tv->tv_usec += 1000000; @@ -301,6 +309,8 @@ int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* gets recalled with irq locally disabled */ + spin_lock(&rtc_lock); save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -346,6 +356,7 @@ */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } @@ -447,10 +458,19 @@ rdtscl(last_tsc_low); +#if 0 /* + * SUBTLE: this is not necessary from here because it's implicit in the + * write xtime_lock. + */ + spin_lock(&i8253_lock); +#endif outb_p(0x00, 0x43); /* latch the count ASAP */ count = inb_p(0x40); /* read the latched count */ count |= inb(0x40) << 8; +#if 0 + spin_unlock(&i8253_lock); +#endif count = ((LATCH-1) - count) * TICK_SIZE; delay_at_last_interrupt = (count + LATCH/2) / LATCH; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.2.17/arch/i386/kernel/traps.c Sat Sep 9 18:42:32 2000 +++ linux/arch/i386/kernel/traps.c Mon Sep 11 17:51:59 2000 @@ -399,6 +399,7 @@ /* Ok, finally something we can handle */ tsk->tss.trap_no = 1; tsk->tss.error_code = error_code; + tsk->tss.debugreg[DR_STATUS] = condition; force_sig(SIGTRAP, tsk); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.2.17/arch/i386/lib/Makefile Fri Apr 21 12:45:46 2000 +++ linux/arch/i386/lib/Makefile Sat Oct 28 13:56:47 2000 @@ -3,7 +3,7 @@ # .S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $*.o L_TARGET = lib.a L_OBJS = checksum.o old-checksum.o semaphore.o delay.o \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/lib/delay.c linux/arch/i386/lib/delay.c --- v2.2.17/arch/i386/lib/delay.c Fri Apr 21 12:45:46 2000 +++ linux/arch/i386/lib/delay.c Sat Sep 30 14:41:43 2000 @@ -22,8 +22,7 @@ /* * Do a udelay using the TSC for any CPU that happens - * to have one that we trust. This could be optimised to avoid - * the multiply per loop but its a delay loop so who are we kidding... + * to have one that we trust. */ static void __rdtsc_delay(unsigned long loops) @@ -63,13 +62,19 @@ __loop_delay(loops); } +/* + * This could be optimised to avoid the multiply per loop but its a + * delay loop so who are we kidding... (we'd run into nasty 32-bit + * issues with delays > 10 ms or HZ > 100 that way) + */ + void __const_udelay(unsigned long xloops) { int d0; __asm__("mull %0" :"=d" (xloops), "=&a" (d0) - :"1" (xloops),"0" (current_cpu_data.loops_per_sec)); - __delay(xloops); + :"1" (xloops),"0" (current_cpu_data.loops_per_jiffy)); + __delay(xloops * HZ); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/math-emu/get_address.c linux/arch/i386/math-emu/get_address.c --- v2.2.17/arch/i386/math-emu/get_address.c Fri Apr 21 12:45:46 2000 +++ linux/arch/i386/math-emu/get_address.c Fri Sep 1 13:15:46 2000 @@ -155,6 +155,7 @@ { struct desc_struct descriptor; unsigned long base_address, limit, address, seg_top; + unsigned short selector; segment--; @@ -172,14 +173,16 @@ /* fs and gs aren't used by the kernel, so they still have their user-space values. */ case PREFIX_FS_-1: - /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register + /* The extra variable is needed here to get gcc to use a 16 bit register in the assembler statement. */ - __asm__("mov %%fs,%0":"=r" ((unsigned short)addr->selector)); + __asm__("mov %%fs,%0":"=r" (selector)); + addr->selector = selector; break; case PREFIX_GS_-1: - /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register + /* The extra variable is needed here to get gcc to use a 16 bit register in the assembler statement. */ - __asm__("mov %%gs,%0":"=r" ((unsigned short)addr->selector)); + __asm__("mov %%gs,%0":"=r" (selector)); + addr->selector = selector; break; default: addr->selector = PM_REG_(segment); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/math-emu/poly_tan.c linux/arch/i386/math-emu/poly_tan.c --- v2.2.17/arch/i386/math-emu/poly_tan.c Fri Apr 21 12:45:46 2000 +++ linux/arch/i386/math-emu/poly_tan.c Mon Sep 11 17:41:24 2000 @@ -89,7 +89,7 @@ { FPU_settag0(TAG_Valid); significand(st0_ptr) = 0x8a51e04daabda360LL; - setexponent16(st0_ptr, 0x41 + EXTENDED_Ebias | SIGN_Negative); + setexponent16(st0_ptr, (0x41 + EXTENDED_Ebias) | SIGN_Negative); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.2.17/arch/i386/mm/init.c Fri Apr 21 12:45:46 2000 +++ linux/arch/i386/mm/init.c Mon Sep 11 17:41:24 2000 @@ -384,7 +384,7 @@ printk(".\n"); } -extern unsigned long i386_endbase __initdata; +extern unsigned long i386_endbase; __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c --- v2.2.17/arch/i386/mm/ioremap.c Fri Apr 21 12:45:46 2000 +++ linux/arch/i386/mm/ioremap.c Thu Dec 7 15:03:54 2000 @@ -110,7 +110,18 @@ * Don't allow anybody to remap normal RAM that we're using.. */ if (phys_addr < virt_to_phys(high_memory)) - return NULL; + { + char *temp_addr, *temp_end; + int i; + + temp_addr = __va(phys_addr); + temp_end = temp_addr + (size - 1); + + for(i = MAP_NR(temp_addr); i <= MAP_NR(temp_end); i++) { + if(!PageReserved(mem_map + i)) + return NULL; + } + } /* * Mappings have to be page-aligned diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/i386/vmlinux.lds.S linux/arch/i386/vmlinux.lds.S --- v2.2.17/arch/i386/vmlinux.lds.S Fri Apr 21 12:45:46 2000 +++ linux/arch/i386/vmlinux.lds.S Tue Sep 5 22:20:06 2000 @@ -42,8 +42,16 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; + . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/Makefile linux/arch/m68k/Makefile --- v2.2.17/arch/m68k/Makefile Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/Makefile Fri Oct 13 23:30:47 2000 @@ -116,6 +116,11 @@ SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060 endif +ifdef CONFIG_FPU_EMU +CORE_FILES := $(CORE_FILES) arch/m68k/math-emu/mathemu.o +SUBDIRS := $(SUBDIRS) arch/m68k/math-emu +endif + lilo: vmlinux if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi @@ -127,13 +132,26 @@ vmlinux.gz: vmlinux -ifdef CONFIG_KGDB +ifndef CONFIG_KGDB cp vmlinux vmlinux.tmp $(STRIP) vmlinux.tmp gzip -9c vmlinux.tmp >vmlinux.gz rm vmlinux.tmp else gzip -9c vmlinux >vmlinux.gz +endif + +bzImage: vmlinux.bz2 + +vmlinux.bz2: vmlinux + +ifndef CONFIG_KGDB + cp vmlinux vmlinux.tmp + $(STRIP) vmlinux.tmp + bzip2 -1c vmlinux.tmp >vmlinux.bz2 + rm vmlinux.tmp +else + bzip2 -1c vmlinux >vmlinux.bz2 endif archclean: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c --- v2.2.17/arch/m68k/bvme6000/config.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/bvme6000/config.c Fri Oct 13 23:30:47 2000 @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,15 @@ static void (*tick_handler)(int, void *, struct pt_regs *); + +int bvme6000_parse_bootinfo(const struct bi_record *bi) +{ + if (bi->tag == BI_VME_TYPE) + return 0; + else + return 1; +} + int bvme6000_kbdrate (struct kbd_repeat *k) { return 0; @@ -164,7 +174,7 @@ unsigned long *old = (unsigned long *)0xf8000000; /* Wait for button release */ - while (*config_reg_ptr & BVME_ABORT_STATUS) + while (*(volatile unsigned char *)BVME_LOCAL_IRQ_STAT & BVME_ABORT_STATUS) ; *(new+4) = *(old+4); /* Illegal instruction */ @@ -405,15 +415,6 @@ /*------------------- Serial console stuff ------------------------*/ -static void bvme_scc_write(struct console *co, const char *str, unsigned cnt); - - -void bvme6000_init_console_port (struct console *co, int cflag) -{ - co->write = bvme_scc_write; -} - - static void scc_delay (void) { int n; @@ -423,6 +424,7 @@ trash = n; } + static void scc_write (char ch) { volatile char *p = (volatile char *)BVME_SCC_A_ADDR; @@ -431,10 +433,7 @@ scc_delay(); } while (!(*p & 4)); - scc_delay(); - *p = 8; - scc_delay(); - *p = ch; + *(p + 4) = ch; } @@ -452,5 +451,24 @@ scc_write (*str++); } restore_flags(flags); +} + + +static int bvme_scc_wait_key (struct console *co) +{ + volatile unsigned char *p = (volatile char *)BVME_SCC_A_ADDR; + + /* wait for rx buf filled */ + while ((*p & 0x01) == 0) + ; + + return *(p + 4); +} + + +void bvme6000_init_console_port (struct console *co, int cflag) +{ + co->write = bvme_scc_write; + co->wait_key = bvme_scc_wait_key; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/config.in linux/arch/m68k/config.in --- v2.2.17/arch/m68k/config.in Sun Jun 11 21:44:09 2000 +++ linux/arch/m68k/config.in Fri Oct 13 23:30:47 2000 @@ -58,6 +58,13 @@ bool '68030 support' CONFIG_M68030 bool '68040 support' CONFIG_M68040 bool '68060 support' CONFIG_M68060 +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Math emulation support' CONFIG_FPU_EMU + if [ "$CONFIG_FPU_EMU" = "y" ]; then + bool 'Math emulation extra precision' CONFIG_FPU_EMU_EXTRAPREC + bool 'Math emulation only kernel' CONFIG_FPU_EMU_ONLY + fi +fi bool 'Advanced configuration options' CONFIG_ADVANCED if [ "$CONFIG_ADVANCED" = "y" ]; then bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS @@ -115,7 +122,7 @@ fi fi fi - if [ "$CONFIG_ATARI" == "y" ]; then + if [ "$CONFIG_ATARI" = "y" ]; then dep_tristate ' Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT fi fi @@ -190,8 +197,8 @@ fi fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI - dep_tristate 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI + tristate 'Macintosh NCR5380 SCSI' CONFIG_MAC_SCSI + dep_tristate 'Macintosh NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI @@ -251,9 +258,15 @@ tristate 'Apollo 3c505 support' CONFIG_APOLLO_ELPLUS fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT -# bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE - bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC + tristate 'Macintosh NS 8390 based ethernet cards (new driver)' CONFIG_MAC8390 + if [ "$CONFIG_MAC8390" = "n" ]; then + bool 'Macintosh NS 8390 based ethernet cards (old driver)' CONFIG_DAYNAPORT + fi + tristate 'Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)' CONFIG_MACSONIC + tristate 'Macintosh SMC 9194 based ethernet cards' CONFIG_SMC9194 + tristate 'Macintosh CS89x0 based ethernet cards' CONFIG_MAC89x0 + bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE + fi if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET @@ -336,7 +349,7 @@ tristate 'Atari mouse support' CONFIG_ATARIMOUSE fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac ADB mouse support' CONFIG_ADBMOUSE + bool 'Macintosh ADB mouse support' CONFIG_ADBMOUSE fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER @@ -361,10 +374,13 @@ dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'HyperCom1 serial support (EXPERIMENTAL)' CONFIG_HYPERCOM1 + fi fi fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac SCC serial support' CONFIG_MAC_SCC + bool 'Macintosh SCC serial support' CONFIG_MAC_SCC fi if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then tristate 'HP DCA serial support' CONFIG_HPDCA diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/fpsp040/bindec.S linux/arch/m68k/fpsp040/bindec.S --- v2.2.17/arch/m68k/fpsp040/bindec.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/fpsp040/bindec.S Fri Oct 13 23:30:47 2000 @@ -484,7 +484,7 @@ fmovex (%a0),%fp0 |load X from memory fabsx %fp0 |use abs(X) tstw %d5 |LAMBDA is in lower word of d5 - bnes sc_mul |if neg (LAMBDA = 1), scale by mul + jne sc_mul |if neg (LAMBDA = 1), scale by mul fdivx %fp1,%fp0 |calculate X / SCALE -> Y to fp0 bras A10_st |branch to A10 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/fpsp040/decbin.S linux/arch/m68k/fpsp040/decbin.S --- v2.2.17/arch/m68k/fpsp040/decbin.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/fpsp040/decbin.S Fri Oct 13 23:30:47 2000 @@ -230,7 +230,7 @@ | m_sign: btst #31,(%a0) |test sign of the mantissa - beqs ap_st_z |if clear, go to append/strip zeros + jeq ap_st_z |if clear, go to append/strip zeros fnegx %fp0 |if set, negate fp0 | @@ -288,7 +288,7 @@ cmpl #27,%d1 |test is with 27 ble pwrten |if abs(expA) <28, skip ap/st zeros btst #30,(%a0) |check sign of exp - bnes ap_st_n |if neg, go to neg side + jne ap_st_n |if neg, go to neg side clrl %d1 |zero count reg movel (%a0),%d4 |load lword 1 to d4 bfextu %d4{#28:#4},%d0 |get M16 in d0 @@ -336,7 +336,7 @@ tstl %d0 |check if d0 is zero bnes ap_p_el |if not, get next bit fmulx %fp1,%fp0 |mul mantissa by 10**(no_bits_shifted) - bras pwrten |go calc pwrten + jra pwrten |go calc pwrten | | This section handles a negative adjusted exponent. | diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/fpsp040/do_func.S linux/arch/m68k/fpsp040/do_func.S --- v2.2.17/arch/m68k/fpsp040/do_func.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/fpsp040/do_func.S Fri Oct 13 23:30:47 2000 @@ -77,7 +77,7 @@ movew CMDREG1B(%a6),%d0 andl #0x7F,%d0 cmpil #0x38,%d0 |if the extension is >= $38, - bges serror |it is illegal + jge serror |it is illegal bfextu STAG(%a6){#0:#3},%d1 lsll #3,%d0 |make room for STAG addl %d1,%d0 |combine for final index into table diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/fpsp040/get_op.S linux/arch/m68k/fpsp040/get_op.S --- v2.2.17/arch/m68k/fpsp040/get_op.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/fpsp040/get_op.S Fri Oct 13 23:30:47 2000 @@ -171,7 +171,7 @@ get_op: clrb DY_MO_FLG(%a6) tstb UFLG_TMP(%a6) |test flag for unsupp/unimp state - beqs uni_getop + jeq uni_getop uns_getop: btstb #direction_bit,CMDREG1B(%a6) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S --- v2.2.17/arch/m68k/fpsp040/skeleton.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/fpsp040/skeleton.S Fri Oct 13 23:30:47 2000 @@ -107,7 +107,7 @@ bnes not_fmt40 fmovel %fpsr,-(%sp) btstb #E1,E_BYTE(%a6) |test for E1 set - beqs not_b1232 + beq not_b1232 btstb #snan_bit,2(%sp) |test for snan beq inex_ckofl addl #4,%sp diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/fpsp040/util.S linux/arch/m68k/fpsp040/util.S --- v2.2.17/arch/m68k/fpsp040/util.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/fpsp040/util.S Fri Oct 13 23:30:47 2000 @@ -138,20 +138,20 @@ | ovf_fsgl: clrl %d0 - bras ovf_res + jra ovf_res ovff_sgl: movel #0x00000001,%d0 |set single - bras ovf_res + jra ovf_res ovff_dbl: movel #0x00000002,%d0 |set double - bras ovf_res + jra ovf_res | | The precision is in the fpcr. | ovf_fpcr: bfextu FPCR_MODE(%a6){#0:#2},%d0 |set round precision - bras ovf_res + jra ovf_res | | diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/fpsp040/x_store.S linux/arch/m68k/fpsp040/x_store.S --- v2.2.17/arch/m68k/fpsp040/x_store.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/fpsp040/x_store.S Fri Oct 13 23:30:47 2000 @@ -92,7 +92,7 @@ cmpil #0,%d0 |if dest format is extended beq dest_ext |then branch cmpil #1,%d0 |if dest format is single - beqs dest_sgl |then branch + jeq dest_sgl |then branch | | fall through to dest_dbl | diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.2.17/arch/m68k/kernel/entry.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/entry.S Fri Oct 13 23:30:47 2000 @@ -90,8 +90,18 @@ jbsr SYMBOL_NAME(syscall_trace) SYMBOL_NAME_LABEL(ret_from_signal) - RESTORE_SWITCH_STACK + RESTORE_SWITCH_STACK + addql #4,%sp +/* on 68040 complete pending writebacks if any */ +#ifdef CONFIG_M68040 + bfextu %sp@(PT_VECTOR){#0,#4},%d0 + subql #7,%d0 | bus error frame ? + jbne 1f + movel %sp,%sp@- + jbsr SYMBOL_NAME(berr_040cleanup) addql #4,%sp +1: +#endif jra SYMBOL_NAME(ret_from_exception) ENTRY(system_call) @@ -283,6 +293,11 @@ movel %sp,%a0@(TASK_TSS+TSS_KSP) /* save floating point context */ +#ifndef CONFIG_FPU_EMU_ONLY +#ifdef CONFIG_FPU_EMU + tstl SYMBOL_NAME(m68k_fputype) + jeq 3f +#endif fsave %a0@(TASK_TSS+TSS_FPSTATE) #if defined(CONFIG_M68060) @@ -304,6 +319,7 @@ 2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG) fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL) 3: +#endif /* CONFIG_FPU_EMU_ONLY */ /* Return previous task in %d1 */ movel %curptr,%d1 @@ -374,7 +390,11 @@ 2: 4: /* restore floating point context */ - +#ifndef CONFIG_FPU_EMU_ONLY +#ifdef CONFIG_FPU_EMU + tstl SYMBOL_NAME(m68k_fputype) + jeq 4f +#endif #if defined(CONFIG_M68060) #if !defined(CPU_M68060_ONLY) btst #3,SYMBOL_NAME(m68k_cputype)+3 @@ -394,6 +414,8 @@ 2: fmovemx %a1@(TASK_TSS+TSS_FPREG),%fp0-%fp7 fmoveml %a1@(TASK_TSS+TSS_FPCNTL),%fpcr/%fpsr/%fpiar 3: frestore %a1@(TASK_TSS+TSS_FPSTATE) +4: +#endif /* CONFIG_FPU_EMU_ONLY */ /* restore the kernel stack pointer */ movel %a1@(TASK_TSS+TSS_KSP),%sp diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S --- v2.2.17/arch/m68k/kernel/head.S Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/head.S Fri Oct 13 23:30:47 2000 @@ -130,7 +130,7 @@ * * mmu_engage * ---------- - * Thanks to a small helping routine enabling the mmu got quiet simple + * Thanks to a small helping routine enabling the mmu got quite simple * and there is only one way left. mmu_engage makes a complete a new mapping * that only includes the absolute necessary to be able to jump to the final * postion and to restore the original mapping. @@ -271,6 +271,7 @@ */ #define CONSOLE +#define CONSOLE_PENGUIN /* * Macintosh serial debug support; outputs boot info to the printer @@ -305,7 +306,7 @@ .globl SYMBOL_NAME(m68k_pgtable_cachemode) .globl SYMBOL_NAME(m68k_supervisor_cachemode) #ifdef CONFIG_MVME16x -.globl SYMBOL_NAME(mvme_bdid_ptr) +.globl SYMBOL_NAME(mvme_bdid) #endif #ifdef CONFIG_Q40 .globl SYMBOL_NAME(q40_mem_cptr) @@ -386,6 +387,17 @@ #endif #endif +/* A macro to make relocating pointers read from memory structures easier. + * Remember, we're not necessarily running where the linker thinks we are, + * yet, so pointers given by the linker must be manually relocated to be + * valid. [CSA 13-May-1999] + */ +.macro load_and_relocate reference,dest +0: lea %pc@(0b),\dest + subl #0b,\dest + addl \reference,\dest +.endm + /* Several macros to make the writing of subroutines easier: * - func_start marks the beginning of the routine which setups the frame * register and saves the registers, it also defines another macro @@ -472,6 +484,12 @@ func_define serial_putc,1 func_define console_putc,1 +func_define console_init +func_define console_put_stats +func_define console_put_penguin +func_define console_plot_pixel,3 +func_define console_scroll + .macro putc ch #if defined(CONSOLE) || defined(SERIAL_DEBUG) pea \ch @@ -503,10 +521,18 @@ .macro puts string #if defined(CONSOLE) || defined(SERIAL_DEBUG) +/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */ +#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB) + bra 1f +#endif __INITDATA .Lstr\@: .string "\string" __FINIT +#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB) + .align 2 +1: +#endif pea %pc@(.Lstr\@) func_call puts addql #4,%sp @@ -525,6 +551,9 @@ #define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab #define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab #define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab +#define is_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jeq lab +#define is_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jeq lab +#define is_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jeq lab #define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab #define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab #define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab @@ -801,6 +830,57 @@ L(notypetest): #endif +#ifdef CONFIG_VME + is_mvme147(L(getvmetype)) + is_bvme6000(L(getvmetype)) + is_not_mvme16x(L(gvtdone)) + + /* See if the loader has specified the BI_VME_TYPE tag. Recent + * versions of VMELILO and TFTPLILO do this. We have to do this + * early so we know how to handle console output. If the tag + * doesn't exist then we use the Bug for output on MVME16x. + */ +L(getvmetype): + get_bi_record BI_VME_TYPE + tstl %d0 + jbmi 1f + movel %a0@,%d3 + lea %pc@(SYMBOL_NAME(vme_brdtype)),%a0 + movel %d3,%a0@ +1: +#ifdef CONFIG_MVME16x + is_not_mvme16x(L(gvtdone)) + + /* Need to get the BRD_ID info to diferentiate between 162, 167, + * etc. This is available as a BI_VME_BRDINFO tag with later + * versions of VMELILO and TFTPLILO, otherwise we call the Bug. + */ + get_bi_record BI_VME_BRDINFO + tstl %d0 + jpl 1f + + /* Get pointer to board ID data from Bug */ + movel %d2,%sp@- + trap #15 + .word 0x70 /* trap 0x70 - .BRD_ID */ + movel %sp@+,%a0 +1: + lea %pc@(SYMBOL_NAME(mvme_bdid)),%a1 + /* Structure is 32 bytes long */ + movel %a0@+,%a1@+ + movel %a0@+,%a1@+ + movel %a0@+,%a1@+ + movel %a0@+,%a1@+ + movel %a0@+,%a1@+ + movel %a0@+,%a1@+ + movel %a0@+,%a1@+ + movel %a0@+,%a1@+ +#endif + +L(gvtdone): + +#endif + /* * Initialize serial port */ @@ -812,11 +892,11 @@ #ifdef CONFIG_MAC is_not_mac(L(nocon)) #ifdef CONSOLE - jbsr L(console_init) + console_init #ifdef CONSOLE_PENGUIN - jbsr L(console_put_penguin) + console_put_penguin #endif /* CONSOLE_PENGUIN */ - jbsr L(console_put_stats) + console_put_stats #endif /* CONSOLE */ L(nocon): #endif /* CONFIG_MAC */ @@ -998,14 +1078,6 @@ is_not_mvme16x(L(not16x)) - /* Get pointer to board ID data */ - movel %d2,%sp@- - trap #15 - .word 0x70 /* trap 0x70 - .BRD_ID */ - movel %sp@+,%d2 - lea %pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0 - movel %d2,%a0@ - /* * On MVME16x we have already created kernel page tables for * 4MB of RAM at address 0, so now need to do a transparent @@ -1082,10 +1154,6 @@ putc 'F' - lea %pc@(L(mac_videobase)),%a0 - lea %pc@(L(console_video_virtual)),%a1 - movel %a0@,%a1@ - is_not_040_or_060(1f) moveq #_PAGE_NOCACHE_S,%d3 @@ -1099,15 +1167,16 @@ */ movel #VIDEOMEMMASK,%d0 - andl L(mac_videobase),%d0 + andl %pc@(L(mac_videobase)),%d0 mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3 - mmu_map_eq #0x40800000,#0x02000000,%d3 /* rom ? */ - mmu_map_eq #0x50000000,#0x02000000,%d3 - mmu_map_eq #0x60000000,#0x00400000,%d3 - mmu_map_eq #0x9c000000,#0x00400000,%d3 + /* IO devices (incl. serial port) from 5000 0000 to 5300 0000 */ + mmu_map_eq #0x50000000,#0x03000000,%d3 + /* Nubus slot space (video at 0xF0000000, rom at 0xF0F80000) */ mmu_map_tt #1,#0xf8000000,#0x08000000,%d3 - + /* ROM from 4000 0000 to 4200 0000 */ + mmu_map_eq #0x40000000,#0x02000000,%d3 /* only for mac_reset() */ + jbra L(mmu_init_done) L(mmu_init_not_mac): @@ -1261,6 +1330,9 @@ andl L(mac_videobase),%d0 addl #VIDEOMEMBASE,%d0 movel %d0,L(mac_videobase) +#ifdef MAC_SERIAL_DEBUG + orl #0x50000000,L(mac_sccbase) +#endif 1: #endif @@ -1661,7 +1733,7 @@ putZc('C','I') /* write through or copy-back */ rts -mmu_030_print: +mmu_030_print: /* print a 3-level (max) translation tree using 3 nested loops*/ puts "\nMMU030\n" puts "\nrp:" putn %a5 @@ -1670,62 +1742,66 @@ andil #0xfffffff0,%d0 movel %d0,%a0 movel #0x00000000,%a4 /* logical address */ - movel #0,%d0 + movel #0,%d0 /* iteration counter for outer loop */ 30: movel %a4,%d5 - addil #PAGESIZE<<13,%d5 + addil #PAGESIZE<<13,%d5 /* next logical address */ movel %a0@+,%d6 - btst #1,%d6 /* is it a ptr? */ - jbne 31f /* yes */ + btst #1,%d6 /* is it a table ptr? */ + jbne 31f /* if yes, jump */ btst #0,%d6 /* is it early terminating? */ - jbeq 1f /* no */ - jbsr mmu_030_print_helper + jbeq 1f /* if no, jump */ + /* DT (descriptor tag) = $01 (PAGE DESCRIPTOR) (early termination) */ + jbsr mmu_030_print_helper /* print " %a4-> %d6"+flags(%d6) */ jbra 38f -1: - jbsr mmu_print_tuple_invalidate +1: /* DT (descriptor tag) = $00 (INVALID) */ + jbsr mmu_print_tuple_invalidate /* prints " %a4##" */ jbra 38f -31: - movel #0,%d1 +31: /* DT (descriptor tag) = $1x (table pointer with 4 or 8 byte entries)*/ + movel #0,%d1 /* iteration counter for middle loop */ andil #0xfffffff0,%d6 movel %d6,%a1 32: movel %a4,%d5 addil #PAGESIZE<<6,%d5 movel %a1@+,%d6 - btst #1,%d6 - jbne 33f - btst #0,%d6 - jbeq 1f /* no */ - jbsr mmu_030_print_helper + btst #1,%d6 /* is it a table ptr? */ + jbne 33f /* if so, jump */ + btst #0,%d6 /* is it a page descriptor? */ + jbeq 1f /* if no, jump */ + /* DT (descriptor tag) = $01 (PAGE DESCRIPTOR) */ + jbsr mmu_030_print_helper /* prints " %a4-> %d6"+flags(%d6) */ jbra 37f -1: - jbsr mmu_print_tuple_invalidate +1: /* DT (descriptor tag) = $00 (INVALID) */ + jbsr mmu_print_tuple_invalidate /* prints " %a4##" */ jbra 37f -33: - movel #0,%d2 +33: /* DT (descriptor tag) = $1x (table pointer with 4 or 8 byte entries)*/ + movel #0,%d2 /* iteration counter for inner loop */ andil #0xfffffff0,%d6 movel %d6,%a2 34: movel %a4,%d5 addil #PAGESIZE,%d5 movel %a2@+,%d6 + /* note that we assume there are no more table indirections left */ btst #0,%d6 jbne 35f - jbsr mmu_print_tuple_invalidate + /* DT (descriptor tag) = $00 (INVALID) */ + jbsr mmu_print_tuple_invalidate /* prints " %a4##" */ jbra 36f -35: - jbsr mmu_030_print_helper -36: +35: /* DT (descriptor tag) = $01 (PAGE DESCRIPTOR) */ + jbsr mmu_030_print_helper /* prints " %a4-> %d6"+flags(%d6) */ +36: /* continue inner loop */ movel %d5,%a4 addq #1,%d2 cmpib #64,%d2 jbne 34b -37: - movel %d5,%a4 +37: /* continue middle loop */ + movel %d5,%a4 /* move to the next logical address */ addq #1,%d1 cmpib #128,%d1 jbne 32b -38: +38: /* continue outer loop */ movel %d5,%a4 /* move to the next logical address */ addq #1,%d0 cmpib #128,%d0 @@ -1746,6 +1822,13 @@ moveml %sp@+,%d0-%d1 rts +/* mmu_print_tuple_invalidate(%a4=this_logical) { + * if (mmu_print_data.mmu_next_valid != INVALID) { + * mmu_print_data.mmu_next_valid = INVALID; + * printf(" %08x##\n", this_logical); + * } + * } [rough C translation by CSA, not the original author] + */ mmu_print_tuple_invalidate: moveml %a0/%d7,%sp@- @@ -1764,6 +1847,19 @@ rts +/* mmu_print_tuple(%d0=logical,%d1=physical, + * %d5=next_logical,%a4=this_logical, + * %a6=print_flags) { + * if (mmu_print_data.mmu_next_valid != VALID || + * mmu_print_data.mmu_next_physical != physical) { + * printf(" %08x-> %08x", logical, physical); + * print_flags(physical); + * mmu_print_data.mmu_next_valid = VALID; + * mmu_print_data.mmu_next_physical=physical; + * } + * mmu_print_data.mmu_next_physical += (next_logical-this_logical); + * } [rough C translation by CSA, not the original author] + */ mmu_print_tuple: moveml %d0-%d7/%a0,%sp@- @@ -2168,7 +2264,7 @@ func_return mmu_fixup_page_mmu_cache /* - * mmu_temp_map + * mmu_temp_map (ARG1=physical_addr, ARG2=logical_addr) * * create a temporary mapping to enable the mmu, * this we don't need any transparation translation tricks. @@ -2834,10 +2930,6 @@ #ifdef CONFIG_MAC is_not_mac(5f) -#ifdef CONSOLE - console_putc %d0 -#endif /* CONSOLE */ - #ifdef MAC_SERIAL_DEBUG #ifdef MAC_USE_SCC_A @@ -2903,13 +2995,54 @@ #ifdef CONFIG_MVME16x is_not_mvme16x(2f) /* - * The VME 16x class has PROM support for serial output - * of some kind; the TRAP table is still valid. + * If the loader gave us a board type then we can use that to + * select an appropriate output routine; otherwise we just use + * the Bug code. If we haev to use the Bug that means the Bug + * workspace has to be valid, which means the Bug has to use + * the SRAM, which is non-standard. */ moveml %d0-%d7/%a2-%a6,%sp@- + movel SYMBOL_NAME(vme_brdtype),%d1 + jeq 1f | No tag - use the Bug + cmpi #VME_TYPE_MVME162,%d1 + jeq 6f + cmpi #VME_TYPE_MVME172,%d1 + jne 5f + /* 162/172; it's an SCC */ +6: btst #2,M162_SCC_CTRL_A + nop + nop + nop + jeq 6b + moveb #8,M162_SCC_CTRL_A + nop + nop + nop + moveb %d0,M162_SCC_CTRL_A + jra 3f +5: + /* 166/167/177; its a CD2401 */ + moveb #0,M167_CYCAR + moveb M167_CYIER,%d2 + moveb #0x02,M167_CYIER +7: + btst #5,M167_PCSCCTICR + jeq 7b + moveb M167_PCTPIACKR,%d1 + moveb M167_CYLICR,%d1 + jeq 8f + moveb #0x08,M167_CYTEOIR + jra 7b +8: + moveb %d0,M167_CYTDR + moveb #0,M167_CYTEOIR + moveb %d2,M167_CYIER + jra 3f +1: moveb %d0,%sp@- trap #15 .word 0x0020 /* TRAP 0x020 */ +3: moveml %sp@+,%d0-%d7/%a2-%a6 jbra L(serial_putc_done) 2: @@ -3004,20 +3137,18 @@ * simple strings! */ ENTRY(mac_serial_print) +#ifdef MAC_SERIAL_DEBUG moveml %d0/%a0,%sp@- -#if 1 move %sr,%sp@- ori #0x0700,%sr -#endif - movel %sp@(10),%a0 /* fetch parameter */ + movel %sp@(14),%a0 /* fetch parameter */ jra 2f 1: serial_putc %d0 2: moveb %a0@+,%d0 jne 1b -#if 1 move %sp@+,%sr -#endif moveml %sp@+,%d0/%a0 +#endif /* MAC_SERIAL_DEBUG */ rts #endif /* CONFIG_MAC */ @@ -3041,7 +3172,7 @@ #define Lconsole_struct_left_edge 16 #define Lconsole_struct_penguin_putc 20 -L(console_init): +func_start console_init,%a0-%a4/%d0-%d7 /* * Some of the register usage that follows * a0 = pointer to boot_info @@ -3055,49 +3186,57 @@ * d5 = number of bytes per scan line * d6 = number of bytes on the entire screen */ - moveml %a0-%a4/%d0-%d7,%sp@- lea %pc@(L(console_globals)),%a2 - lea %pc@(L(mac_videobase)),%a0 - movel %a0@,%a1 - lea %pc@(L(mac_rowbytes)),%a0 - movel %a0@,%d5 - lea %pc@(L(mac_dimensions)),%a0 - movel %a0@,%d3 /* -> low byte */ + movel %pc@(L(mac_videobase)),%a1 + movel %pc@(L(mac_rowbytes)),%d5 + movel %pc@(L(mac_dimensions)),%d3 /* -> low word */ movel %d3,%d4 - swap %d4 /* -> high byte */ - andl #0xffff,%d3 /* d3 = screen width in pixels */ - andl #0xffff,%d4 /* d4 = screen height in pixels */ + swap %d4 /* -> high word */ + andl #0xffff,%d3 /* d3 = screen width in pixels */ + andl #0xffff,%d4 /* d4 = screen height in pixels */ movel %d5,%d6 - subl #20,%d6 - mulul %d4,%d6 /* scan line bytes x num scan lines */ - divul #8,%d6 /* we'll clear 8 bytes at a time */ +| subl #20,%d6 + mulul %d4,%d6 /* scan line bytes x num scan lines */ + lsrl #3,%d6 /* we'll clear 8 bytes at a time */ + moveq #-1,%d0 /* Mac_black */ subq #1,%d6 -console_clear_loop: - movel #0xffffffff,%a1@+ /* Mac_black */ - movel #0xffffffff,%a1@+ /* Mac_black */ - dbra %d6,console_clear_loop +L(console_clear_loop): + movel %d0,%a1@+ + movel %d0,%a1@+ + dbra %d6,L(console_clear_loop) /* Calculate font size */ - + /* Use absolute (not pc-relative) pointer here; which means we'll + * have to do relocation every time before we use it. + * (remember, before mmu_engage we're probably not running where + * the linker expected that we'd end up.) We could store + * %pc@(SYMBOL_NAME(font_xxx)) in memory instead, but if + * everyone did this we'd end up with quite a motley collection of + * fixup code after mmu_engage, which offends our spirit of + * disentangledness (code for similar things together, code for + * unrelated things apart). + */ + #if defined(FONT_8x8) - lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0 + lea SYMBOL_NAME(font_vga_8x8), %a0 #elif defined(FONT_8x16) - lea %pc@(SYMBOL_NAME(font_vga_8x16)),%a0 + lea SYMBOL_NAME(font_vga_8x16),%a0 #elif defined(FONT_6x11) - lea %pc@(SYMBOL_NAME(font_vga_6x11)),%a0 + lea SYMBOL_NAME(font_vga_6x11),%a0 #else /* (FONT_8x8) default */ - lea %pc@(SYMBOL_NAME(font_vga_8x8)), %a0 + lea SYMBOL_NAME(font_vga_8x8), %a0 #endif /* * At this point we make a shift in register usage - * a1 = address of Lconsole_font pointer + * a1 = address of console_font pointer */ lea %pc@(L(console_font)),%a1 - movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in Lconsole_font */ + movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in console_font */ + load_and_relocate %a1@,%a0 /* now relocate the pointer. */ /* * Calculate global maxs @@ -3106,11 +3245,11 @@ * 6 x 11 also supported */ /* ASSERT: a0 = contents of Lconsole_font */ - movel %d3,%d0 /* screen width in pixels */ - divul %a0@(FBCON_FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ + movel %d3,%d0 /* screen width in pixels */ + divul %a0@(FBCON_FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ - movel %d4,%d1 /* screen height in pixels */ - divul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ + movel %d4,%d1 /* screen height in pixels */ + divul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ movel %d0,%a2@(Lconsole_struct_num_columns) movel %d1,%a2@(Lconsole_struct_num_rows) @@ -3125,16 +3264,14 @@ /* * Initialization is complete */ - moveml %sp@+,%a0-%a4/%d0-%d7 - rts +func_return console_init -L(console_put_stats): +func_start console_put_stats,%a0/%d7 /* * Some of the register usage that follows * a0 = pointer to boot_info * d7 = value of boot_info fields */ - moveml %a0/%d7,%sp@- puts "\nMacLinux\n\n" @@ -3154,21 +3291,28 @@ putn %pc@(L(cputype)) putc '\n' + putn %pc@(L(mac_videodepth)) + putn %pc@(L(mac_dimensions)) + putn %pc@(L(mac_rowbytes)) + putn %pc@(L(mac_videodepth)) +#ifdef MAC_SERIAL_DEBUG + putn %pc@(L(mac_sccbase)) +#endif + putc '\n' + # if defined(MMU_PRINT) jbsr mmu_print_machine_cpu_types # endif /* MMU_PRINT */ #endif /* SERIAL_DEBUG */ - moveml %sp@+,%a0/%d7 - rts +func_return console_put_stats #ifdef CONSOLE_PENGUIN -L(console_put_penguin): +func_start console_put_penguin,%a0-%a1/%d0-%d7 /* * Get 'that_penguin' onto the screen in the upper right corner * penguin is 64 x 74 pixels, align against right edge of screen */ - moveml %a0-%a1/%d0-%d7,%sp@- lea %pc@(L(mac_dimensions)),%a0 movel %a0@,%d0 @@ -3177,40 +3321,42 @@ clrl %d1 /* start at the top */ movel #73,%d7 lea %pc@(SYMBOL_NAME(that_penguin)),%a1 -console_penguin_row: +L(console_penguin_row): movel #31,%d6 -console_penguin_pixel_pair: +L(console_penguin_pixel_pair): moveb %a1@,%d2 lsrb #4,%d2 - jbsr console_plot_pixel + console_plot_pixel %d0,%d1,%d2 addq #1,%d0 moveb %a1@+,%d2 - jbsr console_plot_pixel + console_plot_pixel %d0,%d1,%d2 addq #1,%d0 - dbra %d6,console_penguin_pixel_pair + dbra %d6,L(console_penguin_pixel_pair) subil #64,%d0 addq #1,%d1 - dbra %d7,console_penguin_row + dbra %d7,L(console_penguin_row) - moveml %sp@+,%a0-%a1/%d0-%d7 - rts -#endif +func_return console_put_penguin -console_scroll: - moveml %a0-%a4/%d0-%d7,%sp@- +/* include penguin bitmap */ +SYMBOL_NAME_LABEL(that_penguin) +#include "../mac/mac_penguin.S" +#endif /* * Calculate source and destination addresses * output a1 = dest * a2 = source */ + +func_start console_scroll,%a0-%a4/%d0-%d7 lea %pc@(L(mac_videobase)),%a0 movel %a0@,%a1 movel %a1,%a2 lea %pc@(L(mac_rowbytes)),%a0 movel %a0@,%d5 - movel %pc@(L(console_font)),%a0 + load_and_relocate %pc@(L(console_font)),%a0 mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */ addal %d5,%a2 @@ -3229,13 +3375,13 @@ */ lea %pc@(L(mac_rowbytes)),%a0 movel %a0@,%d6 - movel %pc@(L(console_font)),%a0 + load_and_relocate %pc@(L(console_font)),%a0 subl %a0@(FBCON_FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */ mulul %d4,%d6 /* scan line bytes x num scan lines */ divul #32,%d6 /* we'll move 8 longs at a time */ subq #1,%d6 -console_scroll_loop: +L(console_scroll_loop): movel %a2@+,%a1@+ movel %a2@+,%a1@+ movel %a2@+,%a1@+ @@ -3244,17 +3390,17 @@ movel %a2@+,%a1@+ movel %a2@+,%a1@+ movel %a2@+,%a1@+ - dbra %d6,console_scroll_loop + dbra %d6,L(console_scroll_loop) lea %pc@(L(mac_rowbytes)),%a0 movel %a0@,%d6 - movel %pc@(L(console_font)),%a0 + load_and_relocate %pc@(L(console_font)),%a0 mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */ divul #32,%d6 /* we'll move 8 words at a time */ subq #1,%d6 moveq #-1,%d0 -console_scroll_clear_loop: +L(console_scroll_clear_loop): movel %d0,%a1@+ movel %d0,%a1@+ movel %d0,%a1@+ @@ -3263,15 +3409,13 @@ movel %d0,%a1@+ movel %d0,%a1@+ movel %d0,%a1@+ - dbra %d6,console_scroll_clear_loop - - moveml %sp@+,%a0-%a4/%d0-%d7 - rts + dbra %d6,L(console_scroll_clear_loop) +func_return console_scroll func_start console_putc,%a0/%a1/%d0-%d7 - is_not_mac(console_exit) + is_not_mac(L(console_exit)) /* Output character in d7 on console. */ @@ -3285,7 +3429,7 @@ lea %pc@(L(console_globals)),%a0 cmpib #10,%d7 - jne console_not_lf + jne L(console_not_lf) movel %a0@(Lconsole_struct_cur_row),%d0 addil #1,%d0 movel %d0,%a0@(Lconsole_struct_cur_row) @@ -3294,22 +3438,22 @@ jcs 1f subil #1,%d0 movel %d0,%a0@(Lconsole_struct_cur_row) - jbsr console_scroll + console_scroll 1: - jra console_exit + jra L(console_exit) -console_not_lf: +L(console_not_lf): cmpib #13,%d7 - jne console_not_cr + jne L(console_not_cr) clrl %a0@(Lconsole_struct_cur_column) - jra console_exit + jra L(console_exit) -console_not_cr: +L(console_not_cr): cmpib #1,%d7 - jne console_not_home + jne L(console_not_home) clrl %a0@(Lconsole_struct_cur_row) clrl %a0@(Lconsole_struct_cur_column) - jra console_exit + jra L(console_exit) /* * At this point we know that the %d7 character is going to be @@ -3320,13 +3464,13 @@ * d1 = cursor row to draw the character * d7 = character number */ -console_not_home: +L(console_not_home): movel %a0@(Lconsole_struct_cur_column),%d0 - addil #1,%a0@(Lconsole_struct_cur_column) + addql #1,%a0@(Lconsole_struct_cur_column) movel %a0@(Lconsole_struct_num_columns),%d1 cmpl %d1,%d0 jcs 1f - putc '\n' /* recursion is OK! */ + console_putc #'\n' /* recursion is OK! */ 1: movel %a0@(Lconsole_struct_cur_row),%d1 @@ -3334,8 +3478,8 @@ * At this point we make a shift in register usage * a0 = address of pointer to font data (fbcon_font_desc) */ - movel %pc@(L(console_font)),%a0 - movel %a0@(FBCON_FONT_DESC_DATA),%a1 /* Load fbcon_font_desc.data into a1 */ + load_and_relocate %pc@(L(console_font)),%a0 + load_and_relocate %a0@(FBCON_FONT_DESC_DATA),%a1 andl #0x000000ff,%d7 /* ASSERT: a0 = contents of Lconsole_font */ mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */ @@ -3350,35 +3494,34 @@ * d6 = count down for the font's pixel width (8) * d7 = count down for the font's pixel count in height */ + /* ASSERT: a0 = contents of Lconsole_font */ mulul %a0@(FBCON_FONT_DESC_WIDTH),%d0 mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 movel %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */ subq #1,%d7 -console_read_char_scanline: +L(console_read_char_scanline): moveb %a1@+,%d3 /* ASSERT: a0 = contents of Lconsole_font */ movel %a0@(FBCON_FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */ subql #1,%d6 -console_do_font_scanline: +L(console_do_font_scanline): lslb #1,%d3 scsb %d2 /* convert 1 bit into a byte */ - jbsr console_plot_pixel + console_plot_pixel %d0,%d1,%d2 addq #1,%d0 - dbra %d6,console_do_font_scanline + dbra %d6,L(console_do_font_scanline) /* ASSERT: a0 = contents of Lconsole_font */ subl %a0@(FBCON_FONT_DESC_WIDTH),%d0 addq #1,%d1 - dbra %d7,console_read_char_scanline - -console_exit: + dbra %d7,L(console_read_char_scanline) +L(console_exit): func_return console_putc -console_plot_pixel: /* * Input: * d0 = x coordinate @@ -3386,14 +3529,14 @@ * d2 = (bit 0) 1/0 for white/black (!) * All registers are preserved */ - moveml %a0-%a1/%d0-%d4,%sp@- +func_start console_plot_pixel,%a0-%a1/%d0-%d4 - lea %pc@(L(mac_videobase)),%a0 - movel %a0@,%a1 - lea %pc@(L(mac_videodepth)),%a0 - movel %a0@,%d3 - lea %pc@(L(mac_rowbytes)),%a0 - mulul %a0@,%d1 + movel %pc@(L(mac_videobase)),%a1 + movel %pc@(L(mac_videodepth)),%d3 + movel ARG1,%d0 + movel ARG2,%d1 + mulul %pc@(L(mac_rowbytes)),%d1 + movel ARG3,%d2 /* * Register usage: @@ -3402,13 +3545,10 @@ * d2 = black or white (0/1) * d3 = video depth * d4 = temp of x (d0) for many bit depths - * d5 = unused - * d6 = unused - * d7 = unused */ -test_1bit: +L(test_1bit): cmpb #1,%d3 - jbne test_2bit + jbne L(test_2bit) movel %d0,%d4 /* we need the low order 3 bits! */ divul #8,%d0 addal %d0,%a1 @@ -3416,16 +3556,16 @@ andb #7,%d4 eorb #7,%d4 /* reverse the x-coordinate w/ screen-bit # */ andb #1,%d2 - jbne white_1 + jbne L(white_1) bsetb %d4,%a1@ - jbra console_plot_pixel_exit -white_1: + jbra L(console_plot_pixel_exit) +L(white_1): bclrb %d4,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_2bit: +L(test_2bit): cmpb #2,%d3 - jbne test_4bit + jbne L(test_4bit) movel %d0,%d4 /* we need the low order 2 bits! */ divul #4,%d0 addal %d0,%a1 @@ -3434,20 +3574,20 @@ eorb #3,%d4 /* reverse the x-coordinate w/ screen-bit # */ lsll #1,%d4 /* ! */ andb #1,%d2 - jbne white_2 + jbne L(white_2) bsetb %d4,%a1@ addq #1,%d4 bsetb %d4,%a1@ - jbra console_plot_pixel_exit -white_2: + jbra L(console_plot_pixel_exit) +L(white_2): bclrb %d4,%a1@ addq #1,%d4 bclrb %d4,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_4bit: +L(test_4bit): cmpb #4,%d3 - jbne test_8bit + jbne L(test_8bit) movel %d0,%d4 /* we need the low order bit! */ divul #2,%d0 addal %d0,%a1 @@ -3456,7 +3596,7 @@ eorb #1,%d4 lsll #2,%d4 /* ! */ andb #1,%d2 - jbne white_4 + jbne L(white_4) bsetb %d4,%a1@ addq #1,%d4 bsetb %d4,%a1@ @@ -3464,8 +3604,8 @@ bsetb %d4,%a1@ addq #1,%d4 bsetb %d4,%a1@ - jbra console_plot_pixel_exit -white_4: + jbra L(console_plot_pixel_exit) +L(white_4): bclrb %d4,%a1@ addq #1,%d4 bclrb %d4,%a1@ @@ -3473,38 +3613,37 @@ bclrb %d4,%a1@ addq #1,%d4 bclrb %d4,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_8bit: +L(test_8bit): cmpb #8,%d3 - jbne test_16bit + jbne L(test_16bit) addal %d0,%a1 addal %d1,%a1 andb #1,%d2 - jbne white_8 + jbne L(white_8) moveb #0xff,%a1@ - jbra console_plot_pixel_exit -white_8: + jbra L(console_plot_pixel_exit) +L(white_8): clrb %a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -test_16bit: +L(test_16bit): cmpb #16,%d3 - jbne console_plot_pixel_exit + jbne L(console_plot_pixel_exit) addal %d0,%a1 addal %d0,%a1 addal %d1,%a1 andb #1,%d2 - jbne white_16 + jbne L(white_16) clrw %a1@ - jbra console_plot_pixel_exit -white_16: + jbra L(console_plot_pixel_exit) +L(white_16): movew #0x0fff,%a1@ - jbra console_plot_pixel_exit + jbra L(console_plot_pixel_exit) -console_plot_pixel_exit: - moveml %sp@+,%a0-%a1/%d0-%d4 - rts +L(console_plot_pixel_exit): +func_return console_plot_pixel #endif /* CONSOLE */ #if 0 @@ -3549,11 +3688,6 @@ .long 0 #endif -#ifdef CONFIG_MAC -L(console_video_virtual): - .long 0 -#endif /* CONFIG_MAC */ - #if defined(CONSOLE) L(console_globals): .long 0 /* cursor column */ @@ -3597,6 +3731,17 @@ M147_SCC_DATA_A = 0xfffe3003 #endif +#if defined (CONFIG_MVME16x) +M162_SCC_CTRL_A = 0xfff45005 +M167_CYCAR = 0xfff450ee +M167_CYIER = 0xfff45011 +M167_CYLICR = 0xfff45026 +M167_CYTEOIR = 0xfff45085 +M167_CYTDR = 0xfff450f8 +M167_PCSCCTICR = 0xfff4201e +M167_PCTPIACKR = 0xfff42025 +#endif + #if defined (CONFIG_BVME6000) BVME_SCC_CTRL_A = 0xffb0000b BVME_SCC_DATA_A = 0xffb0000f @@ -3630,8 +3775,8 @@ SYMBOL_NAME_LABEL(m68k_supervisor_cachemode) .long 0 #if defined(CONFIG_MVME16x) -SYMBOL_NAME_LABEL(mvme_bdid_ptr) - .long 0 +SYMBOL_NAME_LABEL(mvme_bdid) + .long 0,0,0,0,0,0,0,0 #endif #if defined(CONFIG_Q40) SYMBOL_NAME_LABEL(q40_mem_cptr) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/kgdb.c linux/arch/m68k/kernel/kgdb.c --- v2.2.17/arch/m68k/kernel/kgdb.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/kgdb.c Fri Oct 13 23:30:47 2000 @@ -189,6 +189,11 @@ #include #include #endif +#ifdef CONFIG_MAC +#include +#include +#include +#endif #undef DEBUG @@ -239,6 +244,15 @@ extern int amiga_ser_out( unsigned char c ); extern unsigned char amiga_ser_in( void ); #endif +#ifdef CONFIG_MAC +static unsigned char mac_scca_in( void ); +static unsigned char mac_scca_out( unsigned char c ); +static unsigned char mac_scca_intr( void ); +static unsigned char mac_sccb_in( void ); +static unsigned char mac_sccb_out( unsigned char c); +static unsigned char mac_sccb_intr( void ); +extern void mac_init_scc_port( int cflag, int port ); +#endif /************************* End of Prototypes **************************/ @@ -668,6 +682,31 @@ } #endif +#ifdef CONFIG_MAC + if (MACH_IS_MAC) { + if (!strcmp( m68k_debug_device, "ser" ) || + !strcmp( m68k_debug_device, "ser1" )) { + mac_init_scc_port( B9600|CS8, 0 ); + serial_in = mac_scca_in; + serial_out = mac_scca_out; + serial_intr = mac_scca_intr; + } else if (!strcmp( m68k_debug_device, "ser2" )) { + mac_init_scc_port( B9600|CS8, 1 ); + serial_in = mac_sccb_in; + serial_out = mac_sccb_out; + serial_intr = mac_sccb_intr; + } + } + if (!serial_in || !serial_out) { + if (*m68k_debug_device) + printk( "kgdb_init failed: no valid serial device!\n" ); + else + printk( "kgdb not enabled\n" ); + return; + } + request_irq(4, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL); +#endif + #ifdef CONFIG_ATARI if (!serial_in || !serial_out) { if (*m68k_debug_device) @@ -781,8 +820,15 @@ /* copy format/vector word */ " movew %a0@("FRAMEOFF_VECTOR"),%a1@("GDBOFF_VECTOR")\n" /* save FPU regs */ +#ifndef CONFIG_FPU_EMU_ONLY +#ifdef CONFIG_FPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n" " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n" + "1:\n" +#endif /* CONFIG_FPU_EMU_ONLY */ /* set stack to CPU frame */ " addl #"FRAMEOFF_SR",%a0\n" @@ -801,8 +847,15 @@ /* after return, first restore FPU registers */ " movel #"SYMBOL_NAME_STR(kgdb_registers)",%a0\n" /* source */ +#ifndef CONFIG_FPU_EMU_ONLY +#ifdef CONFIG_FPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %a0@("GDBOFF_FP0"),%fp0-%fp7\n" " fmoveml %a0@("GDBOFF_FPCTL"),%fpcr/%fpsr/%fpiar\n" + "1:\n" +#endif /* CONFIG_FPU_EMU_ONLY */ /* set new stack pointer */ " movel %a0@("GDBOFF_A7"),%sp\n" " clrw %sp@-\n" /* fake format $0 frame */ @@ -849,8 +902,15 @@ /* fake format 0 and vector 1 (translated to SIGINT) */ " movew #4,%a1@("GDBOFF_VECTOR")\n" /* save FPU regs */ +#ifndef CONFIG_FPU_EMU_ONLY +#ifdef CONFIG_FPU_EMU + " tstl "SYMBOL_NAME_STR(m68k_fputype)"\n" + " jeq 1f\n" +#endif " fmovemx %fp0-%fp7,%a1@("GDBOFF_FP0")\n" " fmoveml %fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n" + "1:\n" +#endif /* CONFIG_FPU_EMU_ONLY */ /* pop off the CPU stack frame */ " addql #8,%sp\n" " movel %sp,%a1@("GDBOFF_A7")\n" /* save a7 now */ @@ -1188,6 +1248,114 @@ } scc.cha_b_ctrl = 0x38; /* reset highest IUS */ MFPDELAY(); + return( c ); +} + +#endif + +/* -------------------- Macintosh serial I/O -------------------- */ + +#ifdef CONFIG_MAC + +struct SCC + { + u_char cha_b_ctrl; + u_char char_dummy1; + u_char cha_a_ctrl; + u_char char_dummy2; + u_char cha_b_data; + u_char char_dummy3; + u_char cha_a_data; + }; + +#define scc (*((volatile struct SCC*)mac_bi_data.sccbase)) + +#define uSEC 1 +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 60*uSEC; i > 0; --i ) \ + barrier(); \ + } while(0) + +static unsigned char mac_sccb_out (unsigned char c) +{ + int i; + do { + LONG_DELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_b_data = c; +} + +static unsigned char mac_scca_out (unsigned char c) +{ + int i; + do { + LONG_DELAY(); + } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ + for( i = uSEC; i > 0; --i ) + barrier(); + scc.cha_a_data = c; +} + +static unsigned char mac_sccb_in( void ) +{ + do { + LONG_DELAY(); + } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ + LONG_DELAY(); + return( scc.cha_b_data ); +} + +static unsigned char mac_scca_in( void ) + +{ + do { + LONG_DELAY(); + } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */ + LONG_DELAY(); + return( scc.cha_a_data ); +} + +static unsigned char mac_sccb_intr( void ) + +{ unsigned char c, stat; + + LONG_DELAY(); + scc.cha_b_ctrl = 1; /* RR1 */ + LONG_DELAY(); + stat = scc.cha_b_ctrl; + LONG_DELAY(); + c = scc.cha_b_data; + LONG_DELAY(); + if (stat & 0x30) { + scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */ + LONG_DELAY(); + } + scc.cha_b_ctrl = 0x38; /* reset highest IUS */ + LONG_DELAY(); + return( c ); +} + +static unsigned char mac_scca_intr( void ) + +{ unsigned char c, stat; + + LONG_DELAY(); + scc.cha_a_ctrl = 1; /* RR1 */ + LONG_DELAY(); + stat = scc.cha_a_ctrl; + LONG_DELAY(); + c = scc.cha_a_data; + LONG_DELAY(); + if (stat & 0x30) { + scc.cha_a_ctrl = 0x30; /* error reset for overrun and parity */ + LONG_DELAY(); + } + scc.cha_a_ctrl = 0x38; /* reset highest IUS */ + LONG_DELAY(); return( c ); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/m68k_defs.c linux/arch/m68k/kernel/m68k_defs.c --- v2.2.17/arch/m68k/kernel/m68k_defs.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/m68k_defs.c Fri Oct 13 23:30:47 2000 @@ -43,8 +43,16 @@ /* offsets into the pt_regs */ DEFINE(PT_D0, offsetof(struct pt_regs, d0)); DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0)); + DEFINE(PT_D1, offsetof(struct pt_regs, d1)); + DEFINE(PT_D2, offsetof(struct pt_regs, d2)); + DEFINE(PT_D3, offsetof(struct pt_regs, d3)); + DEFINE(PT_D4, offsetof(struct pt_regs, d4)); + DEFINE(PT_D5, offsetof(struct pt_regs, d5)); + DEFINE(PT_A0, offsetof(struct pt_regs, a0)); + DEFINE(PT_A1, offsetof(struct pt_regs, a1)); + DEFINE(PT_A2, offsetof(struct pt_regs, a2)); + DEFINE(PT_PC, offsetof(struct pt_regs, pc)); DEFINE(PT_SR, offsetof(struct pt_regs, sr)); - /* bitfields are a bit difficult */ DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); @@ -68,6 +76,12 @@ DEFINE(FBCON_FONT_DESC_HEIGHT, offsetof(struct fbcon_font_desc, height)); DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data)); DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref)); + + /* signal defines */ + DEFINE(SIGSEGV, SIGSEGV); + DEFINE(SEGV_MAPERR, SEGV_MAPERR); + DEFINE(SIGTRAP, SIGTRAP); + DEFINE(TRAP_TRACE, TRAP_TRACE); /* offsets into the custom struct */ DEFINE(CUSTOMBASE, &custom); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/m68k_defs.h linux/arch/m68k/kernel/m68k_defs.h --- v2.2.17/arch/m68k/kernel/m68k_defs.h Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/m68k_defs.h Fri Oct 13 23:30:47 2000 @@ -8,7 +8,7 @@ #define TASK_SIGPENDING 8 #define TASK_NEEDRESCHED 20 #define TASK_TSS 470 -#define TASK_MM 622 +#define TASK_MM 826 #define TSS_KSP 0 #define TSS_USP 4 #define TSS_SR 8 @@ -20,6 +20,15 @@ #define TSS_FPSTATE 132 #define PT_D0 32 #define PT_ORIG_D0 36 +#define PT_D1 0 +#define PT_D2 4 +#define PT_D3 8 +#define PT_D4 12 +#define PT_D5 16 +#define PT_A0 20 +#define PT_A1 24 +#define PT_A2 28 +#define PT_PC 46 #define PT_SR 44 #define PT_VECTOR 50 #define IRQ_HANDLER 0 @@ -35,6 +44,10 @@ #define FBCON_FONT_DESC_HEIGHT 12 #define FBCON_FONT_DESC_DATA 16 #define FBCON_FONT_DESC_PREF 20 +#define SIGSEGV 11 +#define SEGV_MAPERR 1 +#define SIGTRAP 5 +#define TRAP_TRACE 2 #define CUSTOMBASE -2132807680 #define C_INTENAR 28 #define C_INTREQR 30 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.2.17/arch/m68k/kernel/m68k_ksyms.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/m68k_ksyms.c Fri Oct 13 23:30:47 2000 @@ -19,9 +19,13 @@ #include #include #include +#include asmlinkage long long __ashrdi3 (long long, int); +asmlinkage long long __ashldi3 (long long, int); +asmlinkage long long __lshrdi3 (long long, int); extern char m68k_debug_device[]; +extern void ret_from_exception(void); extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -44,6 +48,7 @@ EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(m68k_debug_device); +EXPORT_SYMBOL(hwreg_present); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(strnlen); @@ -57,6 +62,10 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(register_serial); EXPORT_SYMBOL(unregister_serial); +EXPORT_SYMBOL(ret_from_exception); +#ifdef CONFIG_VME +EXPORT_SYMBOL(vme_brdtype); +#endif /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); @@ -66,6 +75,8 @@ their interface isn't gonna change any time soon now, so it's OK to leave it out of version control. */ EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__ashldi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memcmp); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v2.2.17/arch/m68k/kernel/process.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/process.c Fri Oct 13 23:30:47 2000 @@ -61,6 +61,7 @@ /* endless idle loop with no priority at all */ current->priority = 0; current->counter = -100; + init_idle(); for (;;) { if (!current->need_resched) #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) @@ -78,14 +79,21 @@ { if (mach_reset) mach_reset(); + for (;;); } void machine_halt(void) { + if (mach_halt) + mach_halt(); + for (;;); } void machine_power_off(void) { + if (mach_power_off) + mach_power_off(); + for (;;); } void show_regs(struct pt_regs * regs) @@ -146,9 +154,10 @@ unsigned long zero = 0; set_fs(USER_DS); current->tss.fs = __USER_DS; - asm volatile (".chip 68k/68881\n\t" - "frestore %0@\n\t" - ".chip 68k" : : "a" (&zero)); + if (!FPU_IS_EMU) + asm volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (zero)); } /* @@ -209,16 +218,18 @@ */ p->tss.fs = get_fs().seg; - /* Copy the current fpu state */ - asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory"); - - if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2]) - asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" - "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" - : : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0]) - : "memory"); - /* Restore the state in case the fpu was busy */ - asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0])); + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory"); + + if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2]) + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0]) + : "memory"); + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0])); + } return 0; } @@ -227,20 +238,34 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) { - char fpustate[216]; + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->tss.fpcntl, 12); + memcpy(fpu->fpregs, current->tss.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } - /* First dump the fpu context to avoid protocol violation. */ - asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) - return 0; + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) + return 0; - asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" :: "m" (fpu->fpcntl[0]) : "memory"); - asm volatile ("fmovemx %/fp0-%/fp7,%0" + asm volatile ("fmovemx %/fp0-%/fp7,%0" :: "m" (fpu->fpregs[0]) : "memory"); - return 1; + return 1; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c --- v2.2.17/arch/m68k/kernel/ptrace.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/ptrace.c Fri Oct 13 23:30:47 2000 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -403,10 +404,17 @@ tmp = get_reg(child, addr); if (addr == PT_SR) tmp >>= 16; - } - else if (addr >= 21 && addr < 49) + } else if (addr >= 21 && addr < 49) { tmp = child->tss.fp[addr - 21]; - else +#ifdef CONFIG_FPU_EMU + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); +#endif + } else goto out; ret = put_user(tmp,(unsigned long *) data); goto out; @@ -442,6 +450,16 @@ } if (addr >= 21 && addr < 48) { +#ifdef CONFIG_FPU_EMU + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { + data = (unsigned long)data << 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } +#endif child->tss.fp[addr - 21] = data; ret = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c --- v2.2.17/arch/m68k/kernel/setup.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/setup.c Fri Oct 13 23:30:47 2000 @@ -41,6 +41,9 @@ unsigned long m68k_cputype; unsigned long m68k_fputype; unsigned long m68k_mmutype; +#ifdef CONFIG_VME +unsigned long vme_brdtype; +#endif int m68k_is040or060 = 0; @@ -76,6 +79,8 @@ int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); +void (*mach_halt)( void ) = NULL; +void (*mach_power_off)( void ) = NULL; long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD) void (*mach_floppy_setup) (char *, int *) __initdata = NULL; @@ -114,6 +119,9 @@ extern int atari_parse_bootinfo(const struct bi_record *); extern int mac_parse_bootinfo(const struct bi_record *); extern int q40_parse_bootinfo(const struct bi_record *); +extern int bvme6000_parse_bootinfo(const struct bi_record *); +extern int mvme16x_parse_bootinfo(const struct bi_record *); +extern int mvme147_parse_bootinfo(const struct bi_record *); extern void config_amiga(void); extern void config_atari(void); @@ -171,6 +179,12 @@ unknown = mac_parse_bootinfo(record); else if (MACH_IS_Q40) unknown = q40_parse_bootinfo(record); + else if (MACH_IS_BVME6000) + unknown = bvme6000_parse_bootinfo(record); + else if (MACH_IS_MVME16x) + unknown = mvme16x_parse_bootinfo(record); + else if (MACH_IS_MVME147) + unknown = mvme147_parse_bootinfo(record); else unknown = 1; } @@ -208,10 +222,12 @@ base_trap_init(); /* clear the fpu if we have one */ +#ifndef CONFIG_FPU_EMU_ONLY if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { volatile int zero = 0; asm __volatile__ ("frestore %0" : : "m" (zero)); } +#endif init_task.mm->start_code = PAGE_OFFSET; init_task.mm->end_code = (unsigned long) &_etext; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.2.17/arch/m68k/kernel/signal.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/signal.c Fri Oct 13 23:30:47 2000 @@ -14,6 +14,10 @@ * 68060 fixes by Jesper Skov * * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab + * + * mathemu support by Roman Zippel + * (Note: fpstate in the signal context is completly ignored for the emulator + * and the internal floating point format is put on stack) */ /* @@ -156,6 +160,9 @@ /* * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. */ struct sigframe @@ -175,9 +182,9 @@ int sig; struct siginfo *pinfo; void *puc; + char retcode[8]; struct siginfo info; struct ucontext uc; - char retcode[8]; }; @@ -187,6 +194,13 @@ { int err = 1; + if (FPU_IS_EMU) { + /* restore registers */ + memcpy(current->tss.fpcntl, sc->sc_fpcntl, 12); + memcpy(current->tss.fp, sc->sc_fpregs, 24); + return 0; + } + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { /* Verify the frame format. */ if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) @@ -239,6 +253,18 @@ fpregset_t fpregs; int err = 1; + if (FPU_IS_EMU) { + /* restore fpu control register */ + if (__copy_from_user(current->tss.fpcntl, + &uc->uc_mcontext.fpregs.f_pcr, 12)) + goto out; + /* restore all other fpu register */ + if (__copy_from_user(current->tss.fp, + uc->uc_mcontext.fpregs.f_fpregs, 96)) + goto out; + return 0; + } + if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) goto out; if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { @@ -478,7 +504,7 @@ struct switch_stack *sw = (struct switch_stack *) &__unused; struct pt_regs *regs = (struct pt_regs *) (sw + 1); unsigned long usp = rdusp(); - struct sigframe *frame = (struct sigframe *)(usp - 24); + struct sigframe *frame = (struct sigframe *)(usp - 4); sigset_t set; int d0; @@ -536,6 +562,13 @@ static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) { + if (FPU_IS_EMU) { + /* save registers */ + memcpy(sc->sc_fpcntl, current->tss.fpcntl, 12); + memcpy(sc->sc_fpregs, current->tss.fp, 24); + return; + } + __asm__ volatile (".chip 68k/68881\n\t" "fsave %0\n\t" ".chip 68k" @@ -567,6 +600,16 @@ int context_size = CPU_IS_060 ? 8 : 0; int err = 0; + if (FPU_IS_EMU) { + /* save fpu control register */ + err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, + current->tss.fpcntl, 12); + /* save all other fpu register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, + current->tss.fp, 96); + return err; + } + __asm__ volatile (".chip 68k/68881\n\t" "fsave %0\n\t" ".chip 68k" @@ -677,25 +720,6 @@ "cpushl %%bc,(%0)\n\t" ".chip 68k" : : "a" (temp)); - if (((vaddr + 8) ^ vaddr) & ~15) { - if (((vaddr + 8) ^ vaddr) & PAGE_MASK) - __asm__ __volatile__ (".chip 68040\n\t" - "nop\n\t" - "ptestr (%1)\n\t" - "movec %%mmusr,%0\n\t" - ".chip 68k" - : "=r" (temp) - : "a" (vaddr + 8)); - - temp &= PAGE_MASK; - temp |= (vaddr + 8) & ~PAGE_MASK; - - __asm__ __volatile__ (".chip 68040\n\t" - "nop\n\t" - "cpushl %%bc,(%0)\n\t" - ".chip 68k" - : : "a" (temp)); - } } else if (CPU_IS_060) { unsigned long temp; @@ -708,18 +732,6 @@ "cpushl %%bc,(%0)\n\t" ".chip 68k" : : "a" (temp)); - if (((vaddr + 8) ^ vaddr) & ~15) { - if (((vaddr + 8) ^ vaddr) & PAGE_MASK) - __asm__ __volatile__ (".chip 68060\n\t" - "plpar (%0)\n\t" - ".chip 68k" - : "=a" (temp) - : "0" (vaddr + 8)); - __asm__ __volatile__ (".chip 68060\n\t" - "cpushl %%bc,(%0)\n\t" - ".chip 68k" - : : "a" (temp)); - } } else { /* @@ -797,11 +809,9 @@ /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); - /* addaw #20,sp */ - err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0)); /* moveq #,d0; trap #0 */ err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), - (long *)(frame->retcode + 4)); + (long *)(frame->retcode)); if (err) goto give_sigsegv; @@ -881,10 +891,10 @@ /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); - /* movel #,d0; trap #0 */ - err |= __put_user(0x203c, (short *)(frame->retcode + 0)); - err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2)); - err |= __put_user(0x4e40, (short *)(frame->retcode + 6)); + /* moveq #,d0; notb d0; trap #0 */ + err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), + (long *)(frame->retcode + 0)); + err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); if (err) goto give_sigsegv; @@ -964,11 +974,10 @@ if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(current); - } + recalc_sigpending(current); } /* @@ -1092,6 +1101,7 @@ default: sigaddset(¤t->signal, signr); + recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); /* NOTREACHED */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c --- v2.2.17/arch/m68k/kernel/traps.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/kernel/traps.c Fri Oct 13 23:30:47 2000 @@ -41,12 +41,17 @@ #include #endif +/*#define DEBUG*/ + /* assembler routines */ asmlinkage void system_call(void); asmlinkage void buserr(void); asmlinkage void trap(void); asmlinkage void inthandler(void); asmlinkage void nmihandler(void); +#ifdef CONFIG_FPU_EMU +asmlinkage void fpu_emu(void); +#endif e_vector vectors[256] = { 0, 0, buserr, trap, trap, trap, trap, trap, @@ -70,7 +75,7 @@ /* setup the exception vector table */ __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); - if (CPU_IS_040) { + if (CPU_IS_040 && !FPU_IS_EMU) { /* set up FPSP entry points */ asmlinkage void dz_vec(void) asm ("dz"); asmlinkage void inex_vec(void) asm ("inex"); @@ -93,6 +98,12 @@ vectors[VEC_FPUNSUP] = unsupp_vec; } if (CPU_IS_060) { + /* set up ISP entry points */ + asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); + + vectors[VEC_UNIMPII] = unimp_vec; + } + if (CPU_IS_060 && !FPU_IS_EMU) { /* set up IFPSP entry points */ asmlinkage void snan_vec(void) asm ("_060_fpsp_snan"); asmlinkage void operr_vec(void) asm ("_060_fpsp_operr"); @@ -104,8 +115,6 @@ asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp"); asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd"); - asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); - vectors[VEC_FPNAN] = snan_vec; vectors[VEC_FPOE] = operr_vec; vectors[VEC_FPOVER] = ovfl_vec; @@ -115,10 +124,6 @@ vectors[VEC_LINE11] = fline_vec; vectors[VEC_FPUNSUP] = unsupp_vec; vectors[VEC_UNIMPEA] = effadd_vec; - - /* set up ISP entry points */ - - vectors[VEC_UNIMPII] = unimp_vec; } } @@ -133,6 +138,11 @@ for (i = 64; i < 256; i++) vectors[i] = inthandler; +#ifdef CONFIG_FPU_EMU + if (FPU_IS_EMU) + vectors[VEC_LINE11] = fpu_emu; +#endif + /* if running on an amiga, make the NMI interrupt do nothing */ if (MACH_IS_AMIGA) { vectors[VEC_INT7] = nmihandler; @@ -182,8 +192,9 @@ void die_if_kernel(char *,struct pt_regs *,int); -asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, - unsigned long error_code); +int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code); +int send_fault_sig(struct pt_regs *regs); asmlinkage void trap_c(struct frame *fp); @@ -232,74 +243,141 @@ #endif /* CONFIG_M68060 */ #if defined (CONFIG_M68040) -static inline unsigned long probe040 (int iswrite, int fc, unsigned long addr) + +static inline unsigned long probe040(int iswrite, unsigned long addr) { unsigned long mmusr; - mm_segment_t fs = get_fs(); - set_fs (MAKE_MM_SEG(fc)); + asm volatile (".chip 68040"); if (iswrite) - /* write */ - asm volatile (".chip 68040\n\t" - "ptestw (%1)\n\t" - "movec %%mmusr,%0\n\t" - ".chip 68k" - : "=r" (mmusr) - : "a" (addr)); + asm volatile ("ptestw (%0)" : : "a" (addr)); else - asm volatile (".chip 68040\n\t" - "ptestr (%1)\n\t" - "movec %%mmusr,%0\n\t" - ".chip 68k" - : "=r" (mmusr) - : "a" (addr)); + asm volatile ("ptestr (%0)" : : "a" (addr)); + + asm volatile ("movec %%mmusr,%0" : "=r" (mmusr)); - set_fs (fs); + asm volatile (".chip 68k"); return mmusr; } -static inline void do_040writeback (unsigned short ssw, - unsigned short wbs, - unsigned long wba, - unsigned long wbd, - struct frame *fp) +static inline int do_040writeback1(unsigned short wbs, unsigned long wba, + unsigned long wbd) { - mm_segment_t fs = get_fs (); - unsigned long mmusr; - unsigned long errorcode; + mm_segment_t old_fs; + int res = 0; - /* - * No special handling for the second writeback anymore. - * It misinterpreted the misaligned status sometimes. - * This way an extra page-fault may be caused (Martin Apel). - */ - - mmusr = probe040 (1, wbs & WBTM_040, wba); - errorcode = (mmusr & MMU_R_040) ? 3 : 2; - if (do_page_fault (&fp->ptregs, wba, errorcode)) - /* just return if we can't perform the writeback */ - return; + old_fs = get_fs(); + set_fs(MAKE_MM_SEG(wbs)); - set_fs (MAKE_MM_SEG(wbs & WBTM_040)); switch (wbs & WBSIZ_040) { - case BA_SIZE_BYTE: - put_user (wbd & 0xff, (char *)wba); + case BA_SIZE_BYTE: + res = put_user(wbd & 0xff, (char *)wba); break; - case BA_SIZE_WORD: - put_user (wbd & 0xffff, (short *)wba); + case BA_SIZE_WORD: + res = put_user(wbd & 0xffff, (short *)wba); break; - case BA_SIZE_LONG: - put_user (wbd, (int *)wba); + case BA_SIZE_LONG: + res = put_user(wbd, (int *)wba); break; } - set_fs (fs); + set_fs(old_fs); + +#ifdef DEBUG + printk("do_040writeback1, res=%d\n",res); +#endif + + return res; +} + +#define FIX_XFRAME(fp,_faddr_,_set_ma_,_wbs_) \ + do{ (fp)->un.fmt7.faddr = (_faddr_); \ + (fp)->un.fmt7.ssw &= ~( 0x7f | MA_040 | RW_040); \ + (fp)->un.fmt7.ssw |= (~0x7f & (_wbs_)); \ + (fp)->un.fmt7.ssw |= ((_set_ma_) ? MA_040 : 0); \ + } while(0) + +/* after an exception in a writeback the stack frame coresponding + * to that exception is discarded, set a few bits in the old frame + * to simulate what it should look like */ + +inline void fix_xframe040(struct frame *fp, unsigned long faddr, unsigned short wbs) +{ + unsigned short ssw=(fp)->un.fmt7.ssw; + + ssw &= ~( 0x7f | MA_040 | RW_040); + ssw |= (~0x7f & wbs); + if (faddr != (unsigned long)(current->buserr_info.si_addr) ) + ssw |= MA_040; + (fp)->un.fmt7.faddr = faddr; + (fp)->un.fmt7.ssw = ssw; +} + +inline void do_040writebacks(struct frame *fp) +{ + unsigned long wbaddr; + int xp=0; +#if 0 + if (fp->un.fmt7.wb1s & WBV_040) + printk("access_error040: cannot handle 1st writeback. oops.\n"); +#endif + + if ((fp->un.fmt7.wb2s & WBV_040) && + !(fp->un.fmt7.wb2s & WBTT_040)) { + wbaddr = fp->un.fmt7.wb2a; + if (xp=do_040writeback1(fp->un.fmt7.wb2s, wbaddr, + fp->un.fmt7.wb2d)) + { + fix_xframe040(fp,wbaddr,fp->un.fmt7.wb2s); + } + else + fp->un.fmt7.wb2s &= ~WBV_040; + } + + if (fp->un.fmt7.wb3s & WBV_040) { + wbaddr= fp->un.fmt7.wb3a; + if (do_040writeback1(fp->un.fmt7.wb3s, wbaddr, + fp->un.fmt7.wb3d)) + { + if (!xp) + { + fix_xframe040(fp,wbaddr,fp->un.fmt7.wb3s); + fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; + fp->un.fmt7.wb3s &= (~WBV_040); + fp->un.fmt7.wb2a = wbaddr; + fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; + xp=1; + } + } + else + fp->un.fmt7.wb3s &= ~WBV_040; + } + + if (!xp) return; + + send_fault_sig(&fp->ptregs); +} + +/* + * called from sigreturn(), must ensure userspace code didn't + * manipulate exception frame to circumvent protection, then complete + * pending writebacks + * Theory is that setting TT1=0 and TM2=0 will avoid all trouble + */ +asmlinkage void berr_040cleanup(struct frame *fp) +{ + fp->un.fmt7.ssw &= ~(0x10 | 0x4); + fp->un.fmt7.wb2s &= ~(0x10 | 0x4); + fp->un.fmt7.wb3s &= ~(0x10 | 0x4); + + do_040writebacks(fp); } -static inline void access_error040 (struct frame *fp) +static inline void access_error040(struct frame *fp) { unsigned short ssw = fp->un.fmt7.ssw; + mm_segment_t old_fs = get_fs(); unsigned long mmusr; #ifdef DEBUG @@ -323,43 +401,43 @@ if (ssw & MA_040) addr = PAGE_ALIGN (addr); + set_fs(MAKE_MM_SEG(ssw)); /* MMU error, get the MMUSR info for this access */ - mmusr = probe040 (!(ssw & RW_040), ssw & TM_040, addr); + mmusr = probe040(!(ssw & RW_040), addr); + set_fs(old_fs); #ifdef DEBUG printk("mmusr = %lx\n", mmusr); #endif + errorcode = ((mmusr & MMU_R_040) ? 1 : 0) | - ((ssw & RW_040) ? 0 : 2); - do_page_fault (&fp->ptregs, addr, errorcode); - } else { - printk ("68040 access error, ssw=%x\n", ssw); - trap_c (fp); - } + ((ssw & RW_040) ? 0 : 2) | + ((ssw & LK_040) ? 2 : 0); -#if 0 - if (fp->un.fmt7.wb1s & WBV_040) - printk("access_error040: cannot handle 1st writeback. oops.\n"); + if (do_page_fault(&fp->ptregs, addr, errorcode)) { +#ifdef DEBUG + printk("do_page_fault() !=0 \n"); #endif + if (user_mode(&fp->ptregs)){ + /* delay writebacks after signal delivery */ +#ifdef DEBUG + printk(".. was usermode - return\n"); +#endif + return; + } + /* disable writeback into user space from kernel */ +#ifdef DEBUG + printk(".. disabling wb2\n"); +#endif + if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) + fp->un.fmt7.wb2s &= ~WBV_040; + } -/* - * We may have to do a couple of writebacks here. - * - * MR: we can speed up the thing a little bit and let do_040writeback() - * not produce another page fault as wb2 corresponds to the address that - * caused the fault. on write faults no second fault is generated, but - * on read faults for security reasons (although per definitionem impossible) - */ + } else { + printk("68040 access error, ssw=%x\n", ssw); + trap_c(fp); + } - if (fp->un.fmt7.wb2s & WBV_040 && (fp->un.fmt7.wb2s & - WBTT_040) != BA_TT_MOVE16) - do_040writeback (ssw, - fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, - fp->un.fmt7.wb2d, fp); - - if (fp->un.fmt7.wb3s & WBV_040) - do_040writeback (ssw, fp->un.fmt7.wb3s, - fp->un.fmt7.wb3a, fp->un.fmt7.wb3d, - fp); + do_040writebacks(fp); } #endif /* CONFIG_M68040 */ @@ -650,7 +728,7 @@ if (user_mode(&fp->ptregs)) current->tss.esp0 = (unsigned long) fp; -#if DEBUG +#if 0/*DEBUG*/ printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); #endif @@ -673,7 +751,7 @@ #endif default: die_if_kernel("bad frame format",&fp->ptregs,0); -#if DEBUG +#if 0/*DEBUG*/ printk("Unknown SIGSEGV - 4\n"); #endif force_sig(SIGSEGV, current); @@ -990,3 +1068,16 @@ { do_exit(SIGSEGV); } + +#ifdef CONFIG_FPU_EMU +asmlinkage void fpemu_signal(int signal, int code, void *addr) +{ + siginfo_t info; + + info.si_signo = signal; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + force_sig_info(signal, &info, current); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/lib/Makefile linux/arch/m68k/lib/Makefile --- v2.2.17/arch/m68k/lib/Makefile Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/lib/Makefile Fri Oct 13 23:30:47 2000 @@ -6,6 +6,6 @@ $(CC) -D__ASSEMBLY__ -traditional -c $< -o $@ L_TARGET = lib.a -L_OBJS = ashrdi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o +L_OBJS = ashrdi3.o lshrdi3.o ashldi3.o checksum.o memcpy.o memcmp.o memset.o semaphore.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/lib/ashldi3.c linux/arch/m68k/lib/ashldi3.c --- v2.2.17/arch/m68k/lib/ashldi3.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/lib/ashldi3.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,62 @@ +/* ashldi3.c extracted from gcc-2.8.1/libgcc2.c which is: */ +/* Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__ashldi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.low = 0; + w.s.high = (USItype)uu.s.low << -bm; + } + else + { + USItype carries = (USItype)uu.s.low >> bm; + w.s.low = (USItype)uu.s.low << b; + w.s.high = ((USItype)uu.s.high << b) | carries; + } + + return w.ll; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/lib/lshrdi3.c linux/arch/m68k/lib/lshrdi3.c --- v2.2.17/arch/m68k/lib/lshrdi3.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/lib/lshrdi3.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,62 @@ +/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__lshrdi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.high = 0; + w.s.low = (USItype)uu.s.high >> -bm; + } + else + { + USItype carries = (USItype)uu.s.high << bm; + w.s.high = (USItype)uu.s.high >> b; + w.s.low = ((USItype)uu.s.low >> b) | carries; + } + + return w.ll; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile --- v2.2.17/arch/m68k/mac/Makefile Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/Makefile Fri Oct 13 23:30:47 2000 @@ -7,11 +7,9 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -EXTRA_CFLAGS := -Wa,-m68020 - O_TARGET := mac.o -O_OBJS := config.o bootparse.o macints.o via6522.o \ - mackeyb.o adb-bus.o macboing.o debug.o +O_OBJS := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \ + mackeyb.o adb-bus.o macboing.o debug.o adb-misc.o OX_OBJS := mac_ksyms.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c --- v2.2.17/arch/m68k/mac/adb-bus.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/adb-bus.c Fri Oct 13 23:30:47 2000 @@ -11,6 +11,28 @@ * - Guido Koerber's session with a logic analyzer * * MSch (1/98) Integrated start of IIsi driver by Robert Thompson + * + * 1999-05-30 (JMT) - Added support for reading/writing the PRAM clock. + * We really need to clean up the reply_expected usage + * in here so that the special cases in adb_interrupt + * for faking replies can be removed. + * + * 1999-06-10 (JMT) - Wedged in some IOP support. This is really getting + * messy... + * + * 1999-06-11 (JMT) - IOP support sort of working. Autopolling of the + * keyboard works but if we transmit and get a timeout + * we'll get bombarded with timeout message from the + * IOP and I don't know how to make them stop. Thus + * I have disabled transmission until I can figure out + * how to handle the timeouts properly. + * 1999-06-12 (JMT) - Rewrote IOP support to match changes in IOP + * architecture. Also discovered that you need to send + * a sensible reply to an autopoll packet or else the + * keyboard will stop sending packets. I chose to send + * back what we received, as that was what we were + * essentially doing before the IOP rewrite and it + * seemed to work. */ #include @@ -22,7 +44,6 @@ #include #include #include -#include "via6522.h" #include #include @@ -32,7 +53,9 @@ #include #include #include - +#include +#include +#include #define MACII /* For now - will be a switch */ @@ -51,11 +74,7 @@ /* Bits in ACR */ #define SR_CTRL 0x1c /* Shift register control bits */ -#ifdef USE_ORIG -#define SR_EXT 0x1c /* Shift on external clock */ -#else #define SR_EXT 0x0c /* Shift on external clock */ -#endif #define SR_OUT 0x10 /* Shift out if 1 */ /* Bits in IFR and IER */ @@ -68,6 +87,17 @@ /* JRT */ #define ADB_DELAY 150 +#ifdef DEBUG_ADB_INTS +static int nclock, ndata; +#endif + +static int need_poll = 0; +static int command_byte = 0; +static int last_reply = 0; +static int last_active = 0; + +static struct adb_request *retry_req; + static struct adb_handler { void (*handler)(unsigned char *, int, struct pt_regs *); } adb_handler[16]; @@ -100,14 +130,23 @@ int in_keybinit = 1; static void adb_start(void); -extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs); +static void adb_interrupt(int irq, void *arg, struct pt_regs *regs); +static void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs); +static void adb_pm_interrupt(int irq, void *arg, struct pt_regs *regs); +#ifdef DEBUG_ADB_INTS +static void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs); +static void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs); +#endif static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs); +static void adb_iop_receive(struct iop_msg *, struct pt_regs *); +static void adb_hw_setup_macII(void); static void adb_hw_setup_IIsi(void); static void adb_hw_setup_cuda(void); +static void adb_hw_setup_iop(void); +static void adb_hw_setup_pm(void); + +void adb_retransmit(int); /* * debug level 10 required for ADB logging (should be && debug_adb, ideally) @@ -149,7 +188,6 @@ void adb_bus_init(void) { unsigned long flags; - unsigned char c, i; save_flags(flags); cli(); @@ -162,122 +200,47 @@ { case MAC_ADB_II: - printk("adb: MacII style keyboard/mouse driver.\n"); - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); - /* - * Docs suggest TREQ should be output - that seems nuts - * BSD agrees here :-) - * Setup vPCR ?? - */ - -#ifdef USE_ORIG - /* Lower the bus signals (MacII is active low it seems ???) */ - via_write(via1, vBufB, via_read(via1, vBufB)&~TACK); -#else - /* Corresponding state: idle (clear state bits) */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - last_status = (via_read(via1, vBufB)&~ST_MASK); -#endif - /* Shift register on input */ - c=via_read(via1, vACR); - c&=~SR_CTRL; /* Clear shift register bits */ - c|=SR_EXT; /* Shift on external clock; out or in? */ - via_write(via1, vACR, c); - /* Wipe any pending data and int */ - via_read(via1, vSR); - - /* This is interrupts on enable SR for keyboard */ - via_write(via1, vIER, IER_SET|SR_INT); - /* This clears the interrupt bit */ - via_write(via1, vIFR, SR_INT); - - /* - * Ok we probably ;) have a ready to use adb bus. Its also - * hopefully idle (Im assuming the mac didnt leave a half - * complete transaction on booting us). - */ - + printk(KERN_INFO "adb: MacII style keyboard/mouse driver.\n"); + adb_hw_setup_macII(); request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, "adb interrupt", adb_interrupt); adb_state = idle; break; - /* - * Unsupported; but later code doesn't notice !! - */ - case MAC_ADB_CUDA: - printk("adb: CUDA interface.\n"); -#if 0 - /* don't know what to set up here ... */ - adb_state = idle; - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); -#endif - adb_hw_setup_cuda(); - adb_state = idle; - request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, - "adb CUDA interrupt", adb_cuda_interrupt); - break; case MAC_ADB_IISI: printk("adb: Using IIsi hardware.\n"); - printk("\tDEBUG_JRT\n"); - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); - - /* - * MSch: I'm pretty sure the setup is mildly wrong - * for the IIsi. - */ - /* Initial state: idle (clear state bits) */ - via_write(via1, vBufB, (via_read(via1, vBufB) & ~(TIP|TACK)) ); - last_status = (via_read(via1, vBufB)&~ST_MASK); - /* Shift register on input */ - c=via_read(via1, vACR); - c&=~SR_CTRL; /* Clear shift register bits */ - c|=SR_EXT; /* Shift on external clock; out or in? */ - via_write(via1, vACR, c); - /* Wipe any pending data and int */ - via_read(via1, vSR); - - /* This is interrupts on enable SR for keyboard */ - via_write(via1, vIER, IER_SET|SR_INT); - /* This clears the interrupt bit */ - via_write(via1, vIFR, SR_INT); - - /* get those pesky clock ticks we missed while booting */ - for ( i = 0; i < 60; i++) { - udelay(ADB_DELAY); - adb_hw_setup_IIsi(); - udelay(ADB_DELAY); - if (via_read(via1, vBufB) & TREQ) - break; - } - if (i == 60) - printk("adb_IIsi: maybe bus jammed ??\n"); - - /* - * Ok we probably ;) have a ready to use adb bus. Its also - */ + adb_hw_setup_IIsi(); request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, "adb interrupt", adb_cuda_interrupt); adb_state = idle; break; + case MAC_ADB_CUDA: + printk(KERN_INFO "adb: CUDA interface.\n"); + + adb_hw_setup_cuda(); + request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, + "adb CUDA interrupt", adb_cuda_interrupt); + adb_state = idle; + break; + case MAC_ADB_IOP: + printk("adb: using IOP for ADB...good luck.\n"); + iop_listen(ADB_IOP, ADB_CHAN, adb_iop_receive, "ADB"); + adb_hw_setup_iop(); + adb_state = idle; + break; + case MAC_ADB_PB1: + case MAC_ADB_PB2: + printk("adb: using PowerManager for ADB... you are doomed.\n"); + adb_hw_setup_pm(); + request_irq(IRQ_MAC_ADB, adb_pm_interrupt, IRQ_FLG_LOCK, + "adb PowerManager interrupt", adb_pm_interrupt); + adb_state = idle; + break; default: printk("adb: Unknown hardware interface.\n"); - nosupp: - printk("adb: Interface unsupported.\n"); restore_flags(flags); return; } - /* - * XXX: interrupt only registered if supported HW !! - * -> unsupported HW will just time out on keyb_init! - */ -#if 0 - request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, - "adb interrupt", adb_interrupt); -#endif #ifdef DEBUG_ADB_INTS request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK, "adb clock interrupt", adb_clock_interrupt); @@ -289,6 +252,100 @@ restore_flags(flags); } +/* Set up IOP ADB */ + +void adb_hw_setup_iop(void) +{ +#if 0 + volatile struct adb_request req; +#endif + + printk("adb-iop: hardware setup in progress.\n"); + +#if 0 + adb_request((struct adb_request *) &req, NULL, + 2, ADB_PACKET, AIF_RESET); + while (!req.complete); +#endif + + printk("adb-iop: hardware setup done!\n"); +} + +/* Strip the adb message out of an IOP message */ + +static void adb_from_iopmsg(struct iop_msg *src, struct adb_iopmsg *dst, + int is_reply) +{ + if (is_reply) { + memcpy(dst, &src->reply[0], sizeof(struct adb_iopmsg)); + } else { + memcpy(dst, &src->message[0], sizeof(struct adb_iopmsg)); + } +} + +/* + * Receive an ADB message from the IOP. + * + * This will be called in two cases: + * + * 1. A message has been successfully sent to the IOP. + * 4. An unsolicited message was received from the IOP. + */ + +void adb_iop_receive(struct iop_msg *msg, struct pt_regs *regs) +{ + struct adb_iopmsg amsg; + struct adb_request *req; + unsigned char packet[16]; + int i; + + req = current_req; + + if (msg->status == IOP_MSGSTATUS_COMPLETE) { + if (req->reply_expected) { + adb_from_iopmsg(msg, &amsg, 1); + req->reply_len = amsg.count + 1; + req->reply[0] = ADB_PACKET; + for (i = 0 ; i < sizeof(amsg.data) ; i++) { + req->reply[i+1] = amsg.data[i]; + } + } + req->complete = 1; + current_req = req->next; + if (req->done) (*req->done)(req); + adb_state = idle; + } else if (msg->status == IOP_MSGSTATUS_UNSOL) { + adb_from_iopmsg(msg, &amsg, 0); + if (amsg.flags & ADB_IOP_TIMEOUT) { /* timeout */ + printk("adb_iop_receive: timeout, retransmitting to %d\n", last_active); + if (last_active == -1) + last_active = (amsg.cmd&0xf0)>>4; + if (current_req) { + adb_start(); + } else { + adb_retransmit(last_active); + } + } else { + /* fake a CUDA-format packet */ + packet[0] = ADB_PACKET; /* packet type */ + packet[1] = 0; /* ???? */ + packet[2] = amsg.cmd; /* command byte */ + i = 0; + while (i < amsg.count) { + packet[i+3] = amsg.data[i]; + i++; + } + adb_input(packet, amsg.count + 3, regs); + memcpy(&msg->reply[0], &msg->message[0], IOP_MSG_LEN); + } + iop_complete_message(msg); + adb_state = idle; + } else { + printk("adb_iop_receive: unknown IOP message state %d.\n", + msg->status); + } +} + void adb_hw_setup_cuda(void) { int x; @@ -398,20 +455,45 @@ printk("\nCUDA: HW Setup done!\n"); } -void adb_hw_setup_IIsi(void) +static void adb_hw_setup_macII(void) +{ + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); + /* + * Docs suggest TREQ should be output - that seems nuts + * BSD agrees here :-) + * Setup vPCR ?? + */ + + /* Set up state: idle */ + via_write(via1, vBufB, via_read(via1, vBufB) | ST_IDLE); + last_status = (via_read(via1, vBufB)&~ST_MASK); + + /* Shift register on input */ + via_write(via1, vACR, (via_read(via1, vACR) & ~SR_CTRL) | SR_EXT); + /* Wipe any pending data and int */ + via_read(via1, vSR); + + /* This is interrupts on enable SR for keyboard */ + via_write(via1, vIER, IER_SET|SR_INT); + /* This clears the interrupt bit */ + via_write(via1, vIFR, SR_INT); +} + +static void adb_IIsi_cleanup(void) { int dummy; long poll_timeout; - printk("adb_IIsi: cleanup!\n"); + printk(KERN_DEBUG "adb_IIsi: cleanup!\n"); /* ??? */ udelay(ADB_DELAY); - /* disable SR int. */ - via_write(via1, vIER, IER_CLR|SR_INT); /* set SR to shift in */ via_write(via1, vACR, via_read(via1, vACR ) & ~SR_OUT); + /* disable SR int. */ + via_write(via1, vIER, IER_CLR|SR_INT); /* this is required, especially on faster machines */ udelay(ADB_DELAY); @@ -454,6 +536,44 @@ via_write(via1, vIER, IER_SET|SR_INT); } +static void adb_hw_setup_IIsi(void) +{ + int i; + + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via_write(via1, vDirB, (via_read(via1,vDirB)|TACK|TIP) & ~TREQ); + + /* Shift register on input */ + via_write(via1, vACR, (via_read(via1, vACR) & ~SR_CTRL) | SR_EXT); + /* Wipe any pending data and int */ + via_read(via1, vSR); + + /* This is interrupts on enable SR for keyboard */ + via_write(via1, vIER, IER_SET|SR_INT); + + /* Set initial state: idle */ + via_write(via1, vBufB, via_read(via1, vBufB) & ~ST_IDLE); + last_status = (via_read(via1, vBufB)&~ST_MASK); + + /* This clears the interrupt bit */ + via_write(via1, vIFR, SR_INT); + + /* get those pesky clock ticks we missed while booting */ + for ( i = 0; i < 60; i++) { + udelay(ADB_DELAY); + adb_IIsi_cleanup(); + udelay(ADB_DELAY); + if (via_read(via1, vBufB) & TREQ) + break; + } + if (i == 60) + printk("adb_IIsi: maybe bus jammed ??\n"); +} + +static void adb_hw_setup_pm(void) +{ +} + #define WAIT_FOR(cond, what) \ do { \ for (x = 1000; !(cond); --x) { \ @@ -477,7 +597,7 @@ * here depending on hardware type ... */ int adb_request(struct adb_request *req, void (*done)(struct adb_request *), - int nbytes, ...) + int nbytes, ...) { va_list list; int i, start; @@ -488,6 +608,9 @@ * skip first byte if not CUDA */ if (macintosh_config->adb_type == MAC_ADB_II) { +/* + (macintosh_config->adb_type == MAC_ADB_IOP)) { +*/ start = va_arg(list, int); nbytes--; } @@ -599,7 +722,7 @@ r.reply_expected=0; r.done=NULL; r.sent=0; - r.got_reply=0; + r.complete=0; r.reply_len=0; save_flags(flags); cli(); @@ -636,7 +759,7 @@ rt.reply_expected = 0; rt.done = NULL; rt.sent = 0; - rt.got_reply = 0; + rt.complete = 0; rt.reply_len = 0; rt.next = NULL; @@ -674,7 +797,7 @@ req->next = 0; req->sent = 0; - req->got_reply = 0; + req->complete = 0; req->reply_len = 0; save_flags(flags); cli(); @@ -696,14 +819,92 @@ return 0; } -static int nclock, ndata; +/* + * Start sending an ADB packet, IOP style + * + * There isn't much to do other than hand the packet over to the IOP + * after encapsulating it in an adb_iopmsg. + */ -static int need_poll = 0; -static int command_byte = 0; -static int last_reply = 0; -static int last_active = 0; +static void adb_start_iop(void) +{ + unsigned long flags; + struct adb_request *req; + struct adb_iopmsg amsg; + int reply_expected,i,nb; -static struct adb_request *retry_req; + /* get the packet to send */ + req = current_req; + + /* TODO: re-enable transmits when timeout handling is fixed */ + + req->sent = 1; + req->complete = 1; + if (req->done) (*req->done)(req); + return; + + /* assert adb_state == idle */ + if (adb_state != idle) { + printk("adb-iop: adb_start_iop called while driver busy (%p %x)!\n", + req, adb_state); + return; + } + + if (req->data[0] != ADB_PACKET) { + printk("abb-iop: attempt to send non-ADB packet through IOP\n"); + return; + } + + if (req == 0) return; + save_flags(flags); + cli(); + + /* Always expecting a reply could be fatal since it could clog */ + /* the receive channel, not to mention it won't reset the adb */ + /* state back to idle since adb_iop_receive won't be called. */ + /* It's best to play it safe; if we aren't sure then don't */ + /* set reply_expected; it won't work right but at least it */ + /* won't clog the ADB subsystem. */ + + if ((req->data[1] & 0x0C) == AIF_TALK) { + reply_expected = 1; + } else { + reply_expected = 0; + } + + /* The IOP appears to take MacII-style packets, not CUDA packets */ + + nb = req->nbytes - 2; + if (nb > sizeof(amsg.data)) nb = sizeof(amsg.data); + + printk("adb-iop: sending packet, %d bytes:", nb); + + amsg.flags = ADB_IOP_EXPLICIT; + amsg.cmd = req->data[1]; + amsg.count = nb; + + printk(" %02X", (uint) amsg.cmd); + + i = 0; + while(i < nb) { + amsg.data[i] = req->data[i+2]; + printk(" %02X", (uint) amsg.data[i]); + i++; + } + printk("\n"); + + /* Now send it. The IOP manager will call */ + /* adb_iop_receive when the reply comes */ + /* or when the send is completed if no */ + /* reply is expected. */ + + iop_send_message(ADB_IOP, ADB_CHAN, req, + sizeof(amsg), (__u8 *) &amsg, adb_iop_receive); + + adb_state = sending; + + restore_flags(flags); +} /* * Start sending ADB packet @@ -713,10 +914,15 @@ unsigned long flags; struct adb_request *req; + if (macintosh_config->adb_type == MAC_ADB_IOP) { + adb_start_iop(); + return; + } + /* * We get here on three 'sane' conditions: * 1) called from send_adb_request, if adb_state == idle - * 2) called from within adb_interrupt, if adb_state == idle + * 2) called from within adb_interrupt, if ade_state == idle * (after receiving, or after sending a LISTEN) * 3) called from within adb_interrupt, if adb_state == sending * and no reply is expected (immediate next command). @@ -741,8 +947,10 @@ printk("adb_start: request %p ", req); #endif +#ifdef DEBUG_ADB_INTS nclock = 0; ndata = 0; +#endif /* * IRQ signaled ?? (means ADB controller wants to send, or might @@ -926,6 +1134,7 @@ restore_flags(flags); } +#ifdef DEBUG_ADB_INTS /* * Debugging gimmicks */ @@ -938,6 +1147,7 @@ { ndata++; } +#endif /* * The notorious ADB interrupt handler - does all of the protocol handling, @@ -1345,7 +1555,7 @@ /* XXX: fake ADB header? */ req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; req->reply_len = 3; - req->got_reply = 1; + req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); @@ -1413,7 +1623,7 @@ /* invert state bits, toggle ODD/EVEN */ x = via_read(via1, vBufB); via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); + (x&~ST_MASK)|(~(x&ST_MASK) & ST_MASK)); } } break; @@ -1632,7 +1842,7 @@ /* invert state bits, toggle ODD/EVEN */ x = via_read(via1, vBufB); via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); + (x&~ST_MASK)|(~(x&ST_MASK) & ST_MASK)); #endif /* adjust packet length */ reply_len--; @@ -1655,7 +1865,7 @@ /* invert state bits, toggle ODD/EVEN */ x = via_read(via1, vBufB); via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); + (x&~ST_MASK)|(~(x&ST_MASK) & ST_MASK)); } } } @@ -1672,7 +1882,7 @@ { req = current_req; req->reply_len = reply_ptr - req->reply; - req->got_reply = 1; + req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); @@ -1824,14 +2034,6 @@ udelay(150); via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - if (status != TREQ) - printk("adb_macII: state=idle status=%x want=%x\n", - status, TREQ); - x = via_read(via1, vSR); - via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); - } adb_state = reading; reply_ptr = cuda_rbuf; reply_len = 0; @@ -1949,9 +2151,7 @@ /* delay */ udelay(ADB_DELAY); /* set the shift register to shift out and send a byte */ -#if 0 via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); -#endif via_write(via1, vSR, current_req->data[1]); /* signal 'byte ready' */ via_write(via1, vBufB, via_read(via1, vBufB) | TACK); @@ -1959,17 +2159,6 @@ adb_state = sending; } } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - if(status!=TIP+SR_OUT) - printk("adb_macII: state=send_first_byte status=%x want=%x\n", - status, TIP+SR_OUT); - via_write(via1, vSR, current_req->data[1]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - data_index=2; - adb_state = sending; - } break; case sending: @@ -1997,21 +2186,13 @@ /* delay */ udelay(ADB_DELAY); /* set the shift register to shift in */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); + via_write(via1, vACR, via_read(via1, vACR) & ~SR_OUT); /* clear SR int. */ x = via_read(via1, vSR); /* set ADB state 'idle' (end of frame) */ via_write(via1, vBufB, via_read(via1,vBufB) & ~(TACK|TIP)); } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vACR, - via_read(via1, vACR) & ~SR_OUT); - x=via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - } req->sent = 1; if (req->reply_expected) { @@ -2019,10 +2200,11 @@ * maybe fake a reply here on Listen ?? * Otherwise, a Listen hangs on success * CUDA+IIsi: only ADB Talk considered - * RTC/PRAM read (0x1 0x3) to follow. */ if ( (req->data[0] == 0x0) && ((req->data[1]&0xc) == 0xc) ) adb_state = awaiting_reply; + else if ((req->data[0] == 0x1) && (req->data[1] == 0x3) ) + adb_state = awaiting_reply; else { /* * Reply expected, but none @@ -2036,7 +2218,7 @@ /* XXX: fake ADB header? */ req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; req->reply_len = 3; - req->got_reply = 1; + req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); @@ -2088,12 +2270,6 @@ /* signal 'byte ready' */ via_write(via1, vBufB, via_read(via1, vBufB) | TACK); } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vSR, req->data[data_index++]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } } break; @@ -2169,24 +2345,6 @@ Handshake anyway?? */ } } - if(macintosh_config->adb_type==MAC_ADB_II) - { - if( status == TIP) - { - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - adb_state = read_done; - } - else - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - if(status!=TIP+TREQ) - printk("macII_adb: state=reading status=%x\n", status); -#endif - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } /* fall through for IIsi on end of frame */ if (macintosh_config->adb_type != MAC_ADB_IISI || adb_state != read_done) @@ -2203,7 +2361,7 @@ { req = current_req; req->reply_len = reply_ptr - req->reply; - req->got_reply = 1; + req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); @@ -2247,31 +2405,38 @@ } +static void adb_pm_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + printk("adb_pm_interrupt called!\n"); +} + /* * The 'reply delivery' routine; determines which device sent the * request and calls the appropriate handler. * Reply data are expected in CUDA format (again, argh...) so we need * to fake this in the interrupt handler for MacII. + * + * Note! The PowerPC code now expects data in ADB format, and + * has their CUDA handler throw non-ADB packets on the floor. We + * are going to sync with them. It is only a matter of time. + * * Only one handler per device ID is currently possible. * XXX: is the ID field here representing the default or real ID? */ static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs) { - int i, id; + int id; switch (buf[0]) { case ADB_PACKET: /* what's in buf[1] ?? */ + /* according to via-cuda.c, buf[1] should tell + us whether to autopoll or not */ id = buf[2] >> 4; -#if 0 - xmon_printf("adb packet: "); - for (i = 0; i < nb; ++i) - xmon_printf(" %x", buf[i]); - xmon_printf(", id = %d\n", id); -#endif #if (ADBDEBUG & ADBDEBUG_INPUT) if (console_loglevel == 10) { + int i; printk("adb_input: adb packet "); for (i = 0; i < nb; ++i) printk(" %x", buf[i]); @@ -2287,6 +2452,7 @@ default: #if (ADBDEBUG & ADBDEBUG_INPUT) if (console_loglevel == 10) { + int i; printk("adb_input: data from via (%d bytes):", nb); for (i = 0; i < nb; ++i) printk(" %.2x", buf[i]); @@ -2338,7 +2504,7 @@ add_wait_queue(&adb_wait, &wait); current->state = TASK_INTERRUPTIBLE; - while (!state->req.got_reply) { + while (!state->req.complete) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; @@ -2358,9 +2524,9 @@ static void adb_write_done(struct adb_request *req) { - if (!req->got_reply) { + if (!req->complete) { req->reply_len = 0; - req->got_reply = 1; + req->complete = 1; } wake_up_interruptible(&adb_wait); } @@ -2371,7 +2537,7 @@ static int adb_open(struct inode *inode, struct file *file) { - int adb_type, adb_subtype; + int adb_subtype; struct adbdev_state *state; if (MINOR(inode->i_rdev) > ADB_MAX_MINOR) @@ -2401,28 +2567,29 @@ return 0; } -static void adb_release(struct inode *inode, struct file *file) +static int adb_release(struct inode *inode, struct file *file) { struct adbdev_state *state = file->private_data; if (state) { + int ret; + file->private_data = NULL; - if (state->req.reply_expected && !state->req.got_reply) - if (adb_wait_reply(state, file)) - return; + if (state->req.reply_expected && !state->req.complete) + if ((ret = adb_wait_reply(state, file))) + return ret; kfree(state); } - return; + return 0; } -static int adb_lseek(struct inode *inode, struct file *file, - off_t offset, int origin) +static loff_t adb_lseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } -static int adb_read(struct inode *inode, struct file *file, - char *buf, int count) +static ssize_t adb_read(struct file *file, char *buf, + size_t count, loff_t *offset) { int ret; struct adbdev_state *state = file->private_data; @@ -2449,8 +2616,8 @@ return ret; } -static int adb_write(struct inode *inode, struct file *file, - const char *buf, int count) +static ssize_t adb_write(struct file *file, const char *buf, + size_t count, loff_t *offset) { int ret, i; struct adbdev_state *state = file->private_data; @@ -2461,7 +2628,7 @@ if (ret) return ret; - if (state->req.reply_expected && !state->req.got_reply) { + if (state->req.reply_expected && !state->req.complete) { /* A previous request is still being processed. Wait for it to finish. */ ret = adb_wait_reply(state, file); @@ -2471,7 +2638,7 @@ state->req.nbytes = count; state->req.done = adb_write_done; - state->req.got_reply = 0; + state->req.complete = 0; copy_from_user(state->req.data, buf, count); #if 0 switch (adb_hardware) { @@ -2508,7 +2675,12 @@ NULL, /* no mmap */ adb_open, NULL, /* flush */ - adb_release + adb_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ }; int adbdev_register(int subtype, struct file_operations *fops) @@ -2537,7 +2709,6 @@ printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); } - #if 0 /* old ADB device */ /* @@ -2566,7 +2737,7 @@ add_wait_queue(&adb_wait, &wait); current->state = TASK_INTERRUPTIBLE; - while (!state->req.got_reply) { + while (!state->req.complete) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; @@ -2586,9 +2757,9 @@ static void adb_write_done(struct adb_request *req) { - if (!req->got_reply) { + if (!req->complete) { req->reply_len = 0; - req->got_reply = 1; + req->complete = 1; } wake_up_interruptible(&adb_wait); } @@ -2611,7 +2782,7 @@ if (state) { file->private_data = NULL; - if (state->req.reply_expected && !state->req.got_reply) + if (state->req.reply_expected && !state->req.complete) if (adb_wait_reply(state, file)) return; kfree(state); @@ -2619,14 +2790,13 @@ return; } -static int adb_lseek(struct inode *inode, struct file *file, - off_t offset, int origin) +static int adb_lseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } -static int adb_read(struct inode *inode, struct file *file, - char *buf, int count) +static int adb_read(struct file *file, char *buf, size_t count, + loff_t *offset) { int ret; struct adbdev_state *state = file->private_data; @@ -2653,8 +2823,8 @@ return ret; } -static int adb_write(struct inode *inode, struct file *file, - const char *buf, int count) +static int adb_write(struct file *file, const char *buf, + size_t count, loff_t *offset) { int ret; struct adbdev_state *state = file->private_data; @@ -2665,7 +2835,7 @@ if (ret) return ret; - if (state->req.reply_expected && !state->req.got_reply) { + if (state->req.reply_expected && !state->req.complete) { /* A previous request is still being processed. Wait for it to finish. */ ret = adb_wait_reply(state, file); @@ -2677,7 +2847,7 @@ state->req.done = adb_write_done; memcpy_fromfs(state->req.data, buf, count); state->req.reply_expected = 1; - state->req.got_reply = 0; + state->req.complete = 0; adb_send_request(&state->req); return count; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/adb-misc.c linux/arch/m68k/mac/adb-misc.c --- v2.2.17/arch/m68k/mac/adb-misc.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/mac/adb-misc.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,145 @@ +/* + * ADB Miscellaneous stuff + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef CONFIG_ADB_NEW +#include +#else +#include +#endif +#include +#include +#include +#include + +extern void cuda_poll(void); +extern int cuda_request(struct adb_request *req, + void (*done)(struct adb_request *), + int nbytes, ...); + +/* + * Return the current time as the number of seconds since January 1, 1904. + * + * This method works for both CUDA and IIsi-style ADB. It'll probably + * work for PowerBooks too once we have PowerBook ADB working. + */ + +__u32 adb_read_time(void) +{ + volatile struct adb_request req; + __u32 time; + +#ifdef CONFIG_ADB_NEW +#ifdef CONFIG_ADB_CUDA + cuda_request((struct adb_request *) &req, NULL, + 2, CUDA_PACKET, CUDA_GET_TIME); + while (!req.complete) cuda_poll(); +#endif +#else + adb_request((struct adb_request *) &req, NULL, + 2, CUDA_PACKET, CUDA_GET_TIME); + while (!req.complete); +#endif + + time = (req.reply[3] << 24) | (req.reply[4] << 16) + | (req.reply[5] << 8) | req.reply[6]; + return time; +} + +/* + * Set the current system time + * + * This method works for both CUDA and IIsi-style ADB. It'll probably + * work for PowerBooks too once we have PowerBook ADB working. + */ + +void adb_write_time(__u32 data) +{ + volatile struct adb_request req; + +#ifdef CONFIG_ADB_NEW +#ifdef CONFIG_ADB_CUDA + cuda_request((struct adb_request *) &req, NULL, + 6, CUDA_PACKET, CUDA_SET_TIME, + (data >> 24) & 0xFF, (data >> 16) & 0xFF, + (data >> 8) & 0xFF, data & 0xFF); + while (!req.complete) cuda_poll(); +#endif +#else + adb_request((struct adb_request *) &req, NULL, + 6, CUDA_PACKET, CUDA_SET_TIME, + (data >> 24) & 0xFF, (data >> 16) & 0xFF, + (data >> 8) & 0xFF, data & 0xFF); + while (!req.complete); +#endif +} + +/* + * Initially discovered this technique in the Mach kernel of MkLinux in + * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC + * code in arch/ppc/kernel/setup.c, which also has a PMU technique for + * PowerBooks! + * + * --David Kilzer + */ + +void adb_poweroff(void) +{ + struct adb_request req; + + /* + * Print our "safe" message before we send the request + * just in case the request never returns. + */ + + printk ("It is now safe to switch off your machine.\n"); + +#ifdef CONFIG_ADB_NEW +#ifdef CONFIG_ADB_CUDA + cuda_request (&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); + for (;;) cuda_poll(); +#endif +#else + adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); + for (;;) ; +#endif +} + +/* + * Initially discovered this technique in the Mach kernel of MkLinux in + * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC + * code in arch/ppc/kernel/setup.c, which also has a PMU technique! + * --David Kilzer + * + * I suspect the MAC_ADB_CUDA code might work with other ADB types of machines + * but have no way to test this myself. --DDK + */ + +void adb_hwreset(void) +{ + struct adb_request req; + + printk ("Resetting system...\n"); + +#ifdef CONFIG_ADB_NEW +#ifdef CONFIG_ADB_CUDA + cuda_request (&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); + for (;;) cuda_poll(); +#endif +#else + adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); + for (;;) ; +#endif +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/bootparse.c linux/arch/m68k/mac/bootparse.c --- v2.2.17/arch/m68k/mac/bootparse.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/bootparse.c Fri Oct 13 23:30:47 2000 @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c --- v2.2.17/arch/m68k/mac/config.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/config.c Fri Oct 13 23:30:47 2000 @@ -37,7 +37,20 @@ #include #include -#include "via6522.h" +#include +#include +#include +#include + +/* Offset between Unix time (1970-based) and Mac time (1904-based) */ + +#define MAC_TIME_OFFSET 2082844800 + +/* + * hardware reset vector + */ + +static void (*rom_reset)(void); /* Mac bootinfo struct */ @@ -59,30 +72,20 @@ unsigned long mac_orig_videoaddr; /* Mac specific keyboard functions */ -extern int mac_keyb_init(void); -extern int mac_kbdrate(struct kbd_repeat *k); -extern void mac_kbd_leds(unsigned int leds); - -/* Mac specific irq functions */ -extern void mac_init_IRQ (void); -extern void (*mac_handlers[]) (int, void *, struct pt_regs *); -extern int mac_request_irq (unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, - void *dev_id); -extern void mac_free_irq (unsigned int irq, void *dev_id); -extern void mac_enable_irq (unsigned int); -extern void mac_disable_irq (unsigned int); -static void mac_get_model(char *model); -/*static int mac_get_hardware_list(char *buffer);*/ -extern int mac_get_irq_list (char *); +extern int mackbd_init_hw(void); +extern void mackbd_leds(unsigned int leds); /* Mac specific timer functions */ extern unsigned long mac_gettimeoffset (void); static void mac_gettod (int *, int *, int *, int *, int *, int *); static int mac_hwclk (int, struct hwclk_time *); static int mac_set_clock_mmss (unsigned long); +extern void iop_init(void); +extern void via_init(void); extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); +extern void via_flush_cache(void); +extern void oss_init(void); +extern void psc_init(void); extern void (*kd_mksound)(unsigned int, unsigned int); extern void mac_mksound(unsigned int, unsigned int); @@ -95,6 +98,18 @@ extern void mac_debug_init(void); extern void mac_debugging_long(int, long); +/* poweroff functions */ +extern void via_poweroff(void); +extern void oss_poweroff(void); +extern void adb_poweroff(void); +extern void adb_hwreset(void); + +/* pram functions */ +extern __u32 via_read_time(void); +extern void via_write_time(__u32); +extern __u32 adb_read_time(void); +extern void adb_write_time(__u32); + #ifdef CONFIG_MAGIC_SYSRQ static char mac_sysrq_xlate[128] = "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */ @@ -124,92 +139,197 @@ extern int console_loglevel; -/* - * This function translates the boot timeval into a proper date, to initialize - * the system time. +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) */ +static unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} -static void mac_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) +/* + * This function translates seconds since 1970 into a proper date. + * + * Algorithm cribbed from glibc2.1, __offtime(). + */ +#define SECS_PER_MINUTE (60) +#define SECS_PER_HOUR (SECS_PER_MINUTE * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) + +static void unmktime(unsigned long time, long offset, + int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) { - unsigned long time; - int leap, oldleap, isleap; - int mon_days[14] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 }; - - time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */ - - *minp = time / 60; - *secp = time - (*minp * 60); - time = *minp; /* minutes now */ - - *hourp = time / 60; - *minp = time - (*hourp * 60); - time = *hourp; /* hours now */ - - *dayp = time / 24; - *hourp = time - (*dayp * 24); - time = *dayp; /* days now ... */ - - /* for leap day calculation */ - *yearp = (time / 365) + 1970; /* approx. year */ - - /* leap year calculation - there's an easier way, I bet. And it's broken :-( */ - /* calculate leap days up to previous year */ - oldleap = (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400; - /* calculate leap days incl. this year */ - leap = *yearp/4 - *yearp/100 + *yearp/400; - /* this year a leap year ?? */ - isleap = (leap != oldleap); - - /* adjust days: days, excluding past leap days since epoch */ - time -= oldleap - (1970/4 - 1970/100 + 1970/400); - - /* precise year, and day in year */ - *yearp = (time / 365); /* #years since epoch */ - *dayp = time - (*yearp * 365) + 1; /* #days this year (0: Jan 1) */ - *yearp += 70; /* add epoch :-) */ - time = *dayp; - - if (isleap) /* add leap day ?? */ - mon_days[2] += 1; - - /* count the months */ - for (*monp = 1; time > mon_days[*monp]; (*monp)++) - time -= mon_days[*monp]; + /* How many days come before each month (0-12). */ + static const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + long int days, rem, y, wday, yday; + const unsigned short int *ip; + + days = time / SECS_PER_DAY; + rem = time % SECS_PER_DAY; + rem += offset; + while (rem < 0) { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) { + rem -= SECS_PER_DAY; + ++days; + } + *hourp = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + *minp = rem / SECS_PER_MINUTE; + *secp = rem % SECS_PER_MINUTE; + /* January 1, 1970 was a Thursday. */ + wday = (4 + days) % 7; /* Day in the week. Not currently used */ + if (wday < 0) wday += 7; + y = 1970; + +#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) +#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) - *dayp = time; + while (days < 0 || days >= (__isleap (y) ? 366 : 365)) + { + /* Guess a corrected year, assuming 365 days per year. */ + long int yg = y + days / 365 - (days % 365 < 0); + /* Adjust DAYS and Y to match the guessed year. */ + days -= ((yg - y) * 365 + + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (y - 1)); + y = yg; + } + *yearp = y - 1900; + yday = days; /* day in the year. Not currently used. */ + ip = __mon_yday[__isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + *monp = y; + *dayp = days + 1; /* day in the month */ return; } +/* + * Return the boot time for use in initializing the kernel clock. + * + * I'd like to read the hardware clock here but many machines read + * the PRAM through ADB, and interrupts aren't initialized when this + * is called so ADB obviously won't work. + */ + +static void mac_gettod(int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + /* Yes the GMT bias is backwards. It looks like Penguin is + screwing up the boottime it gives us... This works for me + in Canada/Eastern but it might be wrong everywhere else. */ + unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60, + yearp, monp, dayp, hourp, minp, secp); + /* For some reason this is off by one */ + *monp = *monp + 1; +} + /* - * TBI: read and write hwclock + * Read/write the hardware clock. */ -static int mac_hwclk( int op, struct hwclk_time *t ) +static int mac_hwclk(int op, struct hwclk_time *t) { - return 0; + unsigned long now; + + if (!op) { /* read */ + if (macintosh_config->adb_type == MAC_ADB_II) { + now = via_read_time(); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + now = adb_read_time(); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + now = via_read_time(); + } else { + now = MAC_TIME_OFFSET; + } + + now -= MAC_TIME_OFFSET; + + t->wday = 0; + unmktime(now, 0, + &t->year, &t->mon, &t->day, + &t->hour, &t->min, &t->sec); + } else { /* write */ + now = mktime(t->year + 1900, t->mon + 1, t->day, + t->hour, t->min, t->sec) + MAC_TIME_OFFSET; + + if (macintosh_config->adb_type == MAC_ADB_II) { + via_write_time(now); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + adb_write_time(now); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + via_write_time(now); + } + } + return 0; } /* - * TBI: set minutes/seconds in hwclock + * Set minutes/seconds in the hardware clock */ static int mac_set_clock_mmss (unsigned long nowtime) { - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + struct hwclk_time now; + + mac_hwclk(0, &now); + now.sec = nowtime % 60; + now.min = (nowtime / 60) % 60; + mac_hwclk(1, &now); - return 0; + return 0; } +#if 0 void mac_waitbut (void) { ; } +#endif extern struct consw fb_con; extern struct fb_info *mac_fb_init(long *); -extern void mac_video_setup(char *, int *); + +extern void mac_default_handler(int, void *, struct pt_regs *); void (*mac_handlers[8])(int, void *, struct pt_regs *)= { @@ -237,7 +357,7 @@ mac_bi_data.id = *data; break; case BI_MAC_VADDR: - mac_bi_data.videoaddr = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); + mac_bi_data.videoaddr = *data; break; case BI_MAC_VDEPTH: mac_bi_data.videodepth = *data; @@ -249,7 +369,8 @@ mac_bi_data.dimensions = *data; break; case BI_MAC_VLOGICAL: - mac_bi_data.videological = *data; + mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); + mac_orig_videoaddr = *data; break; case BI_MAC_SCCBASE: mac_bi_data.sccbase = *data; @@ -266,6 +387,9 @@ case BI_MAC_CPUID: mac_bi_data.cpuid = *data; break; + case BI_MAC_ROMBASE: + mac_bi_data.rombase = *data; + break; default: unknown = 1; } @@ -280,12 +404,11 @@ static void mac_cache_card_flush(int writeback) { - unsigned long flags; - save_flags(flags); + unsigned long cpu_flags; + save_flags(cpu_flags); cli(); - via_write(via2, vBufB, via_read(via2,vBufB)&~VIA2B_vMode32); - via_write(via2, vBufB, via_read(via2,vBufB)|VIA2B_vMode32); - restore_flags(flags); + via_flush_cache(); + restore_flags(cpu_flags); } __initfunc(void config_mac(void)) @@ -298,9 +421,8 @@ mac_debug_init(); mach_sched_init = mac_sched_init; - mach_keyb_init = mac_keyb_init; - mach_kbdrate = mac_kbdrate; - mach_kbd_leds = mac_kbd_leds; + mach_keyb_init = mackbd_init_hw; + mach_kbd_leds = mackbd_leds; mach_init_IRQ = mac_init_IRQ; mach_request_irq = mac_request_irq; mach_free_irq = mac_free_irq; @@ -319,11 +441,12 @@ mach_mksound = mac_mksound; #endif mach_reset = mac_reset; + mach_halt = mac_poweroff; + mach_power_off = mac_poweroff; conswitchp = &dummy_con; mach_max_dma_address = 0xffffffff; #if 0 mach_debug_init = mac_debug_init; - mach_video_setup = mac_video_setup; #endif kd_mksound = mac_mksound; #ifdef CONFIG_MAGIC_SYSRQ @@ -346,18 +469,15 @@ mac_identify(); mac_report_hardware(); - if( - /* Cache cards */ - macintosh_config->ident == MAC_MODEL_IICI|| - macintosh_config->ident == MAC_MODEL_IISI|| - macintosh_config->ident == MAC_MODEL_IICX|| - /* On board L2 cache */ - macintosh_config->ident == MAC_MODEL_IIFX) - { + /* AFAIK only the IIci takes a cache card. The IIfx has onboard + cache ... someone needs to figure out how to tell if it's on or + not. */ + if (macintosh_config->ident == MAC_MODEL_IICI + || macintosh_config->ident == MAC_MODEL_IIFX) { mach_l2_flush = mac_cache_card_flush; } - /* goes on forever if timers broken */ #ifdef MAC_DEBUG_SOUND + /* goes on forever if timers broken */ mac_mksound(1000,10); #endif @@ -365,7 +485,9 @@ * Check for machine specific fixups. */ +#ifdef OLD_NUBUS_CODE nubus_sweep_video(); +#endif } @@ -403,10 +525,11 @@ * The IIfx apparently has different ADB hardware, and stuff * so zany nobody knows how to drive it. * Even so, with Marten's help we'll try to deal with it :-) + * CSA: see http://developer.apple.com/technotes/hw/hw_09.html */ { MAC_MODEL_IICI, "IIci", MAC_ADB_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_IIFX, "IIfx", MAC_ADB_II, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_IIFX, "IIfx", MAC_ADB_IOP, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_IISI, "IIsi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_IIVI, "IIvi", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_IIVX, "IIvx", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, @@ -435,70 +558,72 @@ * confuse us. The 840AV has a SCSI location of its own (same as * the 660AV). */ - + { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_Q605_ACC, "Quadra 605 (33MHz)", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, /* The Q700 does have a NS Sonic */ - { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_MACE, MAC_NUBUS}, - /* These might have IOP problems */ - { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, /* * Performa - more LC type machines */ - { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, -#if 0 /* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */ - { MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, -#endif + { MAC_MODEL_P460, "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + /* These have the comm slot, and therefore the possibility of SONIC ethernet */ + { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + /* * Centris - just guessing again; maybe like Quadra */ - { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + /* The C610 may or may not have SONIC. We probe to make sure */ + { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_MACE, MAC_NUBUS}, /* * Power books - seem similar to early Quadras ? (most have 030 though) */ - { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* The PB150 has IDE, and IIci style VIA */ - { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB190, "PowerBook 190", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + /* These have onboard SONIC */ + { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, /* * Power book Duos - similar to Power books, I hope */ - { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB280, "PowerBook Duo 280", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + /* All of these might have onboard SONIC in the Dock but I'm not quite sure */ + { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB280, "PowerBook Duo 280", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* * Other stuff ?? @@ -533,7 +658,8 @@ model); model = MAC_MODEL_Q800; printk("Defaulting to: Quadra800, model id %d\n", model); - printk("Please report this case to linux-mac68k@wave.lm.com\n"); + printk("Please report this case to " + "linux-mac68k@mac.linux-m68k.org\n"); m=&mac_data_table[0]; while(m->ident != -1) { @@ -592,7 +718,10 @@ break; } - via_configure_base(); + iop_init(); + via_init(); + oss_init(); + psc_init(); } void mac_report_hardware(void) @@ -604,8 +733,133 @@ { strcpy(str,"Macintosh "); strcat(str, macintosh_config->name); - if(mach_l2_flush && !(via_read(via2, vBufB)&VIA2B_vCDis)) - strcat(str, "(+L2 cache)"); +} + +/* + * The power switch - yes it's software! + */ + +void mac_poweroff(void) +{ + /* + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer + */ + + if (oss_present) { + oss_poweroff(); + } else if (macintosh_config->adb_type == MAC_ADB_II) { + via_poweroff(); + } else { + adb_poweroff(); + } +} + +/* + * Not all Macs support software power down; for the rest, just + * try the ROM reset vector ... + */ +void mac_reset(void) +{ + /* + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer + */ + + if (macintosh_config->adb_type == MAC_ADB_II) { + unsigned long cpu_flags; + + /* need ROMBASE in booter */ + /* indeed, plus need to MAP THE ROM !! */ + + if (mac_bi_data.rombase == 0) + mac_bi_data.rombase = 0x40800000; + + /* works on some */ + rom_reset = (void *) (mac_bi_data.rombase + 0xa); + + if (macintosh_config->ident == MAC_MODEL_SE30) { + /* + * MSch: Machines known to crash on ROM reset ... + */ + printk("System halted.\n"); + while(1); + } else { + save_flags(cpu_flags); + cli(); + + rom_reset(); + + restore_flags(cpu_flags); + } + + /* We never make it this far... it usually panics above. */ + printk ("Restart failed. Please restart manually.\n"); + + /* XXX - delay do we need to spin here ? */ + while(1); /* Just in case .. */ + } else if (macintosh_config->adb_type == MAC_ADB_IISI + || macintosh_config->adb_type == MAC_ADB_CUDA) { + adb_hwreset(); + } else if (CPU_IS_030) { + + /* 030-specific reset routine. The idea is general, but the + * specific registers to reset are '030-specific. Until I + * have a non-030 machine, I can't test anything else. + * -- C. Scott Ananian + */ + + unsigned long rombase = 0x40000000; + + /* make a 1-to-1 mapping, using the transparent tran. reg. */ + unsigned long virt = (unsigned long) mac_reset; + unsigned long phys = virt_to_phys(mac_reset); + unsigned long offset = phys-virt; + cli(); /* lets not screw this up, ok? */ + __asm__ __volatile__(".chip 68030\n\t" + "pmove %0,%/tt0\n\t" + ".chip 68k" + : : "m" ((phys&0xFF000000)|0x8777)); + /* Now jump to physical address so we can disable MMU */ + __asm__ __volatile__( + ".chip 68030\n\t" + "lea %/pc@(1f),%/a0\n\t" + "addl %0,%/a0\n\t"/* fixup target address and stack ptr */ + "addl %0,%/sp\n\t" + "pflusha\n\t" + "jmp %/a0@\n\t" /* jump into physical memory */ + "0:.long 0\n\t" /* a constant zero. */ + /* OK. Now reset everything and jump to reset vector. */ + "1:\n\t" + "lea %/pc@(0b),%/a0\n\t" + "pmove %/a0@, %/tc\n\t" /* disable mmu */ + "pmove %/a0@, %/tt0\n\t" /* disable tt0 */ + "pmove %/a0@, %/tt1\n\t" /* disable tt1 */ + "movel #0, %/a0\n\t" + "movec %/a0, %/vbr\n\t" /* clear vector base register */ + "movec %/a0, %/cacr\n\t" /* disable caches */ + "movel #0x0808,%/a0\n\t" + "movec %/a0, %/cacr\n\t" /* flush i&d caches */ + "movew #0x2700,%/sr\n\t" /* set up status register */ + "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */ + "movec %/a0, %/isp\n\t" + "movel %1@(0x4),%/a0\n\t" /* load reset vector */ + "reset\n\t" /* reset external devices */ + "jmp %/a0@\n\t" /* jump to the reset vector */ + ".chip 68k" + : : "r" (offset), "a" (rombase) : "a0"); + + /* should never get here */ + sti(); /* sure, why not */ + printk ("030 Restart failed. Please restart manually.\n"); + while(1); + } else { + /* We never make it here... The above shoule handle all cases. */ + printk ("Restart failed. Please restart manually.\n"); + + /* XXX - delay do we need to spin here ? */ + while(1); /* Just in case .. */ + } } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c --- v2.2.17/arch/m68k/mac/debug.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/debug.c Fri Oct 13 23:30:47 2000 @@ -243,7 +243,7 @@ } } -#ifdef CONFIG_SERIAL_CONSOLE +#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_SERIAL) int mac_sccb_console_wait_key(struct console *co) { int i; @@ -384,6 +384,16 @@ mac_SCC_init_done = 1; } #endif /* DEBUG_SERIAL */ + +void mac_init_scca_port( int cflag ) +{ + mac_init_scc_port(cflag, 0); +} + +void mac_init_sccb_port( int cflag ) +{ + mac_init_scc_port(cflag, 1); +} __initfunc(void mac_debug_init(void)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/iop.c linux/arch/m68k/mac/iop.c --- v2.2.17/arch/m68k/mac/iop.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/mac/iop.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,720 @@ +/* + * I/O Processor (IOP) management + * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice and this list of conditions. + * 2. Redistributions in binary form must reproduce the above copyright + * notice and this list of conditions in the documentation and/or other + * materials provided with the distribution. + */ + +/* + * The IOP chips are used in the IIfx and some Quadras (900, 950) to manage + * serial and ADB. They are actually a 6502 processor and some glue logic. + * + * 990429 (jmt) - Initial implementation, just enough to knock the SCC IOP + * into compatible mode so nobody has to fiddle with the + * Serial Switch control panel anymore. + * 990603 (jmt) - Added code to grab the correct ISM IOP interrupt for OSS + * and non-OSS machines (at least I hope it's correct on a + * non-OSS machine -- someone with a Q900 or Q950 needs to + * check this.) + * 990605 (jmt) - Rearranged things a bit wrt IOP detection; iop_present is + * gone, IOP base addresses are now in an array and the + * globally-visible functions take an IOP number instead of an + * an actual base address. + * 990610 (jmt) - Finished the message passing framework and it seems to work. + * Sending _definately_ works; my adb-bus.c mods can send + * messages and receive the MSG_COMPLETED status back from the + * IOP. The trick now is figuring out the message formats. + * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a + * receive channel were never properly acknowledged. Bracketed + * the remaining debug printk's with #ifdef's and disabled + * debugging. I can now type on the console. + * 990612 (jmt) - Copyright notice added. Reworked the way replies are handled. + * It turns out that replies are placed back in the send buffer + * for that channel; messages on the receive channels are always + * unsolicited messages from the IOP (and our replies to them + * should go back in the receive channel.) Also added tracking + * of device names to the listener functions ala the interrupt + * handlers. + * 990729 (jmt) - Added passing of pt_regs structure to IOP handlers. This is + * used by the new unified ADB driver. + * + * TODO: + * + * o Something should be periodically checking iop_alive() to make sure the + * IOP hasn't died. + * o Some of the IOP manager routines need better error checking and + * return codes. Nothing major, just prettying up. + */ + +/* + * ----------------------- + * IOP Message Passing 101 + * ----------------------- + * + * The host talks to the IOPs using a rather simple message-passing scheme via + * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each + * channel is conneced to a specific software driver on the IOP. For example + * on the SCC IOP there is one channel for each serial port. Each channel has + * an incoming and and outgoing message queue with a depth of one. + * + * A message is 32 bytes plus a state byte for the channel (MSG_IDLE, MSG_NEW, + * MSG_RCVD, MSG_COMPLETE). To send a message you copy the message into the + * buffer, set the state to MSG_NEW and signal the IOP by setting the IRQ flag + * in the IOP control to 1. The IOP will move the state to MSG_RCVD when it + * receives the message and then to MSG_COMPLETE when the message processing + * has completed. It is the host's responsibility at that point to read the + * reply back out of the send channel buffer and reset the channel state back + * to MSG_IDLE. + * + * To receive message from the IOP the same procedure is used except the roles + * are reversed. That is, the IOP puts message in the channel with a state of + * MSG_NEW, and the host receives the message and move its state to MSG_RCVD + * and then to MSG_COMPLETE when processing is completed and the reply (if any) + * has been placed back in the receive channel. The IOP will then reset the + * channel state to MSG_IDLE. + * + * Two sets of host interrupts are provided, INT0 and INT1. Both appear on one + * interrupt level; they are distinguished by a pair of bits in the IOP status + * register. The IOP will raise INT0 when one or more messages in the send + * channels have gone to the MSG_COMPLETE state and it will raise INT1 when one + * or more messages on the receive channels have gone to the MSG_NEW state. + * + * Since each channel handles only one message we have to implement a small + * interrupt-driven queue on our end. Messages to e sent are placed on the + * queue for sending and contain a pointer to an optional callback function. + * The handler for a message is called when the message state goes to + * MSG_COMPLETE. + * + * For receiving message we maintain a list of handler functions to call when + * a message is received on that IOP/channel combination. The handlers are + * called much like an interrupt handler and are passed a copy of the message + * from the IOP. The message state will be in MSG_RCVD while the handler runs; + * it is the handler's responsibility to call iop_complete_message() when + * finished; this function moves the message state to MSG_COMPLETE and signals + * the IOP. This two-step process is provided to allow the handler to defer + * message processing to a bottom-half handler if the processing will take + * a signifigant amount of time (handlers are called at interrupt time so they + * should execute quickly.) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/*#define DEBUG_IOP*/ + +/* Set to nonezero if the IOPs are present. Set by iop_init() */ + +int iop_scc_present,iop_ism_present; + +#ifdef CONFIG_PROC_FS + +/* + * sneaky reuse of the PROC_MAC_VIA inode. It's not needed by via.c + * anymore so we'll use it to debut the IOPs. + */ + +int iop_get_proc_info(char *, char **, off_t, int, int); + +static struct proc_dir_entry proc_mac_iop = { + PROC_MAC_VIA, 7, "mac_iop", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + &iop_get_proc_info +}; + +#endif /* CONFIG_PROC_FS */ + +/* structure for tracking channel listeners */ + +struct listener { + const char *devname; + void (*handler)(struct iop_msg *, struct pt_regs *); +}; + +/* + * IOP structures for the two IOPs + * + * The SCC IOP controls both serial ports (A and B) as its two functions. + * The ISM IOP controls the SWIM (floppy drive) and ADB. + */ + +static volatile struct mac_iop *iop_base[NUM_IOPS]; + +/* + * IOP message queues + */ + +static struct iop_msg iop_msg_pool[NUM_IOP_MSGS]; +static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN]; +static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN]; + +void iop_ism_irq(int, void *, struct pt_regs *); + +extern void oss_irq_enable(int); + +/* + * Private access functions + */ + +static __inline__ void iop_loadaddr(volatile struct mac_iop *iop, __u16 addr) +{ + iop->ram_addr_lo = addr; + iop->ram_addr_hi = addr >> 8; +} + +static __inline__ __u8 iop_readb(volatile struct mac_iop *iop, __u16 addr) +{ + iop->ram_addr_lo = addr; + iop->ram_addr_hi = addr >> 8; + return iop->ram_data; +} + +static __inline__ void iop_writeb(volatile struct mac_iop *iop, __u16 addr, __u8 data) +{ + iop->ram_addr_lo = addr; + iop->ram_addr_hi = addr >> 8; + iop->ram_data = data; +} + +static __inline__ void iop_stop(volatile struct mac_iop *iop) +{ + iop->status_ctrl &= ~IOP_RUN; +} + +static __inline__ void iop_start(volatile struct mac_iop *iop) +{ + iop->status_ctrl = IOP_RUN | IOP_AUTOINC; +} + +static __inline__ void iop_bypass(volatile struct mac_iop *iop) +{ + iop->status_ctrl |= IOP_BYPASS; +} + +static __inline__ void iop_interrupt(volatile struct mac_iop *iop) +{ + iop->status_ctrl |= IOP_IRQ; +} + +static int iop_alive(volatile struct mac_iop *iop) +{ + int retval; + + retval = (iop_readb(iop, IOP_ADDR_ALIVE) == 0xFF); + iop_writeb(iop, IOP_ADDR_ALIVE, 0); + return retval; +} + +static struct iop_msg *iop_alloc_msg(void) +{ + int i; + ulong cpu_flags; + + save_flags(cpu_flags); + cli(); + + for (i = 0 ; i < NUM_IOP_MSGS ; i++) { + if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) { + iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING; + restore_flags(cpu_flags); + return &iop_msg_pool[i]; + } + } + + restore_flags(cpu_flags); + return NULL; +} + +static void iop_free_msg(struct iop_msg *msg) +{ + msg->status = IOP_MSGSTATUS_UNUSED; +} + +/* + * Initialize the IOPs, if present. + */ + +__initfunc(void iop_init(void)) +{ + int i; + long tmp = 0; + volatile long *iop_bogon = &tmp; + + if (macintosh_config->scc_type == MAC_SCC_IOP) { + if (macintosh_config->ident == MAC_MODEL_IIFX) { + iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_IIFX; + } else { + iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_QUADRA; + } + + iop_scc_present = 1; + + printk("IOP: detected SCC IOP at %p\n", iop_base[IOP_NUM_SCC]); + iop_base[IOP_NUM_SCC]->status_ctrl = 0; + iop_bypass(iop_base[IOP_NUM_SCC]); + } else { + iop_base[IOP_NUM_SCC] = NULL; + iop_scc_present = 0; + } + if (macintosh_config->adb_type == MAC_ADB_IOP) { + if (macintosh_config->ident == MAC_MODEL_IIFX) { + iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_IIFX; + } else { + iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA; + } + iop_ism_present = 1; + + printk("IOP: detected ISM IOP at %p\n", iop_base[IOP_NUM_ISM]); + iop_base[IOP_NUM_SCC]->status_ctrl = 0; + for (i = 0 ; i < 16; i++) { + *iop_bogon = *iop_bogon; + } + iop_start(iop_base[IOP_NUM_ISM]); + iop_alive(iop_base[IOP_NUM_ISM]); /* clears the alive flag */ + } else { + iop_base[IOP_NUM_ISM] = NULL; + iop_ism_present = 0; + } + + /* Make the whole pool available and empty the queues */ + + for (i = 0 ; i < NUM_IOP_MSGS ; i++) { + iop_msg_pool[i].status = IOP_MSGSTATUS_UNUSED; + } + + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + iop_send_queue[IOP_NUM_SCC][i] = 0; + iop_send_queue[IOP_NUM_ISM][i] = 0; + iop_listeners[IOP_NUM_SCC][i].devname = NULL; + iop_listeners[IOP_NUM_SCC][i].handler = NULL; + iop_listeners[IOP_NUM_ISM][i].devname = NULL; + iop_listeners[IOP_NUM_ISM][i].handler = NULL; + } + +#ifdef CONFIG_PROC_FS + proc_register(&proc_root, &proc_mac_iop); +#endif +} + +/* + * Register the interrupt handler for the IOPs. + * TODO: might be wrong for non-OSS machines. Anyone? + */ + +__initfunc(void iop_register_interrupts(void)) +{ + if (iop_ism_present) { + if (oss_present) { + sys_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, + IRQ_FLG_LOCK, "ISM IOP", + (void *) IOP_NUM_ISM); + oss_irq_enable(IRQ_MAC_ADB); + } else { + request_irq(IRQ_VIA2_0, iop_ism_irq, + IRQ_FLG_LOCK|IRQ_FLG_FAST, "ISM IOP", + (void *) IOP_NUM_ISM); + } + if (!iop_alive(iop_base[IOP_NUM_ISM])) { + printk("IOP: oh my god, they killed the ISM IOP!\n"); + } else { + printk("IOP: the ISM IOP seems to be alive.\n"); + } + } +} + +/* + * Register or unregister a listener for a specific IOP and channel + * + * If the handler pointer is NULL the current listener (if any) is + * unregistered. Otherwise the new listener is registered provided + * there is no existing listener registered. + */ + +int iop_listen(uint iop_num, uint chan, + void (*handler)(struct iop_msg *, struct pt_regs *), + const char *devname) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; + if (chan >= NUM_IOP_CHAN) return -EINVAL; + if (iop_listeners[iop_num][chan].handler && handler) return -EINVAL; + iop_listeners[iop_num][chan].devname = devname; + iop_listeners[iop_num][chan].handler = handler; + return 0; +} + +/* + * Complete reception of a message, which just means copying the reply + * into the buffer, setting the channel state to MSG_COMPLETE and + * notifying the IOP. + */ + +void iop_complete_message(struct iop_msg *msg) +{ + int iop_num = msg->iop_num; + int chan = msg->channel; + int i,offset; + +#ifdef DEBUG_IOP + printk("iop_complete(%p): iop %d chan %d\n", msg, msg->iop_num, msg->channel); +#endif + + offset = IOP_ADDR_RECV_MSG + (msg->channel * IOP_MSG_LEN); + + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + iop_writeb(iop_base[iop_num], offset, msg->reply[i]); + } + + iop_writeb(iop_base[iop_num], + IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE); + iop_interrupt(iop_base[msg->iop_num]); + + iop_free_msg(msg); +} + +/* + * Actually put a message into a send channel buffer + */ + +static void iop_do_send(struct iop_msg *msg) +{ + volatile struct mac_iop *iop = iop_base[msg->iop_num]; + int i,offset; + + offset = IOP_ADDR_SEND_MSG + (msg->channel * IOP_MSG_LEN); + + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + iop_writeb(iop, offset, msg->message[i]); + } + + iop_writeb(iop, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW); + + iop_interrupt(iop); +} + +/* + * Handle sending a message on a channel that + * has gone into the IOP_MSG_COMPLETE state. + */ + +static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs) +{ + volatile struct mac_iop *iop = iop_base[iop_num]; + struct iop_msg *msg,*msg2; + int i,offset; + +#ifdef DEBUG_IOP + printk("iop_handle_send: iop %d channel %d\n", iop_num, chan); +#endif + + iop_writeb(iop, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE); + + if (!(msg = iop_send_queue[iop_num][chan])) return; + + msg->status = IOP_MSGSTATUS_COMPLETE; + offset = IOP_ADDR_SEND_MSG + (chan * IOP_MSG_LEN); + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + msg->reply[i] = iop_readb(iop, offset); + } + if (msg->handler) (*msg->handler)(msg, regs); + msg2 = msg; + msg = msg->next; + iop_free_msg(msg2); + + iop_send_queue[iop_num][chan] = msg; + if (msg) iop_do_send(msg); +} + +/* + * Handle reception of a message on a channel that has + * gone into the IOP_MSG_NEW state. + */ + +static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs) +{ + volatile struct mac_iop *iop = iop_base[iop_num]; + int i,offset; + struct iop_msg *msg; + +#ifdef DEBUG_IOP + printk("iop_handle_recv: iop %d channel %d\n", iop_num, chan); +#endif + + msg = iop_alloc_msg(); + msg->iop_num = iop_num; + msg->channel = chan; + msg->status = IOP_MSGSTATUS_UNSOL; + msg->handler = iop_listeners[iop_num][chan].handler; + + offset = IOP_ADDR_RECV_MSG + (chan * IOP_MSG_LEN); + + for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { + msg->message[i] = iop_readb(iop, offset); + } + + iop_writeb(iop, IOP_ADDR_RECV_STATE + chan, IOP_MSG_RCVD); + + /* If there is a listener, call it now. Otherwise complete */ + /* the message ourselves to avoid possible stalls. */ + + if (msg->handler) { + (*msg->handler)(msg, regs); + } else { +#ifdef DEBUG_IOP + printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan); + printk("iop_handle_recv:"); + for (i = 0 ; i < IOP_MSG_LEN ; i++) { + printk(" %02X", (uint) msg->message[i]); + } + printk("\n"); +#endif + iop_complete_message(msg); + } +} + +/* + * Send a message + * + * The message is placed at the end of the send queue. Afterwards if the + * channel is idle we force an immediate send of the next message in the + * queue. + */ + +int iop_send_message(uint iop_num, uint chan, void *privdata, + uint msg_len, __u8 *msg_data, + void (*handler)(struct iop_msg *, struct pt_regs *)) +{ + struct iop_msg *msg, *q; + + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; + if (chan >= NUM_IOP_CHAN) return -EINVAL; + if (msg_len > IOP_MSG_LEN) return -EINVAL; + + msg = iop_alloc_msg(); + if (!msg) return -ENOMEM; + + msg->next = NULL; + msg->status = IOP_MSGSTATUS_WAITING; + msg->iop_num = iop_num; + msg->channel = chan; + msg->caller_priv = privdata; + memcpy(msg->message, msg_data, msg_len); + msg->handler = handler; + + if (!(q = iop_send_queue[iop_num][chan])) { + iop_send_queue[iop_num][chan] = msg; + } else { + while (q->next) q = q->next; + q->next = msg; + } + + if (iop_readb(iop_base[iop_num], + IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) { + iop_do_send(msg); + } + + return 0; +} + +/* + * Upload code to the shared RAM of an IOP. + */ + +void iop_upload_code(uint iop_num, __u8 *code_start, + uint code_len, __u16 shared_ram_start) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; + + iop_loadaddr(iop_base[iop_num], shared_ram_start); + + while (code_len--) { + iop_base[iop_num]->ram_data = *code_start++; + } +} + +/* + * Download code from the shared RAM of an IOP. + */ + +void iop_download_code(uint iop_num, __u8 *code_start, + uint code_len, __u16 shared_ram_start) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; + + iop_loadaddr(iop_base[iop_num], shared_ram_start); + + while (code_len--) { + *code_start++ = iop_base[iop_num]->ram_data; + } +} + +/* + * Compare the code in the shared RAM of an IOP with a copy in system memory + * and return 0 on match or the first nonmatching system memory address on + * failure. + */ + +__u8 *iop_compare_code(uint iop_num, __u8 *code_start, + uint code_len, __u16 shared_ram_start) +{ + if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return code_start; + + iop_loadaddr(iop_base[iop_num], shared_ram_start); + + while (code_len--) { + if (*code_start != iop_base[iop_num]->ram_data) { + return code_start; + } + code_start++; + } + return (__u8 *) 0; +} + +/* + * Handle an ISM IOP interrupt + */ + +void iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + uint iop_num = (uint) dev_id; + volatile struct mac_iop *iop = iop_base[iop_num]; + int i,state; + +#ifdef DEBUG_IOP + printk("iop_ism_irq: status = %02X\n", (uint) iop->status_ctrl); +#endif + + /* INT0 indicates a state change on an outgoing message channel */ + + if (iop->status_ctrl & IOP_INT0) { + iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC; +#ifdef DEBUG_IOP + printk("iop_ism_irq: new status = %02X, send states", + (uint) iop->status_ctrl); +#endif + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + state = iop_readb(iop, IOP_ADDR_SEND_STATE + i); +#ifdef DEBUG_IOP + printk(" %02X", state); +#endif + if (state == IOP_MSG_COMPLETE) { + iop_handle_send(iop_num, i, regs); + } + } +#ifdef DEBUG_IOP + printk("\n"); +#endif + } + + if (iop->status_ctrl & IOP_INT1) { /* INT1 for incoming msgs */ + iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC; +#ifdef DEBUG_IOP + printk("iop_ism_irq: new status = %02X, recv states", + (uint) iop->status_ctrl); +#endif + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + state = iop_readb(iop, IOP_ADDR_RECV_STATE + i); +#ifdef DEBUG_IOP + printk(" %02X", state); +#endif + if (state == IOP_MSG_NEW) { + iop_handle_recv(iop_num, i, regs); + } + } +#ifdef DEBUG_IOP + printk("\n"); +#endif + } + +} + +#ifdef CONFIG_PROC_FS + +char *iop_chan_state(int state) +{ + switch(state) { + case IOP_MSG_IDLE : return "idle "; + case IOP_MSG_NEW : return "new "; + case IOP_MSG_RCVD : return "received "; + case IOP_MSG_COMPLETE : return "completed "; + default : return "unknown "; + } +} + +int iop_dump_one_iop(char *buf, int iop_num, char *iop_name) +{ + int i,len = 0; + volatile struct mac_iop *iop = iop_base[iop_num]; + + len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name); + len += sprintf(buf+len, "## send_state recv_state device\n"); + len += sprintf(buf+len, "------------------------------------------------\n"); + for (i = 0 ; i < NUM_IOP_CHAN ; i++) { + len += sprintf(buf+len, "%2d %10s %10s %s\n", i, + iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)), + iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)), + iop_listeners[iop_num][i].handler? + iop_listeners[iop_num][i].devname : ""); + + } + len += sprintf(buf+len, "\n"); + return len; +} + +int iop_get_proc_info(char *buf, char **start, off_t pos, int count, int wr) +{ + int len, cnt; + + cnt = 0; + len = sprintf(buf, "IOPs detected:\n\n"); + + if (iop_scc_present) { + len += sprintf(buf+len, "SCC IOP (%p): status %02X\n", + iop_base[IOP_NUM_SCC], + (uint) iop_base[IOP_NUM_SCC]->status_ctrl); + } + if (iop_ism_present) { + len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n", + iop_base[IOP_NUM_ISM], + (uint) iop_base[IOP_NUM_ISM]->status_ctrl); + } + + if (iop_scc_present) { + len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC"); + + } + + if (iop_ism_present) { + len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM"); + + } + + if (len >= pos) { + if (!*start) { + *start = buf + pos; + cnt = len - pos; + } else { + cnt += len; + } + } + return (count > cnt) ? cnt : count; +} +#endif /* CONFIG_PROC_FS */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/mac_ksyms.c linux/arch/m68k/mac/mac_ksyms.c --- v2.2.17/arch/m68k/mac/mac_ksyms.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/mac_ksyms.c Fri Oct 13 23:30:47 2000 @@ -1,7 +1,14 @@ #include #include #include + /* Hook for mouse driver */ extern void (*adb_mouse_interrupt_hook) (char *); +/* Says whether we're using A/UX interrupts or not */ +extern int via_alt_mapping; + +#ifndef CONFIG_ADB_NEW EXPORT_SYMBOL(adb_mouse_interrupt_hook); +#endif +EXPORT_SYMBOL(via_alt_mapping); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/mac_penguin.S linux/arch/m68k/mac/mac_penguin.S --- v2.2.17/arch/m68k/mac/mac_penguin.S Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/mac/mac_penguin.S Fri Oct 13 23:36:54 2000 @@ -0,0 +1,75 @@ +.byte \ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0xFF,0x0F,0xF0,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x00,0xFF,0xFF,0x0F,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0xFF,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x0F,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x0F,0xF0,0x00,0x00,0xFF,0xF0,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0xF0,0xFF,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x00,\ +0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0xF0,0x00,0x00,\ +0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ +0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,\ +0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,\ +0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,\ +0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/macboing.c linux/arch/m68k/mac/macboing.c --- v2.2.17/arch/m68k/mac/macboing.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/macboing.c Fri Oct 13 23:30:47 2000 @@ -91,14 +91,8 @@ mac_special_bell = mac_quadra_start_bell; mac_asc_samplespersec = 22150; break; - case MAC_MODEL_Q650: - case MAC_MODEL_Q700: - case MAC_MODEL_Q800: - case MAC_MODEL_Q900: - case MAC_MODEL_Q950: - /* - * Currently not implemented! - */ + case MAC_MODEL_C660: + case MAC_MODEL_Q840: /* * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. * It appears to be similar to the "AWACS" custom ASIC in the Power Mac @@ -126,6 +120,22 @@ */ mac_special_bell = mac_av_start_bell; break; + case MAC_MODEL_Q650: + case MAC_MODEL_Q700: + case MAC_MODEL_Q800: + case MAC_MODEL_Q900: + case MAC_MODEL_Q950: + /* + * Currently not implemented! + */ + mac_special_bell = NULL; + break; + default: + /* + * Every switch needs a default + */ + mac_special_bell = NULL; + break; } /* @@ -154,6 +164,12 @@ __u32 cfreq = ( freq << 5 ) / 468; __u32 flags; int i; + + if ( mac_special_bell == NULL ) + { + /* Do nothing */ + return; + } if ( !mac_asc_inited ) mac_init_asc(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c --- v2.2.17/arch/m68k/mac/macints.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/macints.c Fri Oct 13 23:30:47 2000 @@ -7,8 +7,8 @@ * interrupts with exception vectors 0x19-0x1f). The following interrupt levels * are used: * 1 - VIA1 - * - slot 0: one second interrupt - * - slot 1: VBlank + * - slot 0: one second interrupt (CA2) + * - slot 1: VBlank (CA1) * - slot 2: ADB data ready (SR full) * - slot 3: ADB data (CB2) * - slot 4: ADB clock (CB1) @@ -16,57 +16,103 @@ * - slot 6: timer 1 * - slot 7: status of IRQ; signals 'any enabled int.' * - * 2 - VIA2, RBV or OSS - * - slot 0: SCSI DRQ - * - slot 1: NUBUS IRQ - * - slot 3: SCSI IRQ - * - * 4 - SCC - * - subdivided into Channel B and Channel A interrupts - * - * 6 - Off switch (??) - * - * 7 - Debug output - * - * AV Macs only, handled by PSC: - * - * 3 - MACE ethernet IRQ (DMA complete on level 4) - * - * 5 - DSP ?? - * - * Using the autovector irq numbers for Linux/m68k hardware interrupts without - * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt - * handling in kernel versions 2.0.x, so the following strategy is used: - * - * - mac_init_IRQ installs the low-level entry points for the via1 and via2 - * exception vectors and the corresponding handlers (C functions); these - * entry points just add the machspec bit and call the handlers proper. - * (in principle, the C functions can be installed as the exception vectors - * directly, as they are hardcoded anyway; that's the current method). - * - * - via[12]_irq determine what interrupt sources have triggered the interrupt, - * and call the corresponding device interrupt handlers. - * (currently, via1_irq and via2_irq just call via_irq, passing the via base - * address. RBV interrupts are handled by (you guessed it) rbv_irq). - * Some interrupt functions want to have the interrupt number passed, so - * via_irq and rbv_irq need to generate the 'fake' numbers from scratch. - * - * - for the request/free/enable/disable business, interrupt sources are - * numbered internally (suggestion: keep irq 0-7 unused :-). One bit in the - * irq number specifies the via# to use, i.e. via1 interrupts are 8-16, - * via2 interrupts 17-32, rbv interrupts ... - * The device interrupt table and the irq_enable bitmap is maintained by - * the machspec interrupt code; all device drivers should only use these - * functions ! - * - * - For future porting to version 2.1 (and removing of the machspec bit) it - * should be sufficient to use the same numbers (everything > 7 is assumed - * to be machspec, according to Jes!). + * 2 - VIA2 or RBV + * - slot 0: SCSI DRQ (CA2) + * - slot 1: NUBUS IRQ (CA1) need to read port A to find which + * - slot 2: /EXP IRQ (only on IIci) + * - slot 3: SCSI IRQ (CB2) + * - slot 4: ASC IRQ (CB1) + * - slot 5: timer 2 (not on IIci) + * - slot 6: timer 1 (not on IIci) + * - slot 7: status of IRQ; signals 'any enabled int.' + * + * 2 - OSS (IIfx only?) + * - slot 0: SCSI interrupt + * - slot 1: Sound interrupt + * + * Levels 3-6 vary by machine type. For VIA or RBV Macintohes: + * + * 3 - unused (?) + * + * 4 - SCC (slot number determined by reading RR3 on the SSC itself) + * - slot 0: SCC channel A + * - slot 1: SCC channel B + * + * 5 - unused (?) + * [serial errors or special conditions seem to raise level 6 + * interrupts on some models (LC4xx?)] + * + * 6 - off switch (?) + * + * For OSS Macintoshes (IIfx only at this point): + * + * 3 - Nubus interrupt + * - slot 0: Slot $9 + * - slot 1: Slot $A + * - slot 2: Slot $B + * - slot 3: Slot $C + * - slot 4: Slot $D + * - slot 5: Slot $E + * + * 4 - SCC IOP + * - slot 0: SCC channel A + * - slot 1: SCC channel B + * + * 5 - ISM IOP (ADB?) + * + * 6 - unused + * + * For PSC Macintoshes (660AV, 840AV): + * + * 3 - PSC level 3 + * - slot 0: MACE + * + * 4 - PSC level 4 + * - slot 1: SCC channel A interrupt + * - slot 2: SCC channel B interrupt + * - slot 3: MACE DMA + * + * 5 - PSC level 5 + * + * 6 - PSC level 6 + * + * Finally we have good 'ole level 7, the non-maskable interrupt: + * + * 7 - NMI (programmer's switch on the back of some Macs) + * Also RAM parity error on models which support it (IIc, IIfx?) + * + * The current interrupt logic looks something like this: + * + * - We install dispatchers for the autovector interrupts (1-7). These + * dispatchers are responsible for querying the hardware (the + * VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using + * this information a machspec interrupt number is generated by placing the + * index of the interrupt hardware into the low three bits and the original + * autovector interrupt number in the upper 5 bits. The handlers for the + * resulting machspec interrupt are then called. + * + * - Nubus is a special case because its interrupts are hidden behind two + * layers of hardware. Nubus interrupts come in as index 1 on VIA #2, + * which translates to IRQ number 17. In this spot we install _another_ + * dispatcher. This dispatcher finds the interrupting slot number (9-F) and + * then forms a new machspec interrupt number as above with the slot number + * minus 9 in the low three bits and the pseudo-level 7 in the upper five + * bits. The handlers for this new machspec interrupt number are then + * called. This puts Nubus interrupts into the range 56-62. + * + * - We support "fast" and "slow" handlers, just like the Amiga port. The + * fast handlers are called first and with all interrupts disabled. They + * are expected to execute quickly (hence the name). The slow handlers are + * called last with interrupts enabled and the interrupt level restored. + * They must therefore be reentrant. + * + * - Drivers should never try to request autovector interrupt numbers. It + * won't work. * * TODO: - * - integrate Nubus interrupts in request/free_irq * - * - + * o Perhaps build some intelligence into mac_SCC_handler(); we could check + * the SCC ourselves and only call the handler for the appopriate channel. */ #include @@ -82,124 +128,61 @@ #include #include #include -#include "via6522.h" +#include +#include #include /* - * Interrupt handler and parameter types + * The mac_irq_list array is an array of linked lists of irq_node_t nodes. + * Each node contains one handler to be called whenever the interrupt + * occurs, with fast handlers listed before slow handlers. */ -struct irqhandler { - void (*handler)(int, void *, struct pt_regs *); - void *dev_id; -}; - -struct irqparam { - unsigned long flags; - const char *devname; -}; - -struct irqflags { - unsigned int disabled; - unsigned int pending; -}; -/* - * Array with irq's and their parameter data. - */ -static struct irqhandler via1_handler[8]; -static struct irqhandler via2_handler[8]; -static struct irqhandler rbv_handler[8]; -static struct irqhandler psc3_handler[8]; -static struct irqhandler scc_handler[8]; -static struct irqhandler psc5_handler[8]; -static struct irqhandler psc6_handler[8]; -static struct irqhandler nubus_handler[8]; - -static struct irqhandler *handler_table[8]; +irq_node_t *mac_irq_list[NUM_MAC_SOURCES]; /* - * This array hold the rest of parameters of int handlers: type - * (slow,fast,prio) and the name of the handler. These values are only - * accessed from C + * VIA/RBV hooks */ -static struct irqparam via1_param[8]; -static struct irqparam via2_param[8]; -static struct irqparam rbv_param[8]; -static struct irqparam psc3_param[8]; -static struct irqparam scc_param[8]; -static struct irqparam psc5_param[8]; -static struct irqparam psc6_param[8]; -static struct irqparam nubus_param[8]; -static struct irqparam *param_table[8]; +extern void via_init(void); +extern void via_register_interrupts(void); +extern void via_irq_enable(int); +extern void via_irq_disable(int); +extern void via_irq_clear(int); +extern int via_irq_pending(int); /* - * This array holds the 'disabled' and 'pending' software flags maintained - * by mac_{enable,disable}_irq and the generic via_irq function. + * OSS hooks */ -static struct irqflags irq_flags[8]; +extern int oss_present; -/* - * This array holds the pointers to the various VIA or other interrupt - * controllers, indexed by interrupt level - */ - -static volatile unsigned char *via_table[8]; - -/* - * Arrays with irq statistics - */ -static unsigned long via1_irqs[8]; -static unsigned long via2_irqs[8]; -static unsigned long rbv_irqs[8]; -static unsigned long psc3_irqs[8]; -static unsigned long scc_irqs[8]; -static unsigned long psc5_irqs[8]; -static unsigned long psc6_irqs[8]; -static unsigned long nubus_irqs[8]; - -static unsigned long *mac_irqs[8]; - -/* - * Some special nutcases ... - */ - -static unsigned long mac_ide_irqs = 0; -static unsigned long nubus_stuck_events = 0; +extern void oss_init(void); +extern void oss_register_interrupts(void); +extern void oss_irq_enable(int); +extern void oss_irq_disable(int); +extern void oss_irq_clear(int); +extern int oss_irq_pending(int); /* - * VIA/RBV/OSS/PSC register base pointers + * PSC hooks */ -volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS; -volatile unsigned char *rbv_regp=(volatile unsigned char *)VIA2_BAS_IIci; -volatile unsigned char *oss_regp=(volatile unsigned char *)OSS_BAS; -volatile unsigned char *psc_regp=(volatile unsigned char *)PSC_BAS; - -/* - * Flags to control via2 / rbv behaviour - */ - -static int via2_is_rbv = 0; -static int via2_is_oss = 0; -static int rbv_clear = 0; - -/* fake VIA2 to OSS bit mapping */ -static int oss_map[8] = {2, 7, 0, 1, 3, 4, 5}; +extern int psc_present; -void oss_irq(int irq, void *dev_id, struct pt_regs *regs); -static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs); - -/* PSC ints */ -void psc_irq(int irq, void *dev_id, struct pt_regs *regs); +extern void psc_init(void); +extern void psc_register_interrupts(void); +extern void psc_irq_enable(int); +extern void psc_irq_disable(int); +extern void psc_irq_clear(int); +extern int psc_irq_pending(int); /* - * PSC hooks + * IOP hooks */ -extern void psc_init(void); +extern void iop_register_interrupts(void); /* * console_loglevel determines NMI handler function @@ -207,640 +190,401 @@ extern int console_loglevel; -/* - * ADB test hooks - */ -extern int in_keybinit; -void adb_queue_poll(void); - -/* Defined in entry.S; only increments 'num_spurious' */ -asmlinkage void bad_interrupt(void); +extern void mac_bang(int, void *, struct pt_regs *); -void nubus_wtf(int slot, void *via, struct pt_regs *regs); - -void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *regs); -void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs); - -static void via_do_nubus(int slot, void *via, struct pt_regs *regs); +void mac_nmi_handler(int, void *, struct pt_regs *); +void mac_debug_handler(int, void *, struct pt_regs *); +void mac_SCC_handler(int, void *, struct pt_regs *); /* #define DEBUG_MACINTS */ -#define DEBUG_SPURIOUS -#define DEBUG_NUBUS_SPURIOUS -#define DEBUG_NUBUS_INT - -/* #define DEBUG_VIA */ -#define DEBUG_VIA_NUBUS - void mac_init_IRQ(void) { int i; #ifdef DEBUG_MACINTS - printk("Mac interrupt stuff initializing ...\n"); + printk("mac_init_IRQ(): Setting things up...\n"); #endif + /* Initialize the IRQ handler lists. Initially each list is empty, */ - via2_regp = (unsigned char *)VIA2_BAS; - rbv_regp = (unsigned char *)VIA2_BAS_IIci; - - /* initialize the hardwired (primary, autovector) IRQs */ - - /* level 1 IRQ: VIA1, always present */ - sys_request_irq(1, via1_irq, IRQ_FLG_LOCK, "via1", via1_irq); - - /* via2 or rbv?? */ - if (macintosh_config->via_type == MAC_VIA_IIci) { - /* - * A word of caution: the definitions here only affect interrupt - * handling, see via6522.c for yet another file to change - * base addresses and RBV flags - */ - - /* yes, this is messy - the IIfx deserves a class of his own */ - if (macintosh_config->ident == MAC_MODEL_IIFX) { - /* no real VIA2, the OSS seems _very_ different */ - via2_is_oss = 1; - /* IIfx has OSS, at a different base address than RBV */ - rbv_regp = (unsigned char *) OSS_BAS; - sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq); - } else { - /* VIA2 is part of the RBV: different base, other offsets */ - via2_is_rbv = 1; - - /* LC III weirdness: IFR seems to behave like VIA2 */ - /* FIXME: maybe also for LC II ?? */ - if (macintosh_config->ident == MAC_MODEL_LCIII) { - rbv_clear = 0x0; - } else { - rbv_clear = 0x80; - } - /* level 2 IRQ: RBV/OSS; we only care about RBV for now */ - sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq); - } - } else - /* level 2 IRQ: VIA2 */ - sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq); + for (i = 0; i < NUM_MAC_SOURCES; i++) { + mac_irq_list[i] = NULL; + } /* - * level 4 IRQ: SCC - use 'master' interrupt routine that calls the - * registered channel-specific interrupts in turn. - * Currently, one interrupt per channel is used, solely - * to pass the correct async_info as parameter! + * Now register the handlers for the the master IRQ handlers + * at levels 1-7. Most of the work is done elsewhere. */ - sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler); - - /* level 6 */ - sys_request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang); - - /* level 7 (or NMI) : debug stuff */ - sys_request_irq(7, mac_nmi_handler, IRQ_FLG_STD, "NMI", mac_nmi_handler); - - /* initialize the handler tables for VIAs */ - for (i = 0; i < 8; i++) { - via1_handler[i].handler = mac_default_handler; - via1_handler[i].dev_id = NULL; - via1_param[i].flags = IRQ_FLG_STD; - via1_param[i].devname = NULL; - - via2_handler[i].handler = mac_default_handler; - via2_handler[i].dev_id = NULL; - via2_param[i].flags = IRQ_FLG_STD; - via2_param[i].devname = NULL; - - rbv_handler[i].handler = mac_default_handler; - rbv_handler[i].dev_id = NULL; - rbv_param[i].flags = IRQ_FLG_STD; - rbv_param[i].devname = NULL; - - scc_handler[i].handler = mac_default_handler; - scc_handler[i].dev_id = NULL; - scc_param[i].flags = IRQ_FLG_STD; - scc_param[i].devname = NULL; - - /* NUBUS interrupts routed through VIA2 slot 2 - special */ - nubus_handler[i].handler = nubus_wtf; - nubus_handler[i].dev_id = NULL; - nubus_param[i].flags = IRQ_FLG_STD; - nubus_param[i].devname = NULL; - - } - - /* initialize the handler tables (level 1 -> via_handler[0] !!!) */ - via_table[0] = via1_regp; - handler_table[0] = &via1_handler[0]; - param_table[0] = &via1_param[0]; - mac_irqs[0] = &via1_irqs[0]; - - if (via2_is_rbv || via2_is_oss) { - via_table[1] = rbv_regp; - handler_table[1] = &rbv_handler[0]; - param_table[1] = &rbv_param[0]; - mac_irqs[1] = &rbv_irqs[0]; + if (oss_present) { + oss_register_interrupts(); } else { - via_table[1] = via2_regp; - handler_table[1] = &via2_handler[0]; - param_table[1] = &via2_param[0]; - mac_irqs[1] = &via2_irqs[0]; + via_register_interrupts(); } - via_table[2] = NULL; - via_table[3] = NULL; - - handler_table[2] = &rbv_handler[0]; - handler_table[3] = &scc_handler[0]; - handler_table[4] = NULL; - handler_table[5] = NULL; - handler_table[6] = NULL; - handler_table[7] = &nubus_handler[0]; - - param_table[2] = &rbv_param[0]; - param_table[3] = &scc_param[0]; - param_table[7] = &nubus_param[0]; - - mac_irqs[2] = &rbv_irqs[0]; - mac_irqs[3] = &scc_irqs[0]; - mac_irqs[7] = &nubus_irqs[0]; - - /* - * Nubus Macs: turn off the Nubus dispatch interrupt for now - */ - - mac_turnoff_irq(IRQ_MAC_NUBUS); - - /* - * AV Macs: shutup the PSC ints - */ - if (macintosh_config->ident == MAC_MODEL_C660 - || macintosh_config->ident == MAC_MODEL_Q840) - { - psc_init(); - - handler_table[2] = &psc3_handler[0]; - /* handler_table[3] = &psc4_handler[0]; */ - handler_table[4] = &psc5_handler[0]; - handler_table[5] = &psc6_handler[0]; - - param_table[2] = &psc3_param[0]; - /* param_table[3] = &psc4_param[0]; */ - param_table[4] = &psc5_param[0]; - param_table[5] = &psc6_param[0]; - - mac_irqs[2] = &psc3_irqs[0]; - /* mac_irqs[3] = &psc4_irqs[0]; */ - mac_irqs[4] = &psc5_irqs[0]; - mac_irqs[5] = &psc6_irqs[0]; - - sys_request_irq(3, psc_irq, IRQ_FLG_STD, "PSC3", psc_irq); - sys_request_irq(4, psc_irq, IRQ_FLG_STD, "PSC4", psc_irq); - sys_request_irq(5, psc_irq, IRQ_FLG_STD, "PSC5", psc_irq); - sys_request_irq(6, psc_irq, IRQ_FLG_STD, "PSC6", psc_irq); - } - + if (psc_present) psc_register_interrupts(); + iop_register_interrupts(); + sys_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler); #ifdef DEBUG_MACINTS - printk("Mac interrupt init done!\n"); + printk("mac_init_IRQ(): Done!\n"); #endif } /* - * We have no machine specific interrupts on a macintoy - * Yet, we need to register/unregister interrupts ... :-) - * Currently unimplemented: Test for valid irq number, chained irqs, - * Nubus interrupts (use nubus_request_irq!). + * Routines to work with irq_node_t's on linked lists lifted from + * the Amiga code written by Roman Zippel. */ - -int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) + +static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node) { - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - struct irqhandler *via_handler; - struct irqparam *via_param; - volatile unsigned char *via; + unsigned long cpu_flags; + irq_node_t *cur; -#ifdef DEBUG_MACINTS - printk ("%s: IRQ %d on VIA%d[%d] requested from %s\n", - __FUNCTION__, irq, srcidx+1, irqidx, devname); -#endif + if (!node->dev_id) + printk("%s: Warning: dev_id of %s is zero\n", + __FUNCTION__, node->devname); - if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) { - printk ("%s: Bad irq type %ld requested from %s\n", - __FUNCTION__, flags, devname); - return -EINVAL; - } + save_flags(cpu_flags); + cli(); - /* figure out what VIA is handling this irq */ - if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) { - /* non-via irqs unimplemented */ - printk ("%s: Bad irq source %d on VIA %d requested from %s\n", - __FUNCTION__, irq, srcidx, devname); - return -EINVAL; - } - - /* figure out if SCC pseudo-irq (redundant ??) */ - if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) { - /* set specific SCC handler */ - scc_handler[irqidx].handler = handler; - scc_handler[irqidx].dev_id = dev_id; - scc_param[irqidx].flags = flags; - scc_param[irqidx].devname = devname; - /* and done! */ - return 0; - } + cur = *list; - /* - * code below: only for VIA irqs currently - * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq - */ - via = (volatile unsigned char *) via_table[srcidx]; - if (!via) - return -EINVAL; - - via_handler = handler_table[srcidx]; - via_param = param_table[srcidx]; - - /* check for conflicts or possible replacement */ - - /* set the handler - no chained irqs yet !! */ - via_handler[irqidx].handler = handler; - via_handler[irqidx].dev_id = dev_id; - via_param[irqidx].flags = flags; - via_param[irqidx].devname = devname; - - /* and turn it on ... careful, that's VIA only ... */ - if (srcidx == SRC_VIA2 && via2_is_rbv) - via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); - else if (srcidx == SRC_VIA2 && via2_is_oss) - via_write(oss_regp, oss_map[irqidx]+8, 2); - else - via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); - - - if (irq == IRQ_IDX(IRQ_MAC_SCSI)) { - /* - * Set vPCR for SCSI interrupts. (what about RBV here?) - * 980429 MS: RBV is ok, OSS seems to be different - */ - if (!via2_is_oss) - if (macintosh_config->scsi_type == MAC_SCSI_OLD) { - /* CB2 (IRQ) indep. interrupt input, positive edge */ - /* CA2 (DRQ) indep. interrupt input, positive edge */ - via_write(via, vPCR, 0x66); - } else { - /* CB2 (IRQ) indep. interrupt input, negative edge */ - /* CA2 (DRQ) indep. interrupt input, negative edge */ - via_write(via, vPCR, 0x22); - } -#if 0 - else - /* CB2 (IRQ) indep. interrupt input, negative edge */ - /* CA2 (DRQ) indep. interrupt input, negative edge */ - via_write(via, vPCR, 0x22); -#endif + if (node->flags & IRQ_FLG_FAST) { + node->flags &= ~IRQ_FLG_SLOW; + while (cur && cur->flags & IRQ_FLG_FAST) { + list = &cur->next; + cur = cur->next; + } + } else if (node->flags & IRQ_FLG_SLOW) { + while (cur) { + list = &cur->next; + cur = cur->next; + } + } else { + while (cur && !(cur->flags & IRQ_FLG_SLOW)) { + list = &cur->next; + cur = cur->next; + } } - return 0; + node->next = cur; + *list = node; + + restore_flags(cpu_flags); } - -void mac_free_irq (unsigned int irq, void *dev_id) + +static inline void mac_delete_irq(irq_node_t **list, void *dev_id) { - unsigned long flags; - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - struct irqhandler *via_handler; - struct irqparam *via_param; - volatile unsigned char *via; + unsigned long cpu_flags; + irq_node_t *node; -#ifdef DEBUG_MACINTS - printk ("%s: IRQ %d on VIA%d[%d] freed\n", - __FUNCTION__, irq, srcidx+1, irqidx); -#endif + save_flags(cpu_flags); + cli(); - /* figure out what VIA is handling this irq */ - if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) { - /* non-via irqs unimplemented */ - return; - } + for (node = *list; node; list = &node->next, node = *list) { + if (node->dev_id == dev_id) { + *list = node->next; + /* Mark it as free. */ + node->handler = NULL; + restore_flags(cpu_flags); + return; + } + } + restore_flags(cpu_flags); + printk ("%s: tried to remove invalid irq\n", __FUNCTION__); +} - save_flags(flags); - cli(); +/* + * Call all the handlers for a given interrupt. Fast handlers are called + * first followed by slow handlers. + * + * This code taken from the original Amiga code written by Roman Zippel. + */ - /* figure out if SCC pseudo-irq */ - if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) { - /* clear specific SCC handler */ - scc_handler[irqidx].handler = mac_default_handler; - scc_handler[irqidx].dev_id = NULL; - scc_param[irqidx].flags = IRQ_FLG_STD; - scc_param[irqidx].devname = NULL; - /* and done! */ - restore_flags(flags); - return; - } +void mac_do_irq_list(int irq, struct pt_regs *fp) +{ + irq_node_t *node, *slow_nodes; + unsigned long cpu_flags; - via = (volatile unsigned char *) via_table[srcidx]; - via_handler = handler_table[srcidx]; - via_param = param_table[srcidx]; - - if ( !via || (via_handler[irqidx].dev_id != dev_id) ) { - restore_flags(flags); - goto not_found; - } + kstat.irqs[0][irq]++; - /* clear the handler - no chained irqs yet !! */ - via_handler[irqidx].handler = mac_default_handler; - via_handler[irqidx].dev_id = NULL; - via_param[irqidx].flags = IRQ_FLG_STD; - via_param[irqidx].devname = NULL; - - /* and turn it off */ - if (srcidx == SRC_VIA2 && via2_is_rbv) - via_write(via, rIER, (via_read(via, rIER)&(1< 7)) { + printk("mac_do_irq_list: spurious interrupt %d!\n", irq); + } +#endif + /* serve first fast and normal handlers */ + for (node = mac_irq_list[irq]; + node && (!(node->flags & IRQ_FLG_SLOW)); + node = node->next) + node->handler(irq, node->dev_id, fp); + if (!node) return; + save_flags(cpu_flags); + restore_flags((cpu_flags & ~0x0700) | (fp->sr & 0x0700)); + /* if slow handlers exists, serve them now */ + slow_nodes = node; + for (; node; node = node->next) { + node->handler(irq, node->dev_id, fp); + } } /* - * {en,dis}able_irq have the usual semantics of temporary blocking the - * interrupt, but not loosing requests that happen between disabling and - * enabling. On Atari, this is done with the MFP mask registers. - * - * On the Mac, this isn't possible: there is no VIA mask register. - * Needs to be implemented in software, setting 'mask' bits in a separate - * struct for each interrupt controller. These mask bits need to be checked - * by the VIA interrupt routine which should ignore requests for masked IRQs - * (after possibly ack'ing them). - * - * On second thought: some of the IRQ sources _can_ be turned off via bits - * in the VIA output registers. Need to check this ... - * - * TBI: According to the VIA docs, clearing a bit in the IER has the effect of - * blocking generation of the interrupt, but the internal interrupt condition - * is preserved. So the IER might be used as mask register here, and turnon_irq - * would need to clear the interrupt bit in the IFR to prevent getting an - * interrupt at all. - * - * Implementation note: the irq no's here are the _machspec_ irqs, hence the - * hack with srcidx to figure out which VIA/RBV handles the interrupt. - * That's fundamentally different when it comes to the interrupt handlers - * proper: these get the interrupt level no. as argument, all information about - * which source triggered the int. is buried in the VIA IFR ... The int. level - * points us to the proper handler, so we could do a sanity check there ... + * mac_enable_irq - enable an interrupt source + * mac_disable_irq - disable an interrupt source + * mac_clear_irq - clears a pending interrupt + * mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending) + * + * These routines are just dispatchers to the VIA/OSS/PSC routines. */ void mac_enable_irq (unsigned int irq) { - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - - irq_flags[srcidx].disabled &= ~(1<>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); + switch(IRQ_SRC(irq)) { + case 1: via_irq_disable(irq); + break; + case 2: + case 7: + if (oss_present) { + oss_irq_disable(irq); + } else { + via_irq_disable(irq); + } + break; + case 3: + case 4: + case 5: + case 6: if (psc_present) { + psc_irq_disable(irq); + } else if (oss_present) { + oss_irq_disable(irq); + } + break; + } +} - irq_flags[srcidx].disabled |= (1<>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - volatile unsigned char *via; + irq_node_t *node; - via = (volatile unsigned char *) via_table[srcidx]; - if (!via) - return; +#ifdef DEBUG_MACINTS + printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname); +#endif - if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */ - via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); - else if (srcidx == SRC_VIA2 && via2_is_oss) /* OSS */ - via_write(oss_regp, oss_map[irqidx]+8, 2); - else if (srcidx > SRC_VIA2) /* hope AVs have VIA2 */ - via_write(via, (0x104 + 0x10*srcidx), - via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx))); - else /* VIA1+2 */ - via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); + if (irq < VIA1_SOURCE_BASE) { + return sys_request_irq(irq, handler, flags, devname, dev_id); + } -} + if (irq >= NUM_MAC_SOURCES) { + printk ("%s: unknown irq %d requested by %s\n", + __FUNCTION__, irq, devname); + } -void mac_turnoff_irq( unsigned int irq ) -{ - int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); - volatile unsigned char *via; + /* Get a node and stick it onto the right list */ - via = (volatile unsigned char *) via_table[srcidx]; - if (!via) - return; + if (!(node = new_irq_node())) return -ENOMEM; - if (srcidx == SRC_VIA2 && via2_is_rbv) /* RBV as VIA2 */ - via_write(via, rIER, (via_read(via, rIER)&(1< SRC_VIA2) - via_write(via, (0x104 + 0x10*srcidx), - via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx))); - else /* VIA1+2 */ - via_write(via, vIER, (via_read(via, vIER)&(1<handler = handler; + node->flags = flags; + node->dev_id = dev_id; + node->devname = devname; + node->next = NULL; + mac_insert_irq(&mac_irq_list[irq], node); -/* - * These functions currently only handle the software-maintained irq pending - * list for disabled irqs - manipulating the actual irq flags in the via would - * require clearing single bits in the via, such as (probably) - * via_write(via, vIFR, (via_read(via, vIFR)&(1<>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); + mac_enable_irq(irq); - irq_flags[srcidx].pending &= ~(1<>3) - 1; - int irqidx = (irq & IRQ_IDX_MASK); + if (irq < VIA1_SOURCE_BASE) { + return sys_free_irq(irq, dev_id); + } + + if (irq >= NUM_MAC_SOURCES) { + printk ("%s: unknown irq %d freed\n", + __FUNCTION__, irq); + return; + } - pending = irq_flags[srcidx].pending & (1< SRC_VIA2) - pending |= via_read(via, (0x100 + 0x10*srcidx))&(1<>3) - 1; - irqidx = (i & IRQ_IDX_MASK); - - /* - * Not present: skip - */ - - if (mac_irqs[srcidx] == NULL) - continue; - - /* - * never used by VIAs, unused by others so far, counts - * the magic 'nothing pending' cases ... - */ - if (irqidx == 7 && mac_irqs[srcidx][irqidx]) { - len += sprintf(buf+len, "Level %01d: %10lu (spurious) \n", - srcidx, - mac_irqs[srcidx][irqidx]); - continue; - } + /* Don't do Nubus interrupts in this loop; we do them separately */ + /* below so that we can print slot numbers instead of IRQ numbers */ - /* - * Nothing registered for this IPL: skip - */ - - if (handler_table[srcidx] == NULL) - continue; - - /* - * No handler installed: skip - */ - - if (handler_table[srcidx][irqidx].handler == mac_default_handler || - handler_table[srcidx][irqidx].handler == nubus_wtf) - continue; - - - if (i < VIA2_SOURCE_BASE) - len += sprintf(buf+len, "via1 %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else if (i < RBV_SOURCE_BASE) - len += sprintf(buf+len, "via2 %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else if (i < MAC_SCC_SOURCE_BASE) - len += sprintf(buf+len, "rbv %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else if (i < NUBUS_SOURCE_BASE) - len += sprintf(buf+len, "scc %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); - else /* Nubus */ - len += sprintf(buf+len, "nubus %01d: %10lu ", - irqidx, - mac_irqs[srcidx][irqidx]); + for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) { - len += sprintf(buf+len, "%s\n", - param_table[srcidx][irqidx].devname); + /* Nonexistant interrupt or nothing registered; skip it. */ - } - if (num_spurious) - len += sprintf(buf+len, "spurio.: %10u\n", num_spurious); + if ((node = mac_irq_list[i]) == NULL) continue; + if (node->flags & IRQ_FLG_STD) continue; - /* - * XXX Fixme: Nubus sources are never logged above ... - */ - - len += sprintf(buf+len, "Nubus interrupts:\n"); - - for (i = 0; i < 7; i++) { - if (nubus_handler[i].handler == nubus_wtf) - continue; - len += sprintf(buf+len, "nubus %01X: %10lu ", - i+9, - nubus_irqs[i]); - len += sprintf(buf+len, "%s\n", - nubus_param[i].devname); + base = ""; + switch(IRQ_SRC(i)) { + case 1: base = "via1"; + break; + case 2: if (oss_present) { + base = "oss"; + } else { + base = "via2"; + } + break; + case 3: + case 4: + case 5: + case 6: if (psc_present) { + base = "psc"; + } else if (oss_present) { + base = "oss"; + } else { + if (IRQ_SRC(i) == 4) base = "scc"; + } + break; + case 7: base = "nbus"; + break; + } + len += sprintf(buf+len, "%4s %2d: %10u ", + base, i, kstat.irqs[0][i]); + + do { + if (node->flags & IRQ_FLG_FAST) { + len += sprintf(buf+len, "F "); + } else if (node->flags & IRQ_FLG_SLOW) { + len += sprintf(buf+len, "S "); + } else { + len += sprintf(buf+len, " "); + } + len += sprintf(buf+len, "%s\n", node->devname); + if ((node = node->next)) { + len += sprintf(buf+len, " "); + } + } while(node); } - len += sprintf(buf+len, "nubus spurious ints: %10lu\n", - nubus_irqs[7]); - len += sprintf(buf+len, "nubus stuck events : %10lu\n", - nubus_stuck_events); -#ifdef CONFIG_BLK_DEV_IDE - len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n", - mac_ide_irqs); -#endif - return len; } -void via_scsi_clear(void) -{ - volatile unsigned char deep_magic; - if (via2_is_rbv) { - via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80); - deep_magic = via_read(rbv_regp, rBufB); - } else if (via2_is_oss) { - /* nothing */ - /* via_write(oss_regp, 9, 0) */; - } else - deep_magic = via_read(via2_regp, vBufB); - mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) ); -} - - void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs) { #ifdef DEBUG_SPURIOUS - if (console_loglevel > 6) + if (console_loglevel > 6) { printk("Unexpected IRQ %d on device %p\n", irq, dev_id); + } #endif } @@ -854,9 +598,6 @@ } } -void scsi_mac_debug(void); -void scsi_mac_polled(void); - static int in_nmi = 0; static volatile int nmi_hold = 0; @@ -869,10 +610,6 @@ */ in_nmi++; -#if 0 - scsi_mac_debug(); - printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); -#endif for (i=0; i<100; i++) udelay(1000); @@ -889,10 +626,6 @@ while (nmi_hold == 1) udelay(1000); -#if 0 - scsi_mac_polled(); -#endif - if ( console_loglevel >= 8 ) { #if 0 show_state(); @@ -916,799 +649,12 @@ } /* - * Unexpected via interrupt - */ - -void via_wtf(int slot, void *via, struct pt_regs *regs) -{ -#ifdef DEBUG_SPURIOUS - if (console_loglevel > 6) - printk("Unexpected nubus event %d on via %p\n",slot,via); -#endif -} - -/* - * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's - * via6522.c :-), disable/pending masks added. - * The int *viaidx etc. is just to keep the prototype happy ... - */ - -static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs) -{ - unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; - int i; - int ct = 0; - struct irqhandler *via_handler = handler_table[*viaidx]; - struct irqparam *via_param = param_table[*viaidx]; - unsigned long *via_irqs = mac_irqs[*viaidx]; - - /* to be changed, possibly: for each non'masked', enabled IRQ, read - * flag bit, ack and call handler ... - * Currently: all pending irqs ack'ed en bloc. - * If ack for masked IRQ required: keep 'pending' info separate. - */ - - /* shouldn't we disable interrupts here ?? */ - - - /* - * Shouldnt happen - */ - - if(events==0) - { -#ifdef DEBUG_VIA - /* should go away; mostly missing timer ticks and ADB events */ - printk("via%d_irq: nothing pending, flags %x mask %x!\n", - *viaidx + 1, via_read(via, vIFR), via_read(via,vIER)); -#endif - via_irqs[7]++; - return; - } - -#ifdef DEBUG_VIA - /* - * limited verbosity for VIA interrupts - */ -#if 0 - if ( (*viaidx == 0 && events != 1<<6) /* timer int */ - || (*viaidx == 1 && events != 1<<3) ) /* SCSI IRQ */ -#else - if ( *viaidx == 0 && (events & 1<<2) ) -#endif - printk("via_irq: irq %d events %x !\n", (*viaidx)+1, events); -#endif - - do { - /* - * Clear the pending flag - */ - - via_write(via, vIFR, events); - - /* - * Now see what bits are raised - */ - - for(i=0;i<7;i++) - { - /* determine machspec. irq no. */ - int irq = ((*viaidx)+1)* 8 + i; - /* call corresponding handlers */ - if (events&(1< mark pending */ - irq_flags[*viaidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[*viaidx].pending & (1<8) - { -#ifdef DEBUG_VIA - printk("via%d: stuck events %x\n", (*viaidx)+1, events); -#endif - break; - } - } - while(events); -#if 0 - scsi_mac_polled(); -#endif -} - -/* - * Caution: the following stuff is called from process_int as _autovector_ - * system interrupts. So irq is always in the range 0-7 :-( and the selection - * of the appropriate VIA is up to the irq handler here based on the autovec - * irq number. There's no information whatsoever about which source on the VIA - * triggered the int - and that's what the machspec irq no's are about. - * Broken design :-(((( - */ - -/* - * System interrupts - */ - -void via1_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; - via_irq((unsigned char *)via1_regp, &srcidx, regs); -} - - -/* - * Nubus / SCSI interrupts, VIA style (could be wrapped into via1_irq or - * via_irq directly by selecting the regp based on the irq!) - */ - -void via2_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; - via_irq((unsigned char *)via2_regp, &srcidx, regs); -} - -/* - * Nubus / SCSI interrupts; RBV style - * The RBV is different. RBV appears to stand for randomly broken - * VIA (or even real broken VIA). - */ - -void rbv_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; /* MUST be 1 !! */ - volatile unsigned char *via = rbv_regp; - unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F; - int i; - int ct = 0; - struct irqhandler *via_handler = handler_table[srcidx]; - struct irqparam *via_param = param_table[srcidx]; - - /* shouldn't we disable interrupts here ?? */ - - - /* - * Shouldnt happen - */ - - if(events==0) - { -#ifdef DEBUG_VIA - printk("rbv_irq: nothing pending, flags %x mask %x!\n", - via_read(via, rIFR), via_read(via,rIER)); -#endif - rbv_irqs[7]++; - return; - } - -#ifdef DEBUG_VIA - /* - * limited verbosity for RBV interrupts (add more if needed) - */ - if ( srcidx == 1 && events != 1<<3 ) /* SCSI IRQ */ - printk("rbv_irq: irq %d (%d) events %x !\n", irq, srcidx+1, events); -#endif - - /* to be changed, possibly: for each non'masked', enabled IRQ, read - * flag bit, ack and call handler ... - * Currently: all pending irqs ack'ed en bloc. - * If ack for masked IRQ required: keep 'pending' info separate. - */ - - do { - /* - * Clear the pending flag - */ - - via_write(via, rIFR, events | rbv_clear); - - /* - * Now see what bits are raised - */ - - for(i=0;i<7;i++) - { - /* determine machspec. irq no. */ - int irq = (srcidx+1)* 8 + i; - /* call corresponding handlers */ - if (events&(1< mark pending */ - irq_flags[srcidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[srcidx].pending & (1<8) - { - printk("rbv: stuck events %x\n",events); - for(i=0;i<7;i++) - { - if(events&(1< mark pending */ - irq_flags[srcidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[srcidx].pending & (1<8) - { - printk("oss: stuck events %x\n",events); - for(i=0;i<7;i++) - { - if(events&(1< 6) - printk("Unexpected interrupt on nubus slot %d\n",slot); -#endif -} - -/* * SCC master interrupt handler; sole purpose: pass the registered * async struct to the SCC handler proper. */ void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs) { - int i; - /* 1+2: compatibility with PSC ! */ - for (i = 1; i < 3; i++) /* currently only these two used */ - if (scc_handler[i].handler != mac_default_handler) { - (scc_handler[i].handler)(i, scc_handler[i].dev_id, regs); - scc_irqs[i]++; - } -} - -/* - * PSC interrupt handler - */ - -void psc_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - int srcidx = IRQ_IDX(irq) - 1; - volatile unsigned char *via = psc_regp; - unsigned int pIFR = 0x100 + 0x10*srcidx; - unsigned int pIER = 0x104 + 0x10*srcidx; - unsigned char events=(via_read(via, pIFR)&via_read(via,pIER))&0xF; - int i; - int ct = 0; - struct irqhandler *via_handler = handler_table[srcidx]; - struct irqparam *via_param = param_table[srcidx]; - - /* shouldn't we disable interrupts here ?? */ - - - /* - * Shouldnt happen - */ - - if(events==0) - { -#ifdef DEBUG_VIA - printk("psc_irq: nothing pending, flags %x mask %x!\n", - via_read(via, pIFR), via_read(via,pIER)); -#endif - mac_irqs[srcidx][7]++; - return; - } - -#ifdef DEBUG_VIA - /* - * limited verbosity for PSC interrupts (add more if needed) - */ - if ( srcidx == 1 && events != 1<<3 && events != 1<<1 ) /* SCSI IRQ */ - printk("psc_irq: irq %d srcidx+1 %d events %x !\n", irq, srcidx+1, events); -#endif - - /* to be changed, possibly: for each non'masked', enabled IRQ, read - * flag bit, ack and call handler ... - * Currently: all pending irqs ack'ed en bloc. - * If ack for masked IRQ required: keep 'pending' info separate. - */ - - do { - /* - * Clear the pending flag - */ - - /* via_write(via, pIFR, events); */ - - /* - * Now see what bits are raised - */ - - for(i=0;i<7;i++) - { - /* determine machspec. irq no. */ - int irq = (srcidx+1)* 8 + i; - /* call corresponding handlers */ - if (events&(1< mark pending */ - irq_flags[srcidx].pending |= (1< call handler */ - (via_handler[i].handler)(irq, via, regs); - } - } - /* and call handlers for pending irqs - first ?? */ - if ( (irq_flags[srcidx].pending & (1<8) - { - printk("psc: stuck events %x\n",events); - for(i=0;i<7;i++) - { - if(events&(1< 5) - printk("nubus_irq: nothing pending, map %x mask %x active %x\n", - allints, nubus_active, map); -#endif - nubus_irqs[7]++; - } - /* clear it */ - if (allints) - if (via2_is_rbv) - via_write(rbv_regp, rIFR, 0x02); - else - via_write(via2_regp, vIFR, 0x02); - break; - } - -#ifdef DEBUG_VIA_NUBUS - if (console_loglevel > 6) - printk("nubus_irq: map %x mask %x active %x\n", - allints, nubus_active, map); -#endif - -#ifdef CONFIG_BLK_DEV_MAC_IDE - if (mac_ide_intr_hook && ide_pending) { - mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs); - mac_ide_irqs++; - } -#endif - - if(ct++>2) - { - if (console_loglevel > 5) - printk("nubus stuck events - %x/%x/%x ide %x\n", - allints, nubus_active, map, ide_pending); - nubus_stuck_events++; - - return; - } - - for(i=0;i<7;i++) - { - if(map&(1<2) - { -#if 0 - printk("nubus stuck events - %d/%d\n", map, nubus_active); -#endif - return; - } - - for(i=0;i<7;i++) - { - if(map&(1< hide this as function in arch/m68k/mac ? - * Current emulation buttons: right alt/option and control - * (wanted: command and alt/option, or KP= and KP( ...) - * Debug version; might be rewritten to be faster on normal keys. */ - if (adb_emulate_buttons - && (adb_mouse_interrupt_hook || console_loglevel >= 8)) { - unsigned char button, button2, button3, fake_event; - static unsigned char button2state=0, button3state=0; /* up */ + if (adb_emulate_buttons + && (keycode == adb_button2_keycode + || keycode == adb_button3_keycode) + && (adb_mouse_interrupt_hook || console_loglevel == 10)) { + int button; /* faked ADB packet */ static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 }; - button = 0; - fake_event = 0; - if (keycode == adb_button2_keycode) { /* which 'button' ? */ - /* R-option */ - button2 = (!up_flag); /* new state */ - if (button2 != button2state) /* change ? */ - button = 2; - button2state = button2; /* save state */ - fake_event = 2; - } else if (keycode == adb_button3_keycode) { - /* R-control */ - button3 = (!up_flag); /* new state */ - if (button3 != button3state) /* change ? */ - button = 3; - button3state = button3; /* save state */ - fake_event = 3; - } -#ifdef DEBUG_ADBMOUSE - if (fake_event && console_loglevel >= 8) - printk("fake event: button2 %d button3 %d button %d\n", - button2state, button3state, button); -#endif - if (button) { /* there's been a button state change */ - /* fake a mouse packet : send all bytes, change one! */ - data[button] = (up_flag ? 0x80 : 0); + button = keycode == adb_button2_keycode? 2: 3; + if (data[button] != up_flag) { + /* send a fake mouse packet */ + data[button] = up_flag; + if (console_loglevel >= 8) + printk("fake mouse event: %x %x %x\n", + data[1], data[2], data[3]); if (adb_mouse_interrupt_hook) adb_mouse_interrupt_hook(data, 4); -#ifdef DEBUG_ADBMOUSE - else - printk("mouse_fake: data %2x %2x %2x buttons %2x \n", - data[1], data[2], data[3], - ~( (data[1] & 0x80 ? 0 : 4) - | (data[2] & 0x80 ? 0 : 1) - | (data[3] & 0x80 ? 0 : 2) )&7 ); -#endif } - /* - * for mouse 3-button emulation: don't process 'fake' keys! - * Keys might autorepeat, and console state gets generally messed - * up enough so that selection stops working. - */ - if (fake_event) - return; + return; } #endif /* CONFIG_ADBMOUSE */ /* - * Convert R-shift/control/option to L version. + * This should not be done in raw mode, but basically X is + * all screwed up, so we try to make it less so by adjusting + * things. Note that this is also redundant with + * mackbd_translate() above. Either we are wrong somewhere + * or X is wrong, and I'm betting on the latter. */ switch (keycode) { case 0x7b: keycode = 0x38; break; /* R-shift */ @@ -493,16 +466,18 @@ static void mouse_input(unsigned char *data, int nb, struct pt_regs *regs) { - struct kbd_struct *kbd; - int i; +#ifdef DEBUG_ADB + if (console_loglevel == 10 && + (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG)) { + int i; - if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) { - printk("data from mouse:"); + printk(KERN_DEBUG "data from mouse:"); for (i = 0; i < nb; ++i) printk(" %x", data[i]); printk("\n"); return; } +#endif if (adb_mouse_interrupt_hook) { adb_mouse_interrupt_hook(data+2, nb-2); @@ -512,60 +487,6 @@ */ return; } -#ifdef DEBUG_ADBMOUSE - else - if (console_loglevel >= 8) - printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", - data[3], data[4], data[5], - ~((data[3] & 0x80 ? 0 : 4) - | (data[4] & 0x80 ? 0 : 1) - | (data[5] & 0x80 ? 0 : 2))&7, - ((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ), - ((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) ); -#endif - - - kbd = kbd_table + fg_console; - -#if 0 /* The entirely insane way of MkLinux handling mouse input */ - /* Requires put_queue which is static in keyboard.c :-( */ - /* Only send mouse codes when keyboard is in raw mode. */ - if (kbd->kbdmode == VC_RAW) { - static unsigned char uch_ButtonStateSecond = 0; - unsigned char uchButtonSecond; - - /* Send first button, second button and movement. */ - put_queue( 0x7e ); - put_queue( data[3] ); - put_queue( data[4] ); - - /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ - - /* Store the button state. */ - uchButtonSecond = (data[4] & 0x80); - - /* Send second button. */ - if (uchButtonSecond != uch_ButtonStateSecond) { - put_queue( 0x3f | uchButtonSecond ); - uch_ButtonStateSecond = uchButtonSecond; - } - - /* Macintosh 3-button mouse (handler 4). */ - if ((nb == 6) && (data[1] & 0x40)) { - static unsigned char uch_ButtonStateThird = 0; - unsigned char uchButtonThird; - - /* Store the button state for speed. */ - uchButtonThird = (data[5] & 0x80); - - /* Send third button. */ - if (uchButtonThird != uch_ButtonStateThird) { - put_queue( 0x40 | uchButtonThird ); - uch_ButtonStateThird = uchButtonThird; - } - } - } -#endif /* insane MkLinux mouse hack */ } /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ @@ -582,13 +503,11 @@ static int leds_pending; -void mac_kbd_leds(unsigned int leds) +void mackbd_leds(unsigned int leds) { - if (led_request.got_reply) { -#ifdef DEBUG_ADB + if (led_request.complete) { if (console_loglevel == 10) - printk("mac_kbd_leds: got reply, sending request!\n"); -#endif + printk(KERN_DEBUG "mackbd_leds: got reply, sending request!\n"); adb_request(&led_request, mac_leds_done, 4, ADB_PACKET, ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~mac_ledmap[leds]); @@ -603,20 +522,15 @@ if (leds_pending) { leds = leds_pending & 0xff; leds_pending = 0; - mac_kbd_leds(leds); + mackbd_leds(leds); } mark_bh(KEYBOARD_BH); } -int mac_kbdrate(struct kbd_repeat *k) +__initfunc(int mackbd_init_hw(void)) { - return 0; -} - -__initfunc(int mac_keyb_init(void)) -{ - static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req; - volatile int ct; + static struct adb_request autopoll_req, confcod_req; + int ct; /* setup key map */ memcpy(key_maps[0], mac_plain_map, sizeof(plain_map)); @@ -629,12 +543,7 @@ /* initialize mouse interrupt hook */ adb_mouse_interrupt_hook = NULL; - - /* - * Might put that someplace else, possibly .... - */ - adb_bus_init(); - + /* the input functions ... */ adb_register(ADB_KEYBOARD, keyboard_input); adb_register(ADB_MOUSE, mouse_input); @@ -653,17 +562,13 @@ */ if (macintosh_config->adb_type == MAC_ADB_CUDA) { - printk("CUDA autopoll on ...\n"); + printk(KERN_DEBUG "CUDA autopoll on ...\n"); adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); - ct=0; - while (!autopoll_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("Keyboard timed out.\n"); - autopoll_req.got_reply = 1; - } + ct = 0; + while (!autopoll_req.complete && ct++ < 1000) + adb_poll(); + if (ct == 1000) printk(KERN_ERR "ADB timeout\n"); + autopoll_req.complete = 1; } /* @@ -671,15 +576,15 @@ * care of that for other Macs. */ - printk("Configuring keyboard:\n"); - - udelay(3000); + printk(KERN_DEBUG "Configuring keyboard:\n"); + /* Aarrrgggh! Die in hell! */ + udelay(8000); /* * turn on all leds - the keyboard driver will turn them back off - * via mac_kbd_leds if everything works ok! + * via mackbd_leds if everything works ok! */ - printk("leds on ...\n"); + printk(KERN_DEBUG "leds on ...\n"); adb_request(&led_request, NULL, 4, ADB_PACKET, ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7); @@ -687,19 +592,13 @@ * The polling stuff should go away as soon as the ADB driver is stable */ ct = 0; - while (!led_request.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("keyboard timed out.\n"); - led_request.got_reply = 1; - } + while (!led_request.complete && ct++ < 1000) + adb_poll(); + if (ct == 1000) printk(KERN_ERR "ADB timeout\n"); + led_request.complete = 1; -#if 1 - printk("configuring coding mode ...\n"); - - udelay(3000); + printk(KERN_DEBUG "configuring coding mode ...\n"); + udelay(8000); /* * get the keyboard to send separate codes for @@ -707,56 +606,15 @@ */ adb_request(&confcod_req, NULL, 4, ADB_PACKET, ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); - - ct=0; - while (!confcod_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("keyboard timed out.\n"); - confcod_req.got_reply = 1; - } -#endif - -#if 0 /* seems to hurt, at least Geert's Mac */ - printk("Configuring mouse (3-button mode) ...\n"); - - udelay(3000); - - /* - * XXX: taken from the PPC driver again ... - * Try to switch the mouse (id 3) to handler 4, for three-button - * mode. (0x20 is Service Request Enable, 0x03 is Device ID). - */ - adb_request(&mouse_req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); - - ct=0; - while (!mouse_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) - printk("Mouse timed out.\n"); -#endif - -#if 0 - printk("Start polling keyboard ...\n"); - - /* - * get the keyboard to send data back, via the adb_input hook - * XXX: was never used properly, and the driver takes care - * of polling and timeout retransmits now. - * Might be of use if we want to start talking to a specific - * device here... - */ - adb_request(&readkey_req, NULL, 2, ADB_PACKET, - ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG)); -#endif + ct = 0; + while (!confcod_req.complete && ct++ < 1000) + adb_poll(); + if (ct == 1000) printk(KERN_ERR "ADB timeout\n"); + confcod_req.complete = 1; in_keybinit = 0; - printk("keyboard init done\n"); + printk(KERN_DEBUG "keyboard init done\n"); + udelay(8000); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/oss.c linux/arch/m68k/mac/oss.c --- v2.2.17/arch/m68k/mac/oss.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/mac/oss.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,314 @@ +/* + * OSS handling + * Written by Joshua M. Thompson (funaho@jurai.org) + * + * + * This chip is used in the IIfx in place of VIA #2. It acts like a fancy + * VIA chip with prorammable interrupt levels. + * + * 990502 (jmt) - Major rewrite for new interrupt architecture as well as some + * recent insights into OSS operational details. + * 990610 (jmt) - Now taking fulll advantage of the OSS. Interrupts are mapped + * to mostly match the A/UX interrupt scheme supported on the + * VIA side. Also added support for enabling the ISM irq again + * since we now have a functional IOP manager. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int oss_present; +volatile struct mac_oss *oss; + +void oss_irq(int, void *, struct pt_regs *); +void oss_nubus_irq(int, void *, struct pt_regs *); + +extern void via1_irq(int, void *, struct pt_regs *); +extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern int console_loglevel; + +/* + * Initialize the OSS + * + * The OSS "detection" code is actually in via_init() which is always called + * before us. Thus we can count on oss_present being valid on entry. + */ + +__initfunc(void oss_init(void)) +{ + int i; + + if (!oss_present) return; + + oss = (struct mac_oss *) OSS_BASE; + + /* Disable all interrupts. Unlike a VIA it looks like we */ + /* do this by setting the source's interrupt level to zero. */ + + for (i = 0; i <= OSS_NUM_SOURCES; i++) { + oss->irq_level[i] = OSS_IRQLEV_DISABLED; + } + /* If we disable VIA1 here, we never really handle it... */ + oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1; +} + +/* + * Register the OSS and NuBus interrupt dispatchers. + */ + +__initfunc(void oss_register_interrupts(void)) +{ + sys_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, + "OSS SCSI Dispatch", (void *) oss); + sys_request_irq(OSS_IRQLEV_IOPSCC, mac_SCC_handler, IRQ_FLG_LOCK, + "SCC Dispatch", mac_SCC_handler); + sys_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, + "Nubus Dispatch", (void *) oss); + sys_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, + "OSS Sound Dispatch", (void *) oss); + sys_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, + "VIA1 Dispatch", (void *) via1); +} + +/* + * Initialize OSS for Nubus access + */ + +__initfunc(void oss_nubus_init(void)) +{ +} + +/* + * Turn off the power via the ROM control register + * + * FIXME: not sure how this is supposed to work exactly... + */ + +void oss_poweroff(void) +{ + oss->rom_ctrl = OSS_POWEROFF; + + /* We should never make it this far... */ + + printk ("It is now safe to switch off your machine.\n"); + while(1); +} + +/* + * Handle miscellaneous OSS interrupts. Right now that's just sound + * and SCSI; everything else is routed to its own autovector IRQ. + */ + +void oss_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int events; + + events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI); + if (!events) return; + +#ifdef DEBUG_IRQS + if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) { + printk("oss_irq: irq %d events = 0x%04X\n", irq, + (int) oss->irq_pending); + } +#endif + /* FIXME: how do you clear a pending IRQ? */ + + if (events & OSS_IP_SOUND) { + oss->irq_pending &= ~OSS_IP_SOUND; + /* FIXME: call sound handler */ + } else if (events & OSS_IP_SCSI) { + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; + oss->irq_pending &= ~OSS_IP_SCSI; + mac_do_irq_list(IRQ_MAC_SCSI, regs); + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; + } else { + /* FIXME: error check here? */ + } +} + +/* + * Nubus IRQ handler, OSS style + * + * Unlike the VIA/RBV this is on its own autovector interupt level. + */ + +void oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int events, irq_bit, i; + + events = oss->irq_pending & OSS_IP_NUBUS; + if (!events) return; + +#ifdef DEBUG_NUBUS_INT + if (console_loglevel > 7) { + printk("oss_nubus_irq: events = 0x%04X\n", events); + } +#endif + /* There are only six slots on the OSS, not seven */ + + for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + oss->irq_level[i] = OSS_IRQLEV_DISABLED; + oss->irq_pending &= ~irq_bit; + mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs); + oss->irq_level[i] = OSS_IRQLEV_NUBUS; + } + } +} + +/* + * Enable an OSS interrupt + * + * It looks messy but it's rather straightforward. The switch() statement + * just maps the machspec interrupt numbers to the right OSS interrupt + * source (if the OSS handles that interrupt) and then sets the interrupt + * level for that source to nonzero, thus enabling the interrupt. + */ + +void oss_irq_enable(int irq) { +#ifdef DEBUG_IRQUSE + printk("oss_irq_enable(%d)\n", irq); +#endif + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC; + break; + case IRQ_MAC_ADB: + oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM; + break; + case IRQ_MAC_SCSI: + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + oss->irq_level[irq] = OSS_IRQLEV_NUBUS; + break; +#ifdef DEBUG_IRQUSE + default: + printk("%s unknown irq %d\n",__FUNCTION__, irq); + break; +#endif + } +} + +/* + * Disable an OSS interrupt + * + * Same as above except we set the source's interrupt level to zero, + * to disable the interrupt. + */ + +void oss_irq_disable(int irq) { +#ifdef DEBUG_IRQUSE + printk("oss_irq_disable(%d)\n", irq); +#endif + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_DISABLED; + break; + case IRQ_MAC_ADB: + oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_DISABLED; + break; + case IRQ_MAC_SCSI: + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + oss->irq_level[irq] = OSS_IRQLEV_DISABLED; + break; +#ifdef DEBUG_IRQUSE + default: + printk("%s unknown irq %d\n", __FUNCTION__, irq); + break; +#endif + } +} + +/* + * Clear an OSS interrupt + * + * Not sure if this works or not but it's the only method I could + * think of based on the contents of the mac_oss structure. + */ + +void oss_irq_clear(int irq) { + /* FIXME: how to do this on OSS? */ + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + oss->irq_pending &= ~OSS_IP_IOPSCC; + break; + case IRQ_MAC_ADB: + oss->irq_pending &= ~OSS_IP_IOPISM; + break; + case IRQ_MAC_SCSI: + oss->irq_pending &= ~OSS_IP_SCSI; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + oss->irq_pending &= ~(1 << irq); + break; + } +} + +/* + * Check to see if a specific OSS interrupt is pending + */ + +int oss_irq_pending(int irq) +{ + switch(irq) { + case IRQ_SCC: + case IRQ_SCCA: + case IRQ_SCCB: + return oss->irq_pending & OSS_IP_IOPSCC; + break; + case IRQ_MAC_ADB: + return oss->irq_pending & OSS_IP_IOPISM; + break; + case IRQ_MAC_SCSI: + return oss->irq_pending & OSS_IP_SCSI; + break; + case IRQ_NUBUS_9: + case IRQ_NUBUS_A: + case IRQ_NUBUS_B: + case IRQ_NUBUS_C: + case IRQ_NUBUS_D: + case IRQ_NUBUS_E: + irq -= NUBUS_SOURCE_BASE; + return oss->irq_pending & (1 << irq); + break; + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/psc.c linux/arch/m68k/mac/psc.c --- v2.2.17/arch/m68k/mac/psc.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/mac/psc.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,200 @@ +/* + * Apple Peripheral System Controller (PSC) + * + * The PSC is used on the AV Macs to control IO functions not handled + * by the VIAs (Ethernet, DSP, SCC). + * + * TO DO: + * + * Try to figure out what's going on in pIFR5 and pIFR6. There seem to be + * persisant interrupt conditions in those registers and I have no idea what + * they are. Granted it doesn't affect since we're not enabling any interrupts + * on those levels at the moment, but it would be nice to know. I have a feeling + * they aren't actually interrupt lines but data lines (to the DSP?) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG_PSC + +int psc_present; +volatile __u8 *psc; + +void psc_irq(int, void *, struct pt_regs *); + +extern int console_loglevel; + +/* + * Debugging dump, used in various places to see what's going on. + */ + +void psc_debug_dump(void) +{ + int i; + + if (!psc_present) return; + for (i = 0x30 ; i < 0x70 ; i += 0x10) { + printk("PSC #%d: IFR = 0x%02X IER = 0x%02X\n", + i >> 4, + (int) psc_read_byte(pIFRbase + i), + (int) psc_read_byte(pIERbase + i)); + } +} + +/* + * Try to kill all DMA channels on the PSC. Not sure how this his + * supposed to work; this is code lifted from macmace.c and then + * expanded to cover what I think are the other 7 channels. + */ + +void psc_dma_die_die_die(void) +{ + int i; + + printk("Killing all PSC DMA channels..."); + for (i = 0 ; i < 9 ; i++) { + psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800); + psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000); + psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100); + psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100); + } + printk("done!\n"); +} + +/* + * Initialize the PSC. For now this just involves shutting down all + * interrupt sources using the IERs. + */ + +__initfunc(void psc_init(void)) +{ + int i; + + if (macintosh_config->ident != MAC_MODEL_C660 + && macintosh_config->ident != MAC_MODEL_Q840) + { + psc = NULL; + psc_present = 0; + return; + } + + /* + * The PSC is always at the same spot, but using psc + * keeps things consisant with the psc_xxxx functions. + */ + + psc = (void *) PSC_BASE; + psc_present = 1; + + printk("PSC detected at %p\n", psc); + + psc_dma_die_die_die(); + +#ifdef DEBUG_PSC + psc_debug_dump(); +#endif + /* + * Mask and clear all possible interrupts + */ + + for (i = 0x30 ; i < 0x70 ; i += 0x10) { + psc_write_byte(pIERbase + i, 0x0F); + psc_write_byte(pIFRbase + i, 0x0F); + } +} + +/* + * Register the PSC interrupt dispatchers for autovector interrupts 3-6. + */ + +__initfunc(void psc_register_interrupts(void)) +{ + sys_request_irq(3, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x30); + sys_request_irq(4, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x40); + sys_request_irq(5, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x50); + sys_request_irq(6, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", + (void *) 0x60); +} + +/* + * PSC interrupt handler. It's a lot like the VIA interrupt handler. + */ + +void psc_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int pIFR = pIFRbase + ((int) dev_id); + int pIER = pIERbase + ((int) dev_id); + int base_irq = irq << 3; + int irq_bit,i; + unsigned char events; + +#ifdef DEBUG_IRQS + printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n", + irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER)); +#endif + + events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF; + if (!events) return; + + for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + psc_write_byte(pIER, irq_bit); + psc_write_byte(pIFR, irq_bit); + mac_do_irq_list(base_irq + i, regs); + psc_write_byte(pIER, irq_bit | 0x80); + } + } +} + +void psc_irq_enable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIER = pIERbase + (irq_src << 4); + +#ifdef DEBUG_IRQUSE + printk("psc_irq_enable(%d)\n", irq); +#endif + psc_write_byte(pIER, (1 << irq_idx) | 0x80); +} + +void psc_irq_disable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIER = pIERbase + (irq_src << 4); + +#ifdef DEBUG_IRQUSE + printk("psc_irq_disable(%d)\n", irq); +#endif + psc_write_byte(pIER, 1 << irq_idx); +} + +void psc_irq_clear(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIFR = pIERbase + (irq_src << 4); + + psc_write_byte(pIFR, 1 << irq_idx); +} + +int psc_irq_pending(int irq) +{ + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int pIFR = pIERbase + (irq_src << 4); + + return psc_read_byte(pIFR) & (1 << irq_idx); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/via.c linux/arch/m68k/mac/via.c --- v2.2.17/arch/m68k/mac/via.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/mac/via.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,788 @@ +/* + * 6522 Versatile Interface Adapter (VIA) + * + * There are two of these on the Mac II. Some IRQ's are vectored + * via them as are assorted bits and bobs - eg RTC, ADB. + * + * CSA: Motorola seems to have removed documentation on the 6522 from + * their web site; try + * http://nerini.drf.com/vectrex/other/text/chips/6522/ + * http://www.zymurgy.net/classic/vic20/vicdet1.htm + * and + * http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html + * for info. A full-text web search on 6522 AND VIA will probably also + * net some usefulness. 20apr1999 + * + * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b + * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org) + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +volatile __u8 *via1, *via2; +#if 0 +/* See note in mac_via.h about how this is possibly not useful */ +volatile long *via_memory_bogon=(long *)&via_memory_bogon; +#endif +int rbv_present,via_alt_mapping; +__u8 rbv_clear; + +/* + * Globals for accessing the VIA chip registers without having to + * check if we're hitting a real VIA or an RBV. Normally you could + * just hit the combined register (ie, vIER|rIER) but that seems to + * break on AV Macs...probably because they actually decode more than + * eight address bits. Why can't Apple engineers at least be + * _consistantly_ lazy? - 1999-05-21 (jmt) + */ + +static int gIER,gIFR,gBufA,gBufB; + +/* + * Timer defs. + */ + +#define TICK_SIZE 10000 +#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ +#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) +#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) + +static int nubus_active; + +void via_debug_dump(void); +void via1_irq(int, void *, struct pt_regs *); +void via2_irq(int, void *, struct pt_regs *); +void via_nubus_irq(int, void *, struct pt_regs *); +void via_irq_enable(int irq); +void via_irq_disable(int irq); +void via_irq_clear(int irq); + +extern void mac_bang(int, void *, struct pt_regs *); +extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern int console_loglevel; +extern int oss_present; + +/* + * Initialize the VIAs + * + * First we figure out where they actually _are_ as well as what type of + * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.) + * Then we pretty much clear them out and disable all IRQ sources. + * + * Note: the OSS is actually "detected" here and not in oss_init(). It just + * seems more logical to do it here since via_init() needs to know + * these things anyways. + */ + +__initfunc(void via_init(void)) +{ + switch(macintosh_config->via_type) { + + /* IIci, IIsi, IIvx, IIvi (P6xx), LC series */ + + case MAC_VIA_IIci: + via1 = (void *) VIA1_BASE; + if (macintosh_config->ident == MAC_MODEL_IIFX) { + via2 = NULL; + rbv_present = 0; + oss_present = 1; + } else { + via2 = (void *) RBV_BASE; + rbv_present = 1; + oss_present = 0; + } + if (macintosh_config->ident == MAC_MODEL_LCIII) { + rbv_clear = 0x00; + } else { + /* on most RBVs (& unlike the VIAs), you */ + /* need to set bit 7 when you write to IFR */ + /* in order for your clear to occur. */ + rbv_clear = 0x80; + } + gIER = rIER; + gIFR = rIFR; + gBufA = rSIFR; + gBufB = rBufB; + break; + + /* Quadra and early MacIIs agree on the VIA locations */ + + case MAC_VIA_QUADRA: + case MAC_VIA_II: + via1 = (void *) VIA1_BASE; + via2 = (void *) VIA2_BASE; + rbv_present = 0; + oss_present = 0; + rbv_clear = 0x00; + gIER = vIER; + gIFR = vIFR; + gBufA = vBufA; + gBufB = vBufB; + break; + default: + panic("UNKNOWN VIA TYPE"); + } + + printk("VIA1 at %p is a 6522 or clone\n", via1); + + printk("VIA2 at %p is ", via2); + if (rbv_present) { + printk("an RBV\n"); + } else if (oss_present) { + printk("an OSS\n"); + } else { + printk("a 6522 or clone\n"); + } + +#ifdef DEBUG_VIA + via_debug_dump(); +#endif + + /* + * Shut down all IRQ sources, reset the timers, and + * kill the timer latch on VIA1. + */ + + via_write(via1, vIER, 0x7F); + via_write(via1, vIFR, 0x7F); + via_write(via1, vT1LL, 0); + via_write(via1, vT1LH, 0); + via_write(via1, vT1CL, 0); + via_write(via1, vT1CH, 0); + via_write(via1, vT2CL, 0); + via_write(via1, vT2CH, 0); + via_write(via1, vACR, via_read(via1, vACR) & 0x3F); + + /* + * SE/30: disable video IRQ + * XXX: testing for SE/30 VBL + */ + + if (macintosh_config->ident == MAC_MODEL_SE30) { + via_write(via1, vBufB, via_read(via1, vBufB) | 0x40); + via_write(via1, vDirB, via_read(via1, vDirB) | 0x40); + } + + /* + * Set the RTC bits to a known state: all lines to outputs and + * RTC disabled (yes that's 0 to enable and 1 to disable). + */ + + via_write(via1, vDirB, via_read(via1, vDirB) | (VIA1B_vRTCEnb | + VIA1B_vRTCClk | + VIA1B_vRTCData)); + via_write(via1, vBufB, via_read(via1, vBufB) | (VIA1B_vRTCEnb | + VIA1B_vRTCClk)); + + /* Everything below this point is VIA2/RBV only... */ + + if (oss_present) return; + +#if 1 + /* Some machines support an alternate IRQ mapping that spreads */ + /* Ethernet and Sound out to their own autolevel IRQs and moves */ + /* VIA1 to level 6. A/UX uses this mapping and we do too. Note */ + /* that the IIfx emulates this alternate mapping using the OSS. */ + + switch(macintosh_config->ident) { + case MAC_MODEL_C610: + case MAC_MODEL_Q610: + case MAC_MODEL_C650: + case MAC_MODEL_Q650: + case MAC_MODEL_Q700: + case MAC_MODEL_Q800: + case MAC_MODEL_Q900: + case MAC_MODEL_Q950: + via_alt_mapping = 1; + via_write(via1, vDirB, via_read(via1, vDirB) | 0x40); + via_write(via1, vBufB, via_read(via1, vBufB) & ~0x40); + break; + default: + via_alt_mapping = 0; + break; + } +#else + via_alt_mapping = 0; +#endif + + /* + * Now initialize VIA2. For RBV we just kill all interrupts; + * for a regular VIA we also reset the timers and stuff. + */ + + via_write(via2, gIER, 0x7F); + via_write(via2, gIFR, 0x7F | rbv_clear); + if (!rbv_present) { + via_write(via2, vT1LL, 0); + via_write(via2, vT1LH, 0); + via_write(via2, vT1CL, 0); + via_write(via2, vT1CH, 0); + via_write(via2, vT2CL, 0); + via_write(via2, vT2CH, 0); + via_write(via2, vACR, via_read(via2, vACR) & 0x3F); + } +} + +/* + * Start the 100 Hz clock + */ + +__initfunc(void via_init_clock(void (*func)(int, void *, struct pt_regs *))) +{ + via_write(via1, vACR, via_read(via1, vACR) | 0x40); + via_write(via1, vT1LL, MAC_CLOCK_LOW); + via_write(via1, vT1LH, MAC_CLOCK_HIGH); + via_write(via1, vT1CL, MAC_CLOCK_LOW); + via_write(via1, vT1CH, MAC_CLOCK_HIGH); + + request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func); +} + +/* + * Register the interrupt dispatchers for VIA or RBV machines only. + */ + +__initfunc(void via_register_interrupts(void)) +{ + if (via_alt_mapping) { + sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "Software IRQ", (void *) via1); + sys_request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "VIA1 Dispatch", (void *) via1); + } else { + sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "VIA1 Dispatch", (void *) via1); +#if 0 /* interferes with serial on some machines */ + if (!psc_present) { + sys_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, + "Off Switch", mac_bang); + } +#endif + } + sys_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "VIA2 Dispatch", (void *) via2); + if (!psc_present) { + sys_request_irq(IRQ_AUTO_4, mac_SCC_handler, IRQ_FLG_LOCK, + "SCC Dispatch", mac_SCC_handler); + } + request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "Nubus Dispatch", (void *) via2); +} + +/* + * Debugging dump, used in various places to see what's going on. + */ + +void via_debug_dump(void) +{ + printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", + via_read(via1, vDirA), + via_read(via1, vDirB), + via_read(via1, vACR)); + printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", + via_read(via1, vPCR), + via_read(via1, vIFR), + via_read(via1, vIER)); + if (oss_present) { + printk("VIA2: \n"); + } else if (rbv_present) { + printk("VIA2: IFR = 0x%02X IER = 0x%02X\n", + via_read(via2, rIFR), + via_read(via2, rIER)); + printk(" SIFR = 0x%02X SIER = 0x%02X\n", + via_read(via2, rSIFR), + via_read(via2, rSIER)); + } else { + printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", + via_read(via2, vDirA), + via_read(via2, vDirB), + via_read(via2, vACR)); + printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", + via_read(via2, vPCR), + via_read(via2, vIFR), + via_read(via2, vIER)); + } +} + +/* + * This is always executed with interrupts disabled. + * + * TBI: get time offset between scheduling timer ticks + */ + +unsigned long mac_gettimeoffset (void) +{ + unsigned long ticks, offset = 0; + + /* read VIA1 timer 2 current value */ + ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8); + /* The probability of underflow is less than 2% */ + if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) + /* Check for pending timer interrupt in VIA1 IFR */ + if (via_read(via1, vIFR) & 0x40) + offset = TICK_SIZE; + + ticks = MAC_CLOCK_TICK - ticks; + ticks = ticks * 10000L / MAC_CLOCK_TICK; + + return ticks + offset; +} + +/* + * Flush the L2 cache on Macs that have it by flipping + * the system into 24-bit mode for an instant. + */ + +void via_flush_cache(void) +{ + via_write(via2, gBufB, via_read(via2, vBufB) & ~VIA2B_vMode32); + via_write(via2, gBufB, via_read(via2, vBufB) | VIA2B_vMode32); +} + +/* + * Return the status of the L2 cache on a IIci + */ + +int via_get_cache_disable(void) +{ + /* Safeguard against being called accidentally */ + if (!via2) { + printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n"); + return 1; + } + + return via_read(via2, gBufB) & VIA2B_vCDis; +} + +/* + * VIA-based power switch, for machines that support it. + */ + +void via_poweroff(void) +{ + if (rbv_present) { + via_write(via2, rBufB, via_read(via2, rBufB) & ~0x04); + } else { + /* Direction of vDirB is output */ + via_write(via2, vDirB, via_read(via2, vDirB) | 0x04); + /* Send a value of 0 on that line */ + via_write(via2, vBufB, via_read(via2, vBufB) & ~0x04); + /* Otherwise it prints "It is now.." then shuts off */ + mdelay(1000); + } + + /* We should never make it this far... */ + printk ("It is now safe to switch off your machine.\n"); + while(1); +} + +/* + * Initialize VIA2 for Nubus access + */ + +__initfunc(void via_nubus_init(void)) +{ + nubus_active = 0; + + /* unlock nubus transactions */ + + if (!rbv_present) { + /* set the line to be an output on non-RBV machines */ + via_write(via2, vDirB, via_read(via2, vDirB) | 0x02); + } + via_write(via2, gBufB, via_read(via2, gBufB) | 0x02); + + /* disable nubus slot interrupts. */ + if (rbv_present) { + via_write(via2, rSIER, 0x7F); /* like VIA; bit 7=clr,set */ + if ((via_read(via2, rSIER) & 0x7F) != 0) { + printk("SIER not behaving properly: " + "email \n"); + } + } else { + via_write(via2, vBufA, 0xFF); /* active low irqs, force high */ + via_write(via2, vDirA, 0xFF); /* ddr to output. */ + } +} + +/* + * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's + * via6522.c :-), disable/pending masks added. + * + * The new interrupt architecture in macints.c takes care of a lot of the + * gruntwork for us, including tallying the interrupts and calling the + * handlers on the linked list. All we need to do here is basically generate + * the machspec interrupt number after clearing the interrupt. + */ + +void via1_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit, i; + unsigned char events, mask; + + mask = via_read(via1, vIER) & 0x7f; + events = via_read(via1, vIFR) & mask; + if (events == 0) return; + + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) + if (events & irq_bit) { + via_write(via1, vIER, irq_bit); + via_write(via1, vIFR, irq_bit); + mac_do_irq_list(VIA1_SOURCE_BASE + i, regs); + via_write(via1, vIER, irq_bit | 0x80); + } + + if (!oss_present) { + /* This (still) seems to be necessary to get IDE + working. However, if you enable VBL interrupts, + you're screwed... */ + /* FIXME: should we check the SLOTIRQ bit before + pulling this stunt? */ + via_irq_disable(IRQ_MAC_NUBUS); + via_irq_clear(IRQ_MAC_NUBUS); + mac_do_irq_list(IRQ_MAC_NUBUS, regs); + via_irq_enable(IRQ_MAC_NUBUS); + } +} + +void via2_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit, i; + unsigned char events, mask; + + mask = via_read(via2, gIER) & 0x7f; + events = via_read(via2, gIFR) & mask; + if (events == 0) return; + + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) + if (events & irq_bit) { + via_write(via2, gIER, irq_bit); + via_write(via2, gIFR, irq_bit | rbv_clear); + mac_do_irq_list(VIA2_SOURCE_BASE + i, regs); + via_write(via2, gIER, irq_bit | 0x80); + } +} + +/* + * Dispatch Nubus interrupts. We are called as a secondary dispatch by the + * VIA2 dispatcher as a fast interrupt handler. + */ + +void via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit, i; + unsigned char events; + + events = ~via_read(via2, gBufA) & nubus_active; + if (events == 0) return; + + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + via_irq_disable(NUBUS_SOURCE_BASE + i); + /* FIXME: this does nothing. Should we clear + the SLOTIRQ bit here? */ + via_irq_clear(NUBUS_SOURCE_BASE + i); + mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs); + via_irq_enable(NUBUS_SOURCE_BASE + i); + } + } +} + +void via_irq_enable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + +#ifdef DEBUG_IRQUSE + printk("via_irq_enable(%d)\n", irq); +#endif + + if (irq_src == 1) { + via_write(via1, vIER, irq_bit | 0x80); + } else if (irq_src == 2) { + /* + * Set vPCR for SCSI interrupts (but not on RBV) + */ + if ((irq_idx == 0) && !rbv_present) { + if (macintosh_config->scsi_type == MAC_SCSI_OLD) { + /* CB2 (IRQ) indep. input, positive edge */ + /* CA2 (DRQ) indep. input, positive edge */ + via_write(via2, vPCR, 0x66); + } else { + /* CB2 (IRQ) indep. input, negative edge */ + /* CA2 (DRQ) indep. input, negative edge */ + via_write(via2, vPCR, 0x22); + } + } + via_write(via2, gIER, irq_bit | 0x80); + } else if (irq_src == 7) { + if (rbv_present) { + /* enable the slot interrupt. SIER works like IER. */ + via_write(via2, rSIER, IER_SET_BIT(irq_idx)); + } else { + /* Make sure the bit is an input, to enable the irq */ + via_write(via2, vDirA, + via_read(via2, vDirA) & ~irq_bit); + } + nubus_active |= irq_bit; + } +} + +void via_irq_disable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + +#ifdef DEBUG_IRQUSE + printk("via_irq_disable(%d)\n", irq); +#endif + + if (irq_src == 1) { + via_write(via1, vIER, irq_bit); + } else if (irq_src == 2) { + via_write(via2, gIER, irq_bit); + } else if (irq_src == 7) { + if (rbv_present) { + /* disable the slot interrupt. SIER works like IER. */ + via_write(via2, rSIER, IER_CLR_BIT(irq_idx)); + } else { + /* disable the nubus irq by changing dir to output */ + via_write(via2, vBufA, ~nubus_active); + via_write(via2, vDirA, via_read(via2, vDirA) | irq_bit); + } + nubus_active &= ~irq_bit; + } +} + +void via_irq_clear(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + + if (irq_src == 1) { + via_write(via1, vIFR, irq_bit); + } else if (irq_src == 2) { + via_write(via2, gIFR, irq_bit | rbv_clear); + } else if (irq_src == 7) { + /* FIXME: hmm.. */ + } +} + +/* + * Returns nonzero if an interrupt is pending on the given + * VIA/IRQ combination. + */ + +int via_irq_pending(int irq) +{ + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); + int irq_bit = 1 << irq_idx; + + if (irq_src == 1) { + return via_read(via1, vIFR) & irq_bit; + } else if (irq_src == 2) { + return via_read(via2, gIFR) & irq_bit; + } else if (irq_src == 7) { + return (~via_read(via2, gBufA)) & irq_bit; + } + return 0; +} + +void via_scsi_clear(void) +{ + volatile unsigned char deep_magic; + +#ifdef DEBUG_IRQUSE + printk("via_scsi_clear()\n"); +#endif + + /* We handle this in oss.c , but this gets called in mac_scsinew.c */ + if(oss_present) return; + + if (rbv_present) { + via_write(via2, rIFR, (1<<3) | (1<<0) | rbv_clear); + deep_magic = via_read(via2, rBufB); + } else { + deep_magic = via_read(via2, vBufB); + } + mac_enable_irq((IRQ_IDX(IRQ_MAC_SCSI))); +} + +/* + * PRAM/RTC access routines + * + * Must be called with interrupts disabled and + * the RTC should be enabled. + */ + +static __u8 via_pram_readbyte(void) +{ + int i,reg; + __u8 data; + + reg = via_read(via1, vBufB) & ~VIA1B_vRTCClk; + + /* Set the RTC data line to be an input. */ + + via_write(via1, vDirB, via_read(via1, vDirB) & ~VIA1B_vRTCData); + + /* The bits of the byte come out in MSB order */ + + data = 0; + for (i = 0 ; i < 8 ; i++) { + via_write(via1, vBufB, reg); + via_write(via1, vBufB, reg | VIA1B_vRTCClk); + data = (data << 1) | (via_read(via1, vBufB) & VIA1B_vRTCData); + } + + /* Return RTC data line to output state */ + + via_write(via1, vDirB, via_read(via1, vDirB) | VIA1B_vRTCData); + + return data; +} + +static void via_pram_writebyte(__u8 data) +{ + int i,reg,bit; + + reg = via_read(via1, vBufB) & ~(VIA1B_vRTCClk | VIA1B_vRTCData); + + /* The bits of the byte go in in MSB order */ + + for (i = 0 ; i < 8 ; i++) { + bit = data & 0x80? 1 : 0; + data <<= 1; + via_write(via1, vBufB, reg | bit); + via_write(via1, vBufB, reg | bit | VIA1B_vRTCClk); + } +} + +/* + * Execute a PRAM/RTC command. For read commands + * data should point to a one-byte buffer for the + * resulting data. For write commands it should point + * to the data byte to for the command. + * + * This function disables all interrupts while running. + */ + +void via_pram_command(int command, __u8 *data) +{ + unsigned long cpu_flags; + int is_read,tmp; + + save_flags(cpu_flags); + cli(); + + /* Enable the RTC and make sure the strobe line is high */ + + tmp = (via_read(via1, vBufB) | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb; + via_write(via1, vBufB, tmp); + + if (command & 0xFF00) { /* extended (two-byte) command */ + via_pram_writebyte((command & 0xFF00) >> 8); + via_pram_writebyte(command & 0xFF); + is_read = command & 0x8000; + } else { /* one-byte command */ + via_pram_writebyte(command); + is_read = command & 0x80; + } + if (is_read) { + *data = via_pram_readbyte(); + } else { + via_pram_writebyte(*data); + } + + /* All done, disable the RTC */ + + via_write(via1, vBufB, via_read(via1, vBufB) | VIA1B_vRTCEnb); + + restore_flags(cpu_flags); +} + +/* + * Return the current time in seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +__u32 via_read_time(void) +{ + union { + __u8 cdata[4]; + __u32 idata; + } result, last_result; + int ct; + + /* + * The NetBSD guys say to loop until you get the same reading + * twice in a row. + */ + + ct = 0; + do { + if (++ct > 10) { + printk("via_read_time: couldn't get valid time, " + "last read = 0x%08X and 0x%08X\n", last_result.idata, + result.idata); + break; + } + + last_result.idata = result.idata; + result.idata = 0; + + via_pram_command(0x81, &result.cdata[3]); + via_pram_command(0x85, &result.cdata[2]); + via_pram_command(0x89, &result.cdata[1]); + via_pram_command(0x8D, &result.cdata[0]); + } while (result.idata != last_result.idata); + + return result.idata; +} + +/* + * Set the current time to a number of seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +void via_write_time(__u32 time) +{ + union { + __u8 cdata[4]; + __u32 idata; + } data; + __u8 temp; + + /* Clear the write protect bit */ + + temp = 0x55; + via_pram_command(0x35, &temp); + + data.idata = time; + via_pram_command(0x01, &data.cdata[3]); + via_pram_command(0x05, &data.cdata[2]); + via_pram_command(0x09, &data.cdata[1]); + via_pram_command(0x0D, &data.cdata[0]); + + /* Set the write protect bit */ + + temp = 0xD5; + via_pram_command(0x35, &temp); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c --- v2.2.17/arch/m68k/mac/via6522.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/via6522.c Thu Jan 1 01:00:00 1970 @@ -1,419 +0,0 @@ -/* - * 6522 Versatile Interface Adapter (VIA) - * - * There are two of these on the Mac II. Some IRQ's are vectored - * via them as are assorted bits and bobs - eg rtc, adb. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include "via6522.h" -#include - -volatile unsigned char *via1=(unsigned char *)VIABASE; -volatile unsigned char *via2=(unsigned char *)VIABASE2; -volatile unsigned char *psc=(unsigned char *)PSCBASE; - -volatile long *via_memory_bogon=(long *)&via_memory_bogon; - -unsigned char via1_clock, via1_datab; - -static int rbv=0; -static int oss=0; - -extern void adb_interrupt(int slot, void *via, struct pt_regs *regs); - -/* - * hardware reset vector - */ -static void (*rom_reset)(void); - -/* - * Timer defs. - */ -#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ -#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) -#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) - - -void via_configure_base(void) -{ - - switch(macintosh_config->via_type) - { - /* - * CI, SI, VX, LC - */ - case MAC_VIA_IIci: - via1=(void *)0x50F00000; - via2=(void *)0x50F26000; - rbv=1; - if (macintosh_config->ident == MAC_MODEL_IIFX) { - via2=(void *)0x50F1A000; - oss=1; - } - break; - /* - * Quadra and early MacIIs agree on the VIA locations - */ - case MAC_VIA_QUADRA: - case MAC_VIA_II: - via1=(void *)0x50F00000; - via2=(void *)0x50F02000; - break; - default: - } -} - - -void via_init_clock(void (*func)(int, void *, struct pt_regs *)) -{ - unsigned char c; - - via1_clock=via_read(via1, vACR); - via1_datab=via_read(via1, vBufB); - - /* - * Tell what MacOS left us with - */ - - printk("via_init: boot via1 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n", - (int)via1_clock, (int)via_read(via1, vPCR), - (int)via_read(via1, vBufA), (int)via_read(via1, vDirA), - (int)via_read(via1, vBufB), (int)via_read(via1, vDirB)); - - if (rbv == 0) - printk("via_init: boot via2 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n", - (int)via_read(via2, vACR), (int)via_read(via2, vPCR), - (int)via_read(via2, vBufA), (int)via_read(via2, vDirA), - (int)via_read(via2, vBufB), (int)via_read(via2, vDirB)); - - /* - * Shut it down - */ - - via_write(via1,vIER, 0x7F); - - /* - * Kill the timers - */ - - via_write(via1,vT1LL,0); - via_write(via1,vT1LH,0); - via_write(via1,vT1CL,0); - via_write(via1,vT1CH,0); - via_write(via1,vT2CL,0); - via_write(via1,vT2CH,0); - - /* - * Now do via2 - */ - - if(rbv==0) - { - via_write(via2,vT1LL,0); - via_write(via2,vT1LH,0); - via_write(via2,vT1CL,0); - via_write(via2,vT1CH,0); - via_write(via2,vT2CL,0); - via_write(via2,vT2CH,0); - via_write(via2,vIER, 0x7F); - } - else if (oss==0) - { - /* - * Init the RBV chip a bit - */ - - via_write(via2, rIER,0x7F); - } - - /* - * Disable the timer latches - */ - - c=via_read(via1,vACR); - via_write(via1,vACR,c&0x3F); - - if(rbv==0) - { - c=via_read(via2,vACR); - via_write(via2,vACR,c&0x3F); - } - - /* - * Now start the clock - we want 100Hz - */ - - via_write(via1,vACR,via_read(via1,vACR)|0x40); - - via_write(via1,vT1LL, MAC_CLOCK_LOW); - via_write(via1,vT1LH, MAC_CLOCK_HIGH); - via_write(via1,vT1CL, MAC_CLOCK_LOW); - via_write(via1,vT1CH, MAC_CLOCK_HIGH); - - /* - * And enable its interrupt - */ - - request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func); - - /* - * SE/30: disable video int. - * XXX: testing for SE/30 VBL - */ - - if (macintosh_config->ident == MAC_MODEL_SE30) { - c = via_read(via1, vBufB); - via_write(via1, vBufB, c|(0x40)); - c = via_read(via1, vDirB); - via_write(via1, vDirB, c|(0x40)); - } - -#if 0 /* gone to mac_init_IRQ */ - /* - * Set vPCR for SCSI interrupts. - * - * That is: CA1 negative edge int., CA2 indep., positive edge int.; - * CB1 negative edge int., CB2 indep., positive edge int.. - */ - via_write(via2,vPCR, 0x66); -#endif - -} - -/* - * TBI: get time offset between scheduling timer ticks - */ -#define TICK_SIZE 10000 - -/* This is always executed with interrupts disabled. */ - -unsigned long mac_gettimeoffset (void) -{ - unsigned long ticks, offset = 0; - - /* read VIA1 timer 2 current value */ - ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8); - /* The probability of underflow is less than 2% */ - if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) - /* Check for pending timer interrupt in VIA1 IFR */ - if (via_read(via1, vIFR) & 0x40) - offset = TICK_SIZE; - - ticks = MAC_CLOCK_TICK - ticks; - ticks = ticks * 10000L / MAC_CLOCK_TICK; - - return ticks + offset; -} - -/* - * PSC (AV Macs; level 3-6): initialize interrupt enable registers - */ - -void psc_init(void) -{ - via_write(psc, pIER3, 0x01); - via_write(psc, pIER4, 0x09); - via_write(psc, pIER4, 0x86); - via_write(psc, pIER5, 0x03); - via_write(psc, pIER6, 0x07); -} - -/* - * The power switch - yes it's software! - */ - -void mac_poweroff(void) -{ - - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (macintosh_config->adb_type == MAC_ADB_II) - { - if(rbv) { - via_write(via2, rBufB, via_read(via2, rBufB)&~0x04); - } else { - /* Direction of vDirB is output */ - via_write(via2,vDirB,via_read(via2,vDirB)|0x04); - /* Send a value of 0 on that line */ - via_write(via2,vBufB,via_read(via2,vBufB)&~0x04); - /* Otherwise it prints "It is now.." then shuts off */ - mdelay(1000); - } - - /* We should never make it this far... */ - printk ("It is now safe to switch off your machine.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } - - /* - * Initially discovered this technique in the Mach kernel of MkLinux in - * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC - * code in arch/ppc/kernel/setup.c, which also has a PMU technique for PowerBooks! - * --David Kilzer - */ - - else if (macintosh_config->adb_type == MAC_ADB_IISI - || macintosh_config->adb_type == MAC_ADB_CUDA) - { - struct adb_request req; - - /* - * Print our "safe" message before we send the request - * just in case the request never returns. - */ - - printk ("It is now safe to switch off your machine.\n"); - - adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); - - printk ("ADB powerdown request sent.\n"); - for (;;) - { - adb_poll(); - } - } -} - -/* - * Not all Macs support software power down; for the rest, just - * try the ROM reset vector ... - */ -void mac_reset(void) -{ - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (macintosh_config->adb_type == MAC_ADB_II) - { - unsigned long flags; - unsigned long *reset_hook; - - /* need ROMBASE in booter */ - /* indeed, plus need to MAP THE ROM !! */ - - if (mac_bi_data.rombase == 0) - mac_bi_data.rombase = 0x40800000; - - /* works on some */ - rom_reset = (void *) (mac_bi_data.rombase + 0xa); - -#if 0 - /* testing, doesn't work on SE/30 either */ - reset_hook = (unsigned long *) (mac_bi_data.rombase + 0x4); - printk("ROM reset hook: %p\n", *reset_hook); - rom_reset = *reset_hook; -#endif - if (macintosh_config->ident == MAC_MODEL_SE30) { - /* - * MSch: Machines known to crash on ROM reset ... - */ - printk("System halted.\n"); - while(1); - } else { - save_flags(flags); - cli(); - - rom_reset(); - - restore_flags(flags); - } - - /* We never make it this far... it usually panics above. */ - printk ("Restart failed. Please restart manually.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } - - /* - * Initially discovered this technique in the Mach kernel of MkLinux in - * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c. Found equivalent LinuxPPC - * code in arch/ppc/kernel/setup.c, which also has a PMU technique! - * --David Kilzer - * - * I suspect the MAC_ADB_CUDA code might work with other ADB types of machines - * but have no way to test this myself. --DDK - */ - - else if (macintosh_config->adb_type == MAC_ADB_IISI - || macintosh_config->adb_type == MAC_ADB_CUDA) - { - struct adb_request req; - - adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); - - printk ("Restart failed. Please restart manually.\n"); - for (;;) - { - adb_poll(); - } - } -} - -/* - * Set up the keyboard - */ - -void via_setup_keyboard(void) -{ -#if 0 /* moved to adb */ - via1_func_tab.vector[2]=adb_interrupt; -#else - request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, "adb interrupt", - adb_interrupt); -#endif -} - -/* - * Floppy hook - */ - -void via1_set_head(int head) -{ - if(head==0) - via_write(via1, vBufA, via_read(via1, vBufA)&~0x20); - else - via_write(via1, vBufA, via_read(via1, vBufA)|0x20); -} - -void nubus_init_via(void) -{ - if (rbv) { - if (oss==0) { - via_write(via2, rBufB, via_read(via2, rBufB)|0x02); - via_write(via2, rIER, 0x82); /* Interrupts on */ - } - } else { - /* Assert the nubus active */ - via_write(via2, vDirB, via_read(via2, vDirB)|0x02); - via_write(via2, vBufB, via_read(via2, vBufB)|0x02); - /* Make the nubus interrupt source register all output (disable) */ - /* via_write(via2, vDirA, 0xFF); */ - via_write(via2, vIER, 0x82); /* Interrupts on */ - } - - printk("nubus_init_via: via1 acr=%X datab=%X pcr=%X\n", - (int)via_read(via1, vACR), (int)via_read(via1, vBufB), - (int)via_read(via1, vPCR)); - - if (rbv==0) - printk("nubus_init_via: via2 acr=%X datab=%X pcr=%X\n", - (int)via_read(via2, vACR), (int)via_read(via2, vBufB), - (int)via_read(via2, vPCR)); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mac/via6522.h linux/arch/m68k/mac/via6522.h --- v2.2.17/arch/m68k/mac/via6522.h Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mac/via6522.h Thu Jan 1 01:00:00 1970 @@ -1,131 +0,0 @@ -/* - * 6522 Versatile Interface Adapter (VIA) - * - * There are two of these on the Mac II. Some IRQ's are vectored - * via them as are assorted bits and bobs - eg rtc, adb. The picture - * is a bit incomplete as the Mac documentation doesnt cover this well - */ - -#ifndef _ASM_VIA6522_H_ -#define _ASM_VIA6522_H_ - -#define VIABASE 0x50F00000 -#define VIABASE2 0x50F02000 - -/* - * Not all of these are true post MacII I think - */ - -#define VIA1A_vSccWrReq 0x80 /* SCC write */ -#define VIA1A_vRev8 0x40 /* Revision 8 board ??? */ -#define VIA1A_vHeadSel 0x20 /* Head select for IWM */ -#define VIA1A_vOverlay 0x10 -#define VIA1A_vSync 0x08 -#define VIA1A_vVolume 0x07 /* Audio volume mask */ - -#define VIA1B_vSound 0x80 /* Audio on/off */ -#define VIA1B_vMystery 0x40 -#define VIA1B_vADBS2 0x20 /* ADB state 2 */ -#define VIA1B_vADBS1 0x10 /* ADB state 1 */ -#define VIA1B_vADBInt 0x08 /* ADB interrupt */ -#define VIA1B_vRTCEnb 0x04 /* Real time clock */ -#define VIA1B_vRTCClk 0x02 -#define VIA1B_vRTCData 0x01 - -/* - * VIA2 A register is the interrupt lines raised off the nubus - * slots. - */ - -#define VIA2A_vIRQE 0x20 -#define VIA2A_vIRQD 0x10 -#define VIA2A_vIRQC 0x08 -#define VIA2A_vIRQB 0x04 -#define VIA2A_vIRQA 0x02 -#define VIA2A_vIRQ9 0x01 - -/* - * Register B has the fun stuff in it - */ - -#define VIA2B_vMode32 0x08 /* 24/32bit switch - doubles as cache flush */ -#define VIA2B_vPower 0x04 /* Off switch */ -#define VIA2B_vBusLk 0x02 /* Nubus in use ?? */ -#define VIA2B_vCDis 0x01 /* Cache disable */ - -/* - * The 6522 via is a 2MHz part, and needs a delay. MacOS seems to - * execute MOV (Ax),(Ax) for this... Oh and we can't use udelay - * here... see we need the via to calibrate the udelay loop ... - */ - -extern volatile long *via_memory_bogon; - -extern __inline__ void via_write(volatile unsigned char *via,int reg, int v) -{ - *via_memory_bogon; - *via_memory_bogon; - *via_memory_bogon; - via[reg]=v; -} - -extern __inline__ int via_read(volatile unsigned char *via,int reg) -{ - *via_memory_bogon; - *via_memory_bogon; - *via_memory_bogon; - return (int)via[reg]; -} - -extern volatile unsigned char *via1,*via2; - -/* - * 6522 registers - see databook - */ - -#define vBufB 0x0000 -#define vBufA 0x0200 -#define vDirB 0x0400 -#define vDirA 0x0600 -#define vT1CL 0x0800 -#define vT1CH 0x0a00 -#define vT1LL 0x0c00 -#define vT1LH 0x0e00 -#define vT2CL 0x1000 -#define vT2CH 0x1200 -#define vSR 0x1400 -#define vACR 0x1600 -#define vPCR 0x1800 -#define vIFR 0x1a00 -#define vIER 0x1c00 -#define vANH 0x1e00 /* register A (no shake) */ - -#define rBufB 0x00 -#define rBufA 0x02 -/*#define rIFR 0x03*/ -#define rIFR 0x1A03 -#define rVideo 0x10 -#define rSlot 0x12 -/*#define rIER 0x13*/ -#define rIER 0x1C13 -/* -#define R_rIFR 0x03 -#define R_rIER 0x13 -#define W_rIFR 0x1A03 -#define W_rIER 0x1C13 -*/ -/* - * VIA interrupt - */ - -struct via_irq_tab -{ - void (*vector[8])(int, void *, struct pt_regs *); -}; - -extern void via1_irq(int, void *, struct pt_regs *); -extern void via2_irq(int, void *, struct pt_regs *); - -extern void via_setup_keyboard(void); - -#endif /* _ASM_VIA6522_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/Makefile linux/arch/m68k/math-emu/Makefile --- v2.2.17/arch/m68k/math-emu/Makefile Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/Makefile Fri Oct 13 23:36:54 2000 @@ -0,0 +1,19 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ -traditional -c $< -o $*.o + +#EXTRA_CFLAGS=-DFPU_EMU_DEBUG + +O_TARGET := mathemu.o +O_OBJS := fp_entry.o fp_scan.o fp_util.o fp_move.o fp_movem.o \ + fp_cond.o fp_arith.o fp_log.o fp_trig.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_arith.c linux/arch/m68k/math-emu/fp_arith.c --- v2.2.17/arch/m68k/math-emu/fp_arith.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_arith.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,700 @@ +/* + + fp_arith.c: floating-point math routines for the Linux-m68k + floating point emulator. + + Copyright (c) 1998-1999 David Huggins-Daines. + + Somewhat based on the AlphaLinux floating point emulator, by David + Mosberger-Tang. + + You may copy, modify, and redistribute this file under the terms of + the GNU General Public License, version 2, or any later version, at + your convenience. + */ + +#include "fp_emu.h" +#include "multi_arith.h" +#include "fp_arith.h" + +const struct fp_ext fp_QNaN = +{ + 0, 0, 0x7fff, { ~0 } +}; + +const struct fp_ext fp_Inf = +{ + 0, 0, 0x7fff, { 0 } +}; + +/* let's start with the easy ones */ + +struct fp_ext * +fp_fabs(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "fabs\n"); + + fp_monadic_check(dest, src); + + dest->sign = 0; + + return dest; +} + +struct fp_ext * +fp_fneg(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "fneg\n"); + + fp_monadic_check(dest, src); + + dest->sign = !dest->sign; + + return dest; +} + +/* Now, the slightly harder ones */ + +/* fp_fadd: Implements the kernel of the FADD, FSADD, FDADD, FSUB, + FDSUB, and FCMP instructions. */ + +struct fp_ext * +fp_fadd(struct fp_ext *dest, struct fp_ext *src) +{ + int diff; + + dprint(PINSTR, "fadd\n"); + + fp_dyadic_check(dest, src); + + if (IS_INF(dest)) { + /* infinity - infinity == NaN */ + if (IS_INF(src) && (src->sign != dest->sign)) + fp_set_nan(dest); + return dest; + } + if (IS_INF(src)) { + fp_copy_ext(dest, src); + return dest; + } + + if (IS_ZERO(dest)) { + if (IS_ZERO(src)) { + if (src->sign != dest->sign) { + if (FPDATA->rnd == FPCR_ROUND_RM) + dest->sign = 1; + else + dest->sign = 0; + } + } else + fp_copy_ext(dest, src); + return dest; + } + + dest->lowmant = src->lowmant = 0; + + if ((diff = dest->exp - src->exp) > 0) + fp_denormalize(src, diff); + else if ((diff = -diff) > 0) + fp_denormalize(dest, diff); + + if (dest->sign == src->sign) { + if (fp_addmant(dest, src)) + if (!fp_addcarry(dest)) + return dest; + } else { + if (dest->mant.m64 < src->mant.m64) { + fp_submant(dest, src, dest); + dest->sign = !dest->sign; + } else + fp_submant(dest, dest, src); + } + + return dest; +} + +/* fp_fsub: Implementes the kernel of the FSUB, FSSUB, and FDSUB + instructions. + + Remember that the arguments are in assembler-syntax order! */ + +struct fp_ext * +fp_fsub(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "fsub "); + + src->sign = !src->sign; + return fp_fadd(dest, src); +} + + +struct fp_ext * +fp_fcmp(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "fcmp "); + + FPDATA->temp[1] = *dest; + src->sign = !src->sign; + return fp_fadd(&FPDATA->temp[1], src); +} + +struct fp_ext * +fp_ftst(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "ftst\n"); + + (void)dest; + + return src; +} + +struct fp_ext * +fp_fmul(struct fp_ext *dest, struct fp_ext *src) +{ + union fp_mant128 temp; + int exp; + + dprint(PINSTR, "fmul\n"); + + fp_dyadic_check(dest, src); + + /* calculate the correct sign now, as it's necessary for infinities */ + dest->sign = src->sign ^ dest->sign; + + /* Handle infinities */ + if (IS_INF(dest)) { + if (IS_ZERO(src)) + fp_set_nan(dest); + return dest; + } + if (IS_INF(src)) { + if (IS_ZERO(dest)) + fp_set_nan(dest); + else + fp_copy_ext(dest, src); + return dest; + } + + /* Of course, as we all know, zero * anything = zero. You may + not have known that it might be a positive or negative + zero... */ + if (IS_ZERO(dest) || IS_ZERO(src)) { + dest->exp = 0; + dest->mant.m64 = 0; + dest->lowmant = 0; + + return dest; + } + + exp = dest->exp + src->exp - 0x3ffe; + + /* shift up the mantissa for denormalized numbers, + so that the highest bit is set, this makes the + shift of the result below easier */ + if ((long)dest->mant.m32[0] >= 0) + exp -= fp_overnormalize(dest); + if ((long)src->mant.m32[0] >= 0) + exp -= fp_overnormalize(src); + + /* now, do a 64-bit multiply with expansion */ + fp_multiplymant(&temp, dest, src); + + /* normalize it back to 64 bits and stuff it back into the + destination struct */ + if ((long)temp.m32[0] > 0) { + exp--; + fp_putmant128(dest, &temp, 1); + } else + fp_putmant128(dest, &temp, 0); + + if (exp >= 0x7fff) { + fp_set_ovrflw(dest); + return dest; + } + dest->exp = exp; + if (exp < 0) { + fp_set_sr(FPSR_EXC_UNFL); + fp_denormalize(dest, -exp); + } + + return dest; +} + +/* fp_fdiv: Implements the "kernel" of the FDIV, FSDIV, FDDIV and + FSGLDIV instructions. + + Note that the order of the operands is counter-intuitive: instead + of src / dest, the result is actually dest / src. */ + +struct fp_ext * +fp_fdiv(struct fp_ext *dest, struct fp_ext *src) +{ + union fp_mant128 temp; + int exp; + + dprint(PINSTR, "fdiv\n"); + + fp_dyadic_check(dest, src); + + /* calculate the correct sign now, as it's necessary for infinities */ + dest->sign = src->sign ^ dest->sign; + + /* Handle infinities */ + if (IS_INF(dest)) { + /* infinity / infinity = NaN (quiet, as always) */ + if (IS_INF(src)) + fp_set_nan(dest); + /* infinity / anything else = infinity (with approprate sign) */ + return dest; + } + if (IS_INF(src)) { + /* anything / infinity = zero (with appropriate sign) */ + dest->exp = 0; + dest->mant.m64 = 0; + dest->lowmant = 0; + + return dest; + } + + /* zeroes */ + if (IS_ZERO(dest)) { + /* zero / zero = NaN */ + if (IS_ZERO(src)) + fp_set_nan(dest); + /* zero / anything else = zero */ + return dest; + } + if (IS_ZERO(src)) { + /* anything / zero = infinity (with appropriate sign) */ + fp_set_sr(FPSR_EXC_DZ); + dest->exp = 0x7fff; + dest->mant.m64 = 0; + + return dest; + } + + exp = dest->exp - src->exp + 0x3fff; + + /* shift up the mantissa for denormalized numbers, + so that the highest bit is set, this makes lots + of things below easier */ + if ((long)dest->mant.m32[0] >= 0) + exp -= fp_overnormalize(dest); + if ((long)src->mant.m32[0] >= 0) + exp -= fp_overnormalize(src); + + /* now, do the 64-bit divide */ + fp_dividemant(&temp, dest, src); + + /* normalize it back to 64 bits and stuff it back into the + destination struct */ + if (!temp.m32[0]) { + exp--; + fp_putmant128(dest, &temp, 32); + } else + fp_putmant128(dest, &temp, 31); + + if (exp >= 0x7fff) { + fp_set_ovrflw(dest); + return dest; + } + dest->exp = exp; + if (exp < 0) { + fp_set_sr(FPSR_EXC_UNFL); + fp_denormalize(dest, -exp); + } + + return dest; +} + +struct fp_ext * +fp_fsglmul(struct fp_ext *dest, struct fp_ext *src) +{ + int exp; + + dprint(PINSTR, "fsglmul\n"); + + fp_dyadic_check(dest, src); + + /* calculate the correct sign now, as it's necessary for infinities */ + dest->sign = src->sign ^ dest->sign; + + /* Handle infinities */ + if (IS_INF(dest)) { + if (IS_ZERO(src)) + fp_set_nan(dest); + return dest; + } + if (IS_INF(src)) { + if (IS_ZERO(dest)) + fp_set_nan(dest); + else + fp_copy_ext(dest, src); + return dest; + } + + /* Of course, as we all know, zero * anything = zero. You may + not have known that it might be a positive or negative + zero... */ + if (IS_ZERO(dest) || IS_ZERO(src)) { + dest->exp = 0; + dest->mant.m64 = 0; + dest->lowmant = 0; + + return dest; + } + + exp = dest->exp + src->exp - 0x3ffe; + + /* do a 32-bit multiply */ + fp_mul64(dest->mant.m32[0], dest->mant.m32[1], + dest->mant.m32[0] & 0xffffff00, + src->mant.m32[0] & 0xffffff00); + + if (exp >= 0x7fff) { + fp_set_ovrflw(dest); + return dest; + } + dest->exp = exp; + if (exp < 0) { + fp_set_sr(FPSR_EXC_UNFL); + fp_denormalize(dest, -exp); + } + + return dest; +} + +struct fp_ext * +fp_fsgldiv(struct fp_ext *dest, struct fp_ext *src) +{ + int exp; + unsigned long quot, rem; + + dprint(PINSTR, "fsgldiv\n"); + + fp_dyadic_check(dest, src); + + /* calculate the correct sign now, as it's necessary for infinities */ + dest->sign = src->sign ^ dest->sign; + + /* Handle infinities */ + if (IS_INF(dest)) { + /* infinity / infinity = NaN (quiet, as always) */ + if (IS_INF(src)) + fp_set_nan(dest); + /* infinity / anything else = infinity (with approprate sign) */ + return dest; + } + if (IS_INF(src)) { + /* anything / infinity = zero (with appropriate sign) */ + dest->exp = 0; + dest->mant.m64 = 0; + dest->lowmant = 0; + + return dest; + } + + /* zeroes */ + if (IS_ZERO(dest)) { + /* zero / zero = NaN */ + if (IS_ZERO(src)) + fp_set_nan(dest); + /* zero / anything else = zero */ + return dest; + } + if (IS_ZERO(src)) { + /* anything / zero = infinity (with appropriate sign) */ + fp_set_sr(FPSR_EXC_DZ); + dest->exp = 0x7fff; + dest->mant.m64 = 0; + + return dest; + } + + exp = dest->exp - src->exp + 0x3fff; + + dest->mant.m32[0] &= 0xffffff00; + src->mant.m32[0] &= 0xffffff00; + + /* do the 32-bit divide */ + if (dest->mant.m32[0] >= src->mant.m32[0]) { + fp_sub64(dest->mant, src->mant); + fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]); + dest->mant.m32[0] = 0x80000000 | (quot >> 1); + dest->mant.m32[1] = (quot & 1) | rem; /* only for rounding */ + } else { + fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]); + dest->mant.m32[0] = quot; + dest->mant.m32[1] = rem; /* only for rounding */ + exp--; + } + + if (exp >= 0x7fff) { + fp_set_ovrflw(dest); + return dest; + } + dest->exp = exp; + if (exp < 0) { + fp_set_sr(FPSR_EXC_UNFL); + fp_denormalize(dest, -exp); + } + + return dest; +} + +/* fp_roundint: Internal rounding function for use by several of these + emulated instructions. + + This one rounds off the fractional part using the rounding mode + specified. */ + +static void fp_roundint(struct fp_ext *dest, int mode) +{ + union fp_mant64 oldmant; + unsigned long mask; + + if (!fp_normalize_ext(dest)) + return; + + /* infinities and zeroes */ + if (IS_INF(dest) || IS_ZERO(dest)) + return; + + /* first truncate the lower bits */ + oldmant = dest->mant; + switch (dest->exp) { + case 0 ... 0x3ffe: + dest->mant.m64 = 0; + break; + case 0x3fff ... 0x401e: + dest->mant.m32[0] &= 0xffffffffU << (0x401e - dest->exp); + dest->mant.m32[1] = 0; + if (oldmant.m64 == dest->mant.m64) + return; + break; + case 0x401f ... 0x403e: + dest->mant.m32[1] &= 0xffffffffU << (0x403e - dest->exp); + if (oldmant.m32[1] == dest->mant.m32[1]) + return; + break; + default: + return; + } + fp_set_sr(FPSR_EXC_INEX2); + + /* We might want to normalize upwards here... however, since + we know that this is only called on the output of fp_fdiv, + or with the input to fp_fint or fp_fintrz, and the inputs + to all these functions are either normal or denormalized + (no subnormals allowed!), there's really no need. + + In the case of fp_fdiv, observe that 0x80000000 / 0xffff = + 0xffff8000, and the same holds for 128-bit / 64-bit. (i.e. the + smallest possible normal dividend and the largest possible normal + divisor will still produce a normal quotient, therefore, (normal + << 64) / normal is normal in all cases) */ + + switch (mode) { + case FPCR_ROUND_RN: + switch (dest->exp) { + case 0 ... 0x3ffd: + return; + case 0x3ffe: + /* As noted above, the input is always normal, so the + guard bit (bit 63) is always set. therefore, the + only case in which we will NOT round to 1.0 is when + the input is exactly 0.5. */ + if (oldmant.m64 == (1ULL << 63)) + return; + break; + case 0x3fff ... 0x401d: + mask = 1 << (0x401d - dest->exp); + if (!(oldmant.m32[0] & mask)) + return; + if (oldmant.m32[0] & (mask << 1)) + break; + if (!(oldmant.m32[0] << (dest->exp - 0x3ffd)) && + !oldmant.m32[1]) + return; + break; + case 0x401e: + if (!(oldmant.m32[1] >= 0)) + return; + if (oldmant.m32[0] & 1) + break; + if (!(oldmant.m32[1] << 1)) + return; + break; + case 0x401f ... 0x403d: + mask = 1 << (0x403d - dest->exp); + if (!(oldmant.m32[1] & mask)) + return; + if (oldmant.m32[1] & (mask << 1)) + break; + if (!(oldmant.m32[1] << (dest->exp - 0x401d))) + return; + break; + default: + return; + } + break; + case FPCR_ROUND_RZ: + return; + default: + if (dest->sign ^ (mode - FPCR_ROUND_RM)) + break; + return; + } + + switch (dest->exp) { + case 0 ... 0x3ffe: + dest->exp = 0x3fff; + dest->mant.m64 = 1ULL << 63; + break; + case 0x3fff ... 0x401e: + mask = 1 << (0x401e - dest->exp); + if (dest->mant.m32[0] += mask) + break; + dest->mant.m32[0] = 0x80000000; + dest->exp++; + break; + case 0x401f ... 0x403e: + mask = 1 << (0x403e - dest->exp); + if (dest->mant.m32[1] += mask) + break; + if (dest->mant.m32[0] += 1) + break; + dest->mant.m32[0] = 0x80000000; + dest->exp++; + break; + } +} + +/* modrem_kernel: Implementation of the FREM and FMOD instructions + (which are exactly the same, except for the rounding used on the + intermediate value) */ + +static struct fp_ext * +modrem_kernel(struct fp_ext *dest, struct fp_ext *src, int mode) +{ + struct fp_ext tmp; + + fp_dyadic_check(dest, src); + + /* Infinities and zeros */ + if (IS_INF(dest) || IS_ZERO(src)) { + fp_set_nan(dest); + return dest; + } + if (IS_ZERO(dest) || IS_INF(src)) + return dest; + + /* FIXME: there is almost certainly a smarter way to do this */ + fp_copy_ext(&tmp, dest); + fp_fdiv(&tmp, src); /* NOTE: src might be modified */ + fp_roundint(&tmp, mode); + fp_fmul(&tmp, src); + fp_fsub(dest, &tmp); + + /* set the quotient byte */ + fp_set_quotient((dest->mant.m64 & 0x7f) | (dest->sign << 7)); + return dest; +} + +/* fp_fmod: Implements the kernel of the FMOD instruction. + + Again, the argument order is backwards. The result, as defined in + the Motorola manuals, is: + + fmod(src,dest) = (dest - (src * floor(dest / src))) */ + +struct fp_ext * +fp_fmod(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "fmod\n"); + return modrem_kernel(dest, src, FPCR_ROUND_RZ); +} + +/* fp_frem: Implements the kernel of the FREM instruction. + + frem(src,dest) = (dest - (src * round(dest / src))) + */ + +struct fp_ext * +fp_frem(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "frem\n"); + return modrem_kernel(dest, src, FPCR_ROUND_RN); +} + +struct fp_ext * +fp_fint(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "fint\n"); + + fp_copy_ext(dest, src); + + fp_roundint(dest, FPDATA->rnd); + + return dest; +} + +struct fp_ext * +fp_fintrz(struct fp_ext *dest, struct fp_ext *src) +{ + dprint(PINSTR, "fintrz\n"); + + fp_copy_ext(dest, src); + + fp_roundint(dest, FPCR_ROUND_RZ); + + return dest; +} + +struct fp_ext * +fp_fscale(struct fp_ext *dest, struct fp_ext *src) +{ + int scale, oldround; + + dprint(PINSTR, "fscale\n"); + + fp_dyadic_check(dest, src); + + /* Infinities */ + if (IS_INF(src)) { + fp_set_nan(dest); + return dest; + } + if (IS_INF(dest)) + return dest; + + /* zeroes */ + if (IS_ZERO(src) || IS_ZERO(dest)) + return dest; + + /* Source exponent out of range */ + if (src->exp >= 0x400c) { + fp_set_ovrflw(dest); + return dest; + } + + /* src must be rounded with round to zero. */ + oldround = FPDATA->rnd; + FPDATA->rnd = FPCR_ROUND_RZ; + scale = fp_conv_ext2long(src); + FPDATA->rnd = oldround; + + /* new exponent */ + scale += dest->exp; + + if (scale >= 0x7fff) { + fp_set_ovrflw(dest); + } else if (scale <= 0) { + fp_set_sr(FPSR_EXC_UNFL); + fp_denormalize(dest, -scale); + } else + dest->exp = scale; + + return dest; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_arith.h linux/arch/m68k/math-emu/fp_arith.h --- v2.2.17/arch/m68k/math-emu/fp_arith.h Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_arith.h Fri Oct 13 23:36:54 2000 @@ -0,0 +1,52 @@ +/* + + fp_arith.h: floating-point math routines for the Linux-m68k + floating point emulator. + + Copyright (c) 1998 David Huggins-Daines. + + Somewhat based on the AlphaLinux floating point emulator, by David + Mosberger-Tang. + + You may copy, modify, and redistribute this file under the terms of + the GNU General Public License, version 2, or any later version, at + your convenience. + + */ + +#ifndef FP_ARITH_H +#define FP_ARITH_H + +/* easy ones */ +struct fp_ext * +fp_fabs(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fneg(struct fp_ext *dest, struct fp_ext *src); + +/* straightforward arithmetic */ +struct fp_ext * +fp_fadd(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fsub(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fcmp(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_ftst(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fmul(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fdiv(struct fp_ext *dest, struct fp_ext *src); + +/* ones that do rounding and integer conversions */ +struct fp_ext * +fp_fmod(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_frem(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fint(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fintrz(struct fp_ext *dest, struct fp_ext *src); +struct fp_ext * +fp_fscale(struct fp_ext *dest, struct fp_ext *src); + +#endif /* FP_ARITH__H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_cond.S linux/arch/m68k/math-emu/fp_cond.S --- v2.2.17/arch/m68k/math-emu/fp_cond.S Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_cond.S Fri Oct 13 23:36:54 2000 @@ -0,0 +1,334 @@ +/* + * fp_cond.S + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fp_emu.h" +#include "fp_decode.h" + + .globl fp_fscc, fp_fbccw, fp_fbccl + +#ifdef FPU_EMU_DEBUG +fp_fnop: + printf PDECODE,"fnop\n" + jra fp_end +#else +#define fp_fnop fp_end +#endif + +fp_fbccw: + tst.w %d2 + jeq fp_fnop + printf PDECODE,"fbccw " + fp_get_pc %a0 + lea (-2,%a0,%d2.w),%a0 + jra 1f + +fp_fbccl: + printf PDECODE,"fbccl " + fp_get_pc %a0 + move.l %d2,%d0 + swap %d0 + fp_get_instr_word %d0,fp_err_ua1 + lea (-2,%a0,%d0.l),%a0 +1: printf PDECODE,"%x",1,%a0 + move.l %d2,%d0 + swap %d0 + jsr fp_compute_cond + tst.l %d0 + jeq 1f + fp_put_pc %a0,1 +1: printf PDECODE,"\n" + jra fp_end + +fp_fdbcc: + printf PDECODE,"fdbcc " + fp_get_pc %a1 | calculate new pc + fp_get_instr_word %d0,fp_err_ua1 + add.w %d0,%a1 + fp_decode_addr_reg + printf PDECODE,"d%d,%x\n",2,%d0,%a1 + swap %d1 | test condition in %d1 + tst.w %d1 + jne 2f + move.l %d0,%d1 + jsr fp_get_data_reg + subq.w #1,%d0 + jcs 1f + fp_put_pc %a1,1 +1: jsr fp_put_data_reg +2: jra fp_end + +| set flags for decode macros for fs +do_fscc=1 +do_no_pc_mode=1 + +fp_fscc: + printf PDECODE,"fscc " + move.l %d2,%d0 + jsr fp_compute_cond + move.w %d0,%d1 + swap %d1 + + | decode addressing mode + fp_decode_addr_mode + + .long fp_data, fp_fdbcc + .long fp_indirect, fp_postinc + .long fp_predecr, fp_disp16 + .long fp_extmode0, fp_extmode1 + + | addressing mode: data register direct +fp_data: + fp_mode_data_direct + move.w %d0,%d1 | save register nr + jsr fp_get_data_reg + swap %d1 + move.b %d1,%d0 + swap %d1 + jsr fp_put_data_reg + printf PDECODE,"\n" + jra fp_end + +fp_indirect: + fp_mode_addr_indirect + jra fp_do_scc + +fp_postinc: + fp_mode_addr_indirect_postinc + jra fp_do_scc + +fp_predecr: + fp_mode_addr_indirect_predec + jra fp_do_scc + +fp_disp16: + fp_mode_addr_indirect_disp16 + jra fp_do_scc + +fp_extmode0: + fp_mode_addr_indirect_extmode0 + jra fp_do_scc + +fp_extmode1: + bfextu %d2{#13,#3},%d0 + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: + .long fp_absolute_short, fp_absolute_long + .long fp_ill, fp_ill | NOTE: jump here to ftrap.x + .long fp_ill, fp_ill + .long fp_ill, fp_ill + +fp_absolute_short: + fp_mode_abs_short + jra fp_do_scc + +fp_absolute_long: + fp_mode_abs_long +| jra fp_do_scc + +fp_do_scc: + swap %d1 + putuser.b %d1,(%a0),fp_err_ua1,%a0 + printf PDECODE,"\n" + jra fp_end + + +#define tst_NAN btst #24,%d1 +#define tst_Z btst #26,%d1 +#define tst_N btst #27,%d1 + +fp_compute_cond: + move.l (FPD_FPSR,FPDATA),%d1 + btst #4,%d0 + jeq 1f + tst_NAN + jeq 1f + bset #15,%d1 + bset #7,%d1 + move.l %d1,(FPD_FPSR,FPDATA) +1: and.w #0xf,%d0 + jmp ([0f:w,%pc,%d0.w*4]) + + .align 4 +0: + .long fp_f , fp_eq , fp_ogt, fp_oge + .long fp_olt, fp_ole, fp_ogl, fp_or + .long fp_un , fp_ueq, fp_ugt, fp_uge + .long fp_ult, fp_ule, fp_ne , fp_t + +fp_f: + moveq #0,%d0 + rts + +fp_eq: + moveq #0,%d0 + tst_Z + jeq 1f + moveq #-1,%d0 +1: rts + +fp_ogt: + moveq #0,%d0 + tst_NAN + jne 1f + tst_Z + jne 1f + tst_N + jne 1f + moveq #-1,%d0 +1: rts + +fp_oge: + moveq #-1,%d0 + tst_Z + jne 2f + tst_NAN + jne 1f + tst_N + jeq 2f +1: moveq #0,%d0 +2: rts + +fp_olt: + moveq #0,%d0 + tst_NAN + jne 1f + tst_Z + jne 1f + tst_N + jeq 1f + moveq #-1,%d0 +1: rts + +fp_ole: + moveq #-1,%d0 + tst_Z + jne 2f + tst_NAN + jne 1f + tst_N + jne 2f +1: moveq #0,%d0 +2: rts + +fp_ogl: + moveq #0,%d0 + tst_NAN + jne 1f + tst_Z + jne 1f + moveq #-1,%d0 +1: rts + +fp_or: + moveq #0,%d0 + tst_NAN + jne 1f + moveq #-1,%d0 +1: rts + +fp_un: + moveq #0,%d0 + tst_NAN + jeq 1f + moveq #-1,%d0 + rts + +fp_ueq: + moveq #-1,%d0 + tst_NAN + jne 1f + tst_Z + jne 1f + moveq #0,%d0 +1: rts + +fp_ugt: + moveq #-1,%d0 + tst_NAN + jne 2f + tst_N + jne 1f + tst_Z + jeq 2f +1: moveq #0,%d0 +2: rts + +fp_uge: + moveq #-1,%d0 + tst_NAN + jne 1f + tst_Z + jne 1f + tst_N + jeq 1f + moveq #0,%d0 +1: rts + +fp_ult: + moveq #-1,%d0 + tst_NAN + jne 2f + tst_Z + jne 1f + tst_N + jne 2f +1: moveq #0,%d0 +2: rts + +fp_ule: + moveq #-1,%d0 + tst_NAN + jne 1f + tst_Z + jne 1f + tst_N + jne 1f + moveq #0,%d0 +1: rts + +fp_ne: + moveq #0,%d0 + tst_Z + jne 1f + moveq #-1,%d0 +1: rts + +fp_t: + moveq #-1,%d0 + rts diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_decode.h linux/arch/m68k/math-emu/fp_decode.h --- v2.2.17/arch/m68k/math-emu/fp_decode.h Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_decode.h Fri Oct 13 23:36:54 2000 @@ -0,0 +1,417 @@ +/* + * fp_decode.h + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FP_DECODE_H +#define _FP_DECODE_H + +/* These macros do the dirty work of the instr decoding, several variables + * can be defined in the source file to modify the work of these macros, + * currently the following variables are used: + * ... + * The register usage: + * d0 - will contain source operand for data direct mode, + * otherwise scratch register + * d1 - upper 16bit are reserved for caller + * lower 16bit may contain further arguments, + * is destroyed during decoding + * d2 - contains first two instruction words, + * first word will be used for extension word + * a0 - will point to source/dest operand for any indirect mode + * otherwise scratch register + * a1 - scratch register + * a2 - base addr to the task structure + * + * the current implementation doesn't check for every disallowed + * addressing mode (e.g. pc relative modes as destination), as long + * as it only means a new addressing mode, which should not appear + * in a program and that doesn't crash the emulation, I think it's + * not a problem to allow these modes. + */ + +do_fmovem=0 +do_fmovem_cr=0 +do_no_pc_mode=0 +do_fscc=0 + +| first decoding of the instr type +| this seperates the conditional instr +.macro fp_decode_cond_instr_type + bfextu %d2{#8,#2},%d0 + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: +| .long "f","fscc/fdbcc" +| .long "fbccw","fbccl" +.endm + +| second decoding of the instr type +| this seperates most move instr +.macro fp_decode_move_instr_type + bfextu %d2{#16,#3},%d0 + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: +| .long "f fpx,fpx","invalid instr" +| .long "f ,fpx","fmove fpx," +| .long "fmovem ,fpcr","fmovem ,fpx" +| .long "fmovem fpcr,","fmovem fpx," +.endm + +| extract the source specifier, specifies +| either source fp register or data format +.macro fp_decode_sourcespec + bfextu %d2{#19,#3},%d0 +.endm + +| decode destination format for fmove reg,ea +.macro fp_decode_dest_format + bfextu %d2{#19,#3},%d0 +.endm + +| decode source register for fmove reg,ea +.macro fp_decode_src_reg + bfextu %d2{#22,#3},%d0 +.endm + +| extract the addressing mode +| it depends on the instr which of the modes is valid +.macro fp_decode_addr_mode + bfextu %d2{#10,#3},%d0 + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: +| .long "data register direct","addr register direct" +| .long "addr register indirect" +| .long "addr register indirect postincrement" +| .long "addr register indirect predecrement" +| .long "addr register + index16" +| .long "extension mode1","extension mode2" +.endm + +| extract the register for the addressing mode +.macro fp_decode_addr_reg + bfextu %d2{#13,#3},%d0 +.endm + +| decode the 8bit diplacement from the brief extension word +.macro fp_decode_disp8 + move.b %d2,%d0 + ext.w %d0 +.endm + +| decode the index of the brief/full extension word +.macro fp_decode_index + bfextu %d2{#17,#3},%d0 | get the register nr + btst #15,%d2 | test for data/addr register + jne 1\@f + printf PDECODE,"d%d",1,%d0 + jsr fp_get_data_reg + jra 2\@f +1\@: printf PDECODE,"a%d",1,%d0 + jsr fp_get_addr_reg + move.l %a0,%d0 +2\@: +debug lea "'l'.w,%a0" + btst #11,%d2 | 16/32 bit size? + jne 3\@f +debug lea "'w'.w,%a0" + ext.l %d0 +3\@: printf PDECODE,":%c",1,%a0 + move.w %d2,%d1 | scale factor + rol.w #7,%d1 + and.w #3,%d1 +debug move.l "%d1,-(%sp)" +debug ext.l "%d1" + printf PDECODE,":%d",1,%d1 +debug move.l "(%sp)+,%d1" + lsl.l %d1,%d0 +.endm + +| decode the base displacement size +.macro fp_decode_basedisp + bfextu %d2{#26,#2},%d0 + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: +| .long "reserved","null displacement" +| .long "word displacement","long displacement" +.endm + +.macro fp_decode_outerdisp + bfextu %d2{#30,#2},%d0 + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: +| .long "no memory indirect action/reserved","null outer displacement" +| .long "word outer displacement","long outer displacement" +.endm + +| get the extension word and test for brief or full extension type +.macro fp_get_test_extword label + fp_get_instr_word %d2,fp_err_ua1 + btst #8,%d2 + jne \label +.endm + + +| test if %pc is the base register for the indirect addr mode +.macro fp_test_basereg_d16 label + btst #20,%d2 + jeq \label +.endm + +| test if %pc is the base register for one of the extended modes +.macro fp_test_basereg_ext label + btst #19,%d2 + jeq \label +.endm + +.macro fp_test_suppr_index label + btst #6,%d2 + jne \label +.endm + + +| addressing mode: data register direct +.macro fp_mode_data_direct + fp_decode_addr_reg + printf PDECODE,"d%d",1,%d0 +.endm + +| addressing mode: address register indirect +.macro fp_mode_addr_indirect + fp_decode_addr_reg + printf PDECODE,"(a%d)",1,%d0 + jsr fp_get_addr_reg +.endm + +| adjust stack for byte moves from/to stack +.macro fp_test_sp_byte_move + .if !do_fmovem + .if do_fscc + move.w #6,%d1 + .endif + cmp.w #7,%d0 + jne 1\@f + .if !do_fscc + cmp.w #6,%d1 + jne 1\@f + .endif + move.w #4,%d1 +1\@: + .endif +.endm + +| addressing mode: address register indirect with postincrement +.macro fp_mode_addr_indirect_postinc + fp_decode_addr_reg + printf PDECODE,"(a%d)+",1,%d0 + fp_test_sp_byte_move + jsr fp_get_addr_reg + move.l %a0,%a1 | save addr + .if do_fmovem + lea (%a0,%d1.w*4),%a0 + .if !do_fmovem_cr + lea (%a0,%d1.w*8),%a0 + .endif + .else + add.w (fp_datasize,%d1.w*2),%a0 + .endif + jsr fp_put_addr_reg + move.l %a1,%a0 +.endm + +| addressing mode: address register indirect with predecrement +.macro fp_mode_addr_indirect_predec + fp_decode_addr_reg + printf PDECODE,"-(a%d)",1,%d0 + fp_test_sp_byte_move + jsr fp_get_addr_reg + .if do_fmovem + .if !do_fmovem_cr + lea (-12,%a0),%a1 | setup to addr of 1st reg to move + neg.w %d1 + lea (%a0,%d1.w*4),%a0 + add.w %d1,%d1 + lea (%a0,%d1.w*4),%a0 + jsr fp_put_addr_reg + move.l %a1,%a0 + .else + neg.w %d1 + lea (%a0,%d1.w*4),%a0 + jsr fp_put_addr_reg + .endif + .else + sub.w (fp_datasize,%d1.w*2),%a0 + jsr fp_put_addr_reg + .endif +.endm + +| addressing mode: address register/programm counter indirect +| with 16bit displacement +.macro fp_mode_addr_indirect_disp16 + .if !do_no_pc_mode + fp_test_basereg_d16 1f + printf PDECODE,"pc" + fp_get_pc %a0 + jra 2f + .endif +1: fp_decode_addr_reg + printf PDECODE,"a%d",1,%d0 + jsr fp_get_addr_reg +2: fp_get_instr_word %a1,fp_err_ua1 + printf PDECODE,"@(%x)",1,%a1 + add.l %a1,%a0 +.endm + +| perform preindex (if I/IS == 0xx and xx != 00) +.macro fp_do_preindex + moveq #3,%d0 + and.w %d2,%d0 + jeq 1f + btst #2,%d2 + jne 1f + printf PDECODE,")@(" + getuser.l (%a1),%a1,fp_err_ua1,%a1 +debug jra "2f" +1: printf PDECODE,"," +2: +.endm + +| perform postindex (if I/IS == 1xx) +.macro fp_do_postindex + btst #2,%d2 + jeq 1f + printf PDECODE,")@(" + getuser.l (%a1),%a1,fp_err_ua1,%a1 +debug jra "2f" +1: printf PDECODE,"," +2: +.endm + +| all other indirect addressing modes will finally end up here +.macro fp_mode_addr_indirect_extmode0 + .if !do_no_pc_mode + fp_test_basereg_ext 1f + printf PDECODE,"pc" + fp_get_pc %a0 + jra 2f + .endif +1: fp_decode_addr_reg + printf PDECODE,"a%d",1,%d0 + jsr fp_get_addr_reg +2: move.l %a0,%a1 + swap %d2 + fp_get_test_extword 3f + | addressing mode: address register/programm counter indirect + | with index and 8bit displacement + fp_decode_disp8 +debug ext.l "%d0" + printf PDECODE,"@(%x,",1,%d0 + add.w %d0,%a1 + fp_decode_index + add.l %d0,%a1 + printf PDECODE,")" + jra 9f +3: | addressing mode: address register/programm counter memory indirect + | with base and/or outer displacement + btst #7,%d2 | base register suppressed? + jeq 1f + printf PDECODE,"!" + sub.l %a1,%a1 +1: printf PDECODE,"@(" + fp_decode_basedisp + + .long fp_ill,1f + .long 2f,3f + +#ifdef FPU_EMU_DEBUG +1: printf PDECODE,"0" | null base displacement + jra 1f +#endif +2: fp_get_instr_word %a0,fp_err_ua1 | 16bit base displacement + printf PDECODE,"%x:w",1,%a0 + jra 4f +3: fp_get_instr_long %a0,fp_err_ua1 | 32bit base displacement + printf PDECODE,"%x:l",1,%a0 +4: add.l %a0,%a1 +1: + fp_do_postindex + fp_test_suppr_index 1f + fp_decode_index + add.l %d0,%a1 +1: fp_do_preindex + + fp_decode_outerdisp + + .long 5f,1f + .long 2f,3f + +#ifdef FPU_EMU_DEBUG +1: printf PDECODE,"0" | null outer displacement + jra 1f +#endif +2: fp_get_instr_word %a0,fp_err_ua1 | 16bit outer displacement + printf PDECODE,"%x:w",1,%a0 + jra 4f +3: fp_get_instr_long %a0,fp_err_ua1 | 32bit outer displacement + printf PDECODE,"%x:l",1,%a0 +4: add.l %a0,%a1 +1: +5: printf PDECODE,")" +9: move.l %a1,%a0 + swap %d2 +.endm + +| get the absolute short address from user space +.macro fp_mode_abs_short + fp_get_instr_word %a0,fp_err_ua1 + printf PDECODE,"%x.w",1,%a0 +.endm + +| get the absolute long address from user space +.macro fp_mode_abs_long + fp_get_instr_long %a0,fp_err_ua1 + printf PDECODE,"%x.l",1,%a0 +.endm + +#endif /* _FP_DECODE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_emu.h linux/arch/m68k/math-emu/fp_emu.h --- v2.2.17/arch/m68k/math-emu/fp_emu.h Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_emu.h Fri Oct 13 23:36:54 2000 @@ -0,0 +1,137 @@ +/* + * fp_emu.h + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FP_EMU_H +#define _FP_EMU_H + +#ifndef __ASSEMBLY__ + +#include + +#define IS_INF(a) ((a)->exp == 0x7fff) +#define IS_ZERO(a) ((a)->mant.m64 == 0) + + +#define fp_set_sr(bit) ({ \ + FPDATA->fpsr |= 1 << (bit); \ +}) + +#define fp_set_quotient(quotient) ({ \ + FPDATA->fpsr &= 0xff00ffff; \ + FPDATA->fpsr |= ((quotient) & 0xff) << 16; \ +}) + +/* linkage for several useful functions */ + +/* Normalize the extended struct, return 0 for a NaN */ +#define fp_normalize_ext(fpreg) ({ \ + register struct fp_ext *reg asm ("a0") = fpreg; \ + register int res asm ("d0"); \ + \ + asm volatile ("jsr fp_conv_ext2ext" \ + : "=d" (res) : "a" (reg) \ + : "a1", "d1", "d2", "memory"); \ + res; \ +}) + +#define fp_copy_ext(dest, src) ({ \ + *dest = *src; \ +}) + +#define fp_monadic_check(dest, src) ({ \ + fp_copy_ext(dest, src); \ + if (!fp_normalize_ext(dest)) \ + return dest; \ +}) + +#define fp_dyadic_check(dest, src) ({ \ + if (!fp_normalize_ext(dest)) \ + return dest; \ + if (!fp_normalize_ext(src)) { \ + fp_copy_ext(dest, src); \ + return dest; \ + } \ +}) + +extern const struct fp_ext fp_QNaN; +extern const struct fp_ext fp_Inf; + +#define fp_set_nan(dest) ({ \ + fp_set_sr(FPSR_EXC_OPERR); \ + *dest = fp_QNaN; \ +}) + +/* TODO check rounding mode? */ +#define fp_set_ovrflw(dest) ({ \ + fp_set_sr(FPSR_EXC_OVFL); \ + dest->exp = 0x7fff; \ + dest->mant.m64 = 0; \ +}) + +#define fp_conv_ext2long(src) ({ \ + register struct fp_ext *__src asm ("a0") = src; \ + register int __res asm ("d0"); \ + \ + asm volatile ("jsr fp_conv_ext2long" \ + : "=d" (__res) : "a" (__src) \ + : "a1", "d1", "d2", "memory"); \ + __res; \ +}) + +#else /* __ASSEMBLY__ */ + +#include "../kernel/m68k_defs.h" +#include + +/* + * set, reset or clear a bit in the fp status register + */ +.macro fp_set_sr bit + bset #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA) +.endm + +.macro fp_clr_sr bit + bclr #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA) +.endm + +.macro fp_tst_sr bit + btst #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA) +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _FP_EMU_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_entry.S linux/arch/m68k/math-emu/fp_entry.S --- v2.2.17/arch/m68k/math-emu/fp_entry.S Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_entry.S Fri Oct 13 23:36:54 2000 @@ -0,0 +1,324 @@ +/* + * fp_emu.S + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "fp_emu.h" + + .globl SYMBOL_NAME(fpu_emu) + .globl fp_debugprint + .globl fp_err_ua1,fp_err_ua2 + + .text +SYMBOL_NAME_LABEL(fpu_emu) + SAVE_ALL_INT + GET_CURRENT(%d0) + +#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060) + tst.l SYMBOL_NAME(m68k_is040or060) + jeq 1f +#endif +#if defined(CPU_M68040_OR_M68060) + move.l (FPS_PC2,%sp),(FPS_PC,%sp) +#endif +1: + | emulate the instruction + jsr fp_scan + +#if defined(CONFIG_M68060) +#if !defined(CPU_M68060_ONLY) + btst #3,SYMBOL_NAME(m68k_cputype)+3 + jeq 1f +#endif + btst #7,(FPS_SR,%sp) + jne fp_sendtrace060 +#endif +1: + | emulation successful? + tst.l %d0 + jeq SYMBOL_NAME(ret_from_exception) + + | send some signal to program here + + jra SYMBOL_NAME(ret_from_exception) + + | we jump here after an access error while trying to access + | user space, we correct stackpointer and send a SIGSEGV to + | the user process +fp_err_ua2: + addq.l #4,%sp +fp_err_ua1: + addq.l #4,%sp + move.l %a0,-(%sp) + pea SEGV_MAPERR + pea SIGSEGV + jsr SYMBOL_NAME(fpemu_signal) + add.w #12,%sp + jra SYMBOL_NAME(ret_from_exception) + +#if defined(CONFIG_M68060) + | send a trace signal if we are debugged + | it does not really belong here, but... +fp_sendtrace060: + move.l (FPS_PC,%sp),-(%sp) + pea TRAP_TRACE + pea SIGTRAP + jsr SYMBOL_NAME(fpemu_signal) + add.w #12,%sp + jra SYMBOL_NAME(ret_from_exception) +#endif + + .globl fp_get_data_reg, fp_put_data_reg + .globl fp_get_addr_reg, fp_put_addr_reg + + | Entry points to get/put a register. Some of them can be get/put + | directly, others are on the stack, as we read/write the stack + | directly here, these function may only be called from within + | instruction decoding, otherwise the stack pointer is incorrect + | and the stack gets corrupted. +fp_get_data_reg: + jmp ([0f:w,%pc,%d0.w*4]) + + .align 4 +0: + .long fp_get_d0, fp_get_d1 + .long fp_get_d2, fp_get_d3 + .long fp_get_d4, fp_get_d5 + .long fp_get_d6, fp_get_d7 + +fp_get_d0: + move.l (PT_D0+8,%sp),%d0 + printf PREGISTER,"{d0->%08x}",1,%d0 + rts + +fp_get_d1: + move.l (PT_D1+8,%sp),%d0 + printf PREGISTER,"{d1->%08x}",1,%d0 + rts + +fp_get_d2: + move.l (PT_D2+8,%sp),%d0 + printf PREGISTER,"{d2->%08x}",1,%d0 + rts + +fp_get_d3: + move.l %d3,%d0 + printf PREGISTER,"{d3->%08x}",1,%d0 + rts + +fp_get_d4: + move.l %d4,%d0 + printf PREGISTER,"{d4->%08x}",1,%d0 + rts + +fp_get_d5: + move.l %d5,%d0 + printf PREGISTER,"{d5->%08x}",1,%d0 + rts + +fp_get_d6: + move.l %d6,%d0 + printf PREGISTER,"{d6->%08x}",1,%d0 + rts + +fp_get_d7: + move.l %d7,%d0 + printf PREGISTER,"{d7->%08x}",1,%d0 + rts + +fp_put_data_reg: + jmp ([0f:w,%pc,%d1.w*4]) + + .align 4 +0: + .long fp_put_d0, fp_put_d1 + .long fp_put_d2, fp_put_d3 + .long fp_put_d4, fp_put_d5 + .long fp_put_d6, fp_put_d7 + +fp_put_d0: + printf PREGISTER,"{d0<-%08x}",1,%d0 + move.l %d0,(PT_D0+8,%sp) + rts + +fp_put_d1: + printf PREGISTER,"{d1<-%08x}",1,%d0 + move.l %d0,(PT_D1+8,%sp) + rts + +fp_put_d2: + printf PREGISTER,"{d2<-%08x}",1,%d0 + move.l %d0,(PT_D2+8,%sp) + rts + +fp_put_d3: + printf PREGISTER,"{d3<-%08x}",1,%d0 +| move.l %d0,%d3 + move.l %d0,(PT_D3+8,%sp) + rts + +fp_put_d4: + printf PREGISTER,"{d4<-%08x}",1,%d0 +| move.l %d0,%d4 + move.l %d0,(PT_D4+8,%sp) + rts + +fp_put_d5: + printf PREGISTER,"{d5<-%08x}",1,%d0 +| move.l %d0,%d5 + move.l %d0,(PT_D5+8,%sp) + rts + +fp_put_d6: + printf PREGISTER,"{d6<-%08x}",1,%d0 + move.l %d0,%d6 + rts + +fp_put_d7: + printf PREGISTER,"{d7<-%08x}",1,%d0 + move.l %d0,%d7 + rts + +fp_get_addr_reg: + jmp ([0f:w,%pc,%d0.w*4]) + + .align 4 +0: + .long fp_get_a0, fp_get_a1 + .long fp_get_a2, fp_get_a3 + .long fp_get_a4, fp_get_a5 + .long fp_get_a6, fp_get_a7 + +fp_get_a0: + move.l (PT_A0+8,%sp),%a0 + printf PREGISTER,"{a0->%08x}",1,%a0 + rts + +fp_get_a1: + move.l (PT_A1+8,%sp),%a0 + printf PREGISTER,"{a1->%08x}",1,%a0 + rts + +fp_get_a2: + move.l (PT_A2+8,%sp),%a0 + printf PREGISTER,"{a2->%08x}",1,%a0 + rts + +fp_get_a3: + move.l %a3,%a0 + printf PREGISTER,"{a3->%08x}",1,%a0 + rts + +fp_get_a4: + move.l %a4,%a0 + printf PREGISTER,"{a4->%08x}",1,%a0 + rts + +fp_get_a5: + move.l %a5,%a0 + printf PREGISTER,"{a5->%08x}",1,%a0 + rts + +fp_get_a6: + move.l %a6,%a0 + printf PREGISTER,"{a6->%08x}",1,%a0 + rts + +fp_get_a7: + move.l %usp,%a0 + printf PREGISTER,"{a7->%08x}",1,%a0 + rts + +fp_put_addr_reg: + jmp ([0f:w,%pc,%d0.w*4]) + + .align 4 +0: + .long fp_put_a0, fp_put_a1 + .long fp_put_a2, fp_put_a3 + .long fp_put_a4, fp_put_a5 + .long fp_put_a6, fp_put_a7 + +fp_put_a0: + printf PREGISTER,"{a0<-%08x}",1,%a0 + move.l %a0,(PT_A0+8,%sp) + rts + +fp_put_a1: + printf PREGISTER,"{a1<-%08x}",1,%a0 + move.l %a0,(PT_A1+8,%sp) + rts + +fp_put_a2: + printf PREGISTER,"{a2<-%08x}",1,%a0 + move.l %a0,(PT_A2+8,%sp) + rts + +fp_put_a3: + printf PREGISTER,"{a3<-%08x}",1,%a0 + move.l %a0,%a3 + rts + +fp_put_a4: + printf PREGISTER,"{a4<-%08x}",1,%a0 + move.l %a0,%a4 + rts + +fp_put_a5: + printf PREGISTER,"{a5<-%08x}",1,%a0 + move.l %a0,%a5 + rts + +fp_put_a6: + printf PREGISTER,"{a6<-%08x}",1,%a0 + move.l %a0,%a6 + rts + +fp_put_a7: + printf PREGISTER,"{a7<-%08x}",1,%a0 + move.l %a0,%usp + rts + + .data + .align 4 + +fp_debugprint: +| .long PMDECODE + .long PMINSTR+PMDECODE+PMCONV+PMNORM +| .long PMCONV+PMNORM+PMINSTR +| .long 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_log.c linux/arch/m68k/math-emu/fp_log.c --- v2.2.17/arch/m68k/math-emu/fp_log.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_log.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,142 @@ +/* + + fp_trig.c: floating-point math routines for the Linux-m68k + floating point emulator. + + Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel. + + I hereby give permission, free of charge, to copy, modify, and + redistribute this software, in source or binary form, provided that + the above copyright notice and the following disclaimer are included + in all such copies. + + THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL + OR IMPLIED. + +*/ + +#include "fp_emu.h" + +struct fp_ext * +fp_fsqrt(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsqrt\n"); + + fp_monadic_check(dest, src); + + if (IS_ZERO(dest)) + return dest; + + if (dest->sign) { + fp_set_nan(dest); + return dest; + } + if (IS_INF(dest)) + return dest; + + return dest; +} + +struct fp_ext * +fp_fetoxm1(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fetoxm1\n"); + + fp_monadic_check(dest, src); + + if (IS_ZERO(dest)) + return dest; + + return dest; +} + +struct fp_ext * +fp_fetox(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fetox\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_ftwotox(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("ftwotox\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_ftentox(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("ftentox\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_flogn(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("flogn\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_flognp1(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("flognp1\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_flog10(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("flog10\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_flog2(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("flog2\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fgetexp(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fgetexp\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fgetman(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fgetman\n"); + + fp_monadic_check(dest, src); + + return dest; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_move.S linux/arch/m68k/math-emu/fp_move.S --- v2.2.17/arch/m68k/math-emu/fp_move.S Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_move.S Fri Oct 13 23:36:54 2000 @@ -0,0 +1,244 @@ +/* + * fp_move.S + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fp_emu.h" +#include "fp_decode.h" + +do_no_pc_mode=1 + + .globl fp_fmove_fp2mem + +fp_fmove_fp2mem: + clr.b (2+FPD_FPSR,FPDATA) + fp_decode_dest_format + move.w %d0,%d1 | store data size twice in %d1 + swap %d1 | one can be trashed below + move.w %d0,%d1 +#ifdef FPU_EMU_DEBUG + lea 0f,%a0 + clr.l %d0 + move.b (%a0,%d1.w),%d0 + printf PDECODE,"fmove.%c ",1,%d0 + fp_decode_src_reg + printf PDECODE,"fp%d,",1,%d0 + + .data +0: .byte 'l','s','x','p','w','d','b','p' + .previous +#endif + + | encode addressing mode for dest + fp_decode_addr_mode + + .long fp_data, fp_ill + .long fp_indirect, fp_postinc + .long fp_predecr, fp_disp16 + .long fp_extmode0, fp_extmode1 + + | addressing mode: data register direct +fp_data: + fp_mode_data_direct + move.w %d0,%d1 + fp_decode_src_reg + fp_get_fp_reg + lea (FPD_TEMPFP1,FPDATA),%a1 + move.l (%a0)+,(%a1)+ + move.l (%a0)+,(%a1)+ + move.l (%a0),(%a1) + lea (-8,%a1),%a0 + swap %d1 + move.l %d1,%d2 + printf PDECODE,"\n" + jmp ([0f:w,%pc,%d1.w*4]) + + .align 4 +0: + .long fp_data_long, fp_data_single + .long fp_ill, fp_ill + .long fp_data_word, fp_ill + .long fp_data_byte, fp_ill + +fp_data_byte: + jsr fp_normalize_ext + jsr fp_conv_ext2byte + move.l %d0,%d1 + swap %d2 + move.w %d2,%d0 + jsr fp_get_data_reg + move.b %d1,%d0 + move.w %d2,%d1 + jsr fp_put_data_reg + jra fp_final + +fp_data_word: + jsr fp_normalize_ext + jsr fp_conv_ext2short + move.l %d0,%d1 + swap %d2 + move.w %d2,%d0 + jsr fp_get_data_reg + move.w %d1,%d0 + move.l %d2,%d1 + jsr fp_put_data_reg + jra fp_final + +fp_data_long: + jsr fp_normalize_ext + jsr fp_conv_ext2long + swap %d2 + move.w %d2,%d1 + jsr fp_put_data_reg + jra fp_final + +fp_data_single: + jsr fp_normalize_ext + jsr fp_conv_ext2single + swap %d2 + move.w %d2,%d1 + jsr fp_put_data_reg + jra fp_final + + | addressing mode: address register indirect +fp_indirect: + fp_mode_addr_indirect + jra fp_putdest + + | addressing mode: address register indirect with postincrement +fp_postinc: + fp_mode_addr_indirect_postinc + jra fp_putdest + + | addressing mode: address register indirect with predecrement +fp_predecr: + fp_mode_addr_indirect_predec + jra fp_putdest + + | addressing mode: address register indirect with 16bit displacement +fp_disp16: + fp_mode_addr_indirect_disp16 + jra fp_putdest + +fp_extmode0: + fp_mode_addr_indirect_extmode0 + jra fp_putdest + +fp_extmode1: + fp_decode_addr_reg + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: + .long fp_abs_short, fp_abs_long + .long fp_ill, fp_ill + .long fp_ill, fp_ill + .long fp_ill, fp_ill + +fp_abs_short: + fp_mode_abs_short + jra fp_putdest + +fp_abs_long: + fp_mode_abs_long + jra fp_putdest + +fp_putdest: + move.l %a0,%a1 + fp_decode_src_reg + move.l %d1,%d2 | save size + fp_get_fp_reg + printf PDECODE,"\n" + addq.l #8,%a0 + move.l (%a0),-(%sp) + move.l -(%a0),-(%sp) + move.l -(%a0),-(%sp) + move.l %sp,%a0 + jsr fp_normalize_ext + + swap %d2 + jmp ([0f:w,%pc,%d2.w*4]) + + .align 4 +0: + .long fp_format_long, fp_format_single + .long fp_format_extended, fp_format_packed + .long fp_format_word, fp_format_double + .long fp_format_byte, fp_format_packed + +fp_format_long: + jsr fp_conv_ext2long + putuser.l %d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + +fp_format_single: + jsr fp_conv_ext2single + putuser.l %d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + +fp_format_extended: + move.l (%a0)+,%d0 + lsl.w #1,%d0 + lsl.l #7,%d0 + lsl.l #8,%d0 + putuser.l %d0,(%a1)+,fp_err_ua1,%a1 + move.l (%a0)+,%d0 + putuser.l %d0,(%a1)+,fp_err_ua1,%a1 + move.l (%a0),%d0 + putuser.l %d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + +fp_format_packed: + /* not supported yet */ + lea (12,%sp),%sp + jra fp_ill + +fp_format_word: + jsr fp_conv_ext2short + putuser.w %d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + +fp_format_double: + jsr fp_conv_ext2double + jra fp_finish_move + +fp_format_byte: + jsr fp_conv_ext2byte + putuser.b %d0,(%a1),fp_err_ua1,%a1 +| jra fp_finish_move + +fp_finish_move: + lea (12,%sp),%sp + jra fp_final diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_movem.S linux/arch/m68k/math-emu/fp_movem.S --- v2.2.17/arch/m68k/math-emu/fp_movem.S Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_movem.S Fri Oct 13 23:36:54 2000 @@ -0,0 +1,368 @@ +/* + * fp_movem.S + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fp_emu.h" +#include "fp_decode.h" + +| set flags for decode macros for fmovem +do_fmovem=1 + + .globl fp_fmovem_fp, fp_fmovem_cr + +| %d1 contains the mask and count of the register list +| for other register usage see fp_decode.h + +fp_fmovem_fp: + printf PDECODE,"fmovem.x " + | get register list and count them + btst #11,%d2 + jne 1f + bfextu %d2{#24,#8},%d0 | static register list + jra 2f +1: bfextu %d2{#25,#3},%d0 | dynamic register list + jsr fp_get_data_reg +2: move.l %d0,%d1 + swap %d1 + jra 2f +1: addq.w #1,%d1 | count the # of registers in +2: lsr.b #1,%d0 | register list and keep it in %d1 + jcs 1b + jne 2b + printf PDECODE,"#%08x",1,%d1 +#ifdef FPU_EMU_DEBUG + btst #12,%d2 + jne 1f + printf PDECODE,"-" | decremental move + jra 2f +1: printf PDECODE,"+" | incremental move +2: btst #13,%d2 + jeq 1f + printf PDECODE,"->" | fpu -> cpu + jra 2f +1: printf PDECODE,"<-" | fpu <- cpu +2: +#endif + + | decode address mode + fp_decode_addr_mode + + .long fp_ill, fp_ill + .long fpr_indirect, fpr_postinc + .long fpr_predecr, fpr_disp16 + .long fpr_extmode0, fpr_extmode1 + + | addressing mode: address register indirect +fpr_indirect: + fp_mode_addr_indirect + jra fpr_do_movem + + | addressing mode: address register indirect with postincrement +fpr_postinc: + fp_mode_addr_indirect_postinc + jra fpr_do_movem + +fpr_predecr: + fp_mode_addr_indirect_predec + jra fpr_do_movem + + | addressing mode: address register/programm counter indirect + | with 16bit displacement +fpr_disp16: + fp_mode_addr_indirect_disp16 + jra fpr_do_movem + +fpr_extmode0: + fp_mode_addr_indirect_extmode0 + jra fpr_do_movem + +fpr_extmode1: + fp_decode_addr_reg + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: + .long fpr_absolute_short, fpr_absolute_long + .long fpr_disp16, fpr_extmode0 + .long fp_ill, fp_ill + .long fp_ill, fp_ill + +fpr_absolute_short: + fp_mode_abs_short + jra fpr_do_movem + +fpr_absolute_long: + fp_mode_abs_long +| jra fpr_do_movem + +fpr_do_movem: + swap %d1 | get fpu register list + lea (FPD_FPREG,FPDATA),%a1 + moveq #12,%d0 + btst #12,%d2 + jne 1f + lea (-12,%a1,%d0*8),%a1 + neg.l %d0 +1: btst #13,%d2 + jne 4f + | move register from memory into fpu + jra 3f +1: printf PMOVEM,"(%p>%p)",2,%a0,%a1 + getuser.l (%a0)+,%d2,fp_err_ua1,%a0 + lsr.l #8,%d2 + lsr.l #7,%d2 + lsr.w #1,%d2 + move.l %d2,(%a1)+ + getuser.l (%a0)+,%d2,fp_err_ua1,%a0 + move.l %d2,(%a1)+ + getuser.l (%a0),%d2,fp_err_ua1,%a0 + move.l %d2,(%a1) + subq.l #8,%a0 + subq.l #8,%a1 + add.l %d0,%a0 +2: add.l %d0,%a1 +3: lsl.b #1,%d1 + jcs 1b + jne 2b + jra 5f + | move register from fpu into memory +1: printf PMOVEM,"(%p>%p)",2,%a1,%a0 + move.l (%a1)+,%d2 + lsl.w #1,%d2 + lsl.l #7,%d2 + lsl.l #8,%d2 + putuser.l %d2,(%a0)+,fp_err_ua1,%a0 + move.l (%a1)+,%d2 + putuser.l %d2,(%a0)+,fp_err_ua1,%a0 + move.l (%a1),%d2 + putuser.l %d2,(%a0),fp_err_ua1,%a0 + subq.l #8,%a1 + subq.l #8,%a0 + add.l %d0,%a0 +2: add.l %d0,%a1 +4: lsl.b #1,%d1 + jcs 1b + jne 2b +5: + printf PDECODE,"\n" +#if 0 + lea (FPD_FPREG,FPDATA),%a0 + printf PMOVEM,"fp:" + printx PMOVEM,%a0@(0) + printx PMOVEM,%a0@(12) + printf PMOVEM,"\n " + printx PMOVEM,%a0@(24) + printx PMOVEM,%a0@(36) + printf PMOVEM,"\n " + printx PMOVEM,%a0@(48) + printx PMOVEM,%a0@(60) + printf PMOVEM,"\n " + printx PMOVEM,%a0@(72) + printx PMOVEM,%a0@(84) + printf PMOVEM,"\n" +#endif + jra fp_end + +| set flags for decode macros for fmovem control register +do_fmovem=1 +do_fmovem_cr=1 + +fp_fmovem_cr: + printf PDECODE,"fmovem.cr " + | get register list and count them + bfextu %d2{#19,#3},%d0 + move.l %d0,%d1 + swap %d1 + jra 2f +1: addq.w #1,%d1 +2: lsr.l #1,%d0 + jcs 1b + jne 2b + printf PDECODE,"#%08x",1,%d1 +#ifdef FPU_EMU_DEBUG + btst #13,%d2 + jeq 1f + printf PDECODE,"->" | fpu -> cpu + jra 2f +1: printf PDECODE,"<-" | fpu <- cpu +2: +#endif + + | decode address mode + fp_decode_addr_mode + + .long fpc_data, fpc_addr + .long fpc_indirect, fpc_postinc + .long fpc_predecr, fpc_disp16 + .long fpc_extmode0, fpc_extmode1 + +fpc_data: + fp_mode_data_direct + move.w %d0,%d1 + bfffo %d2{#19,#3},%d0 + sub.w #19,%d0 + lea (FPD_FPCR,FPDATA,%d0.w*4),%a1 + btst #13,%d2 + jne 1f + move.w %d1,%d0 + jsr fp_get_data_reg + move.l %d0,(%a1) + jra fpc_movem_fin +1: move.l (%a1),%d0 + jsr fp_put_data_reg + jra fpc_movem_fin + +fpc_addr: + fp_decode_addr_reg + printf PDECODE,"a%d",1,%d0 + btst #13,%d2 + jne 1f + jsr fp_get_addr_reg + move.l %a0,(FPD_FPIAR,FPDATA) + jra fpc_movem_fin +1: move.l (FPD_FPIAR,FPDATA),%a0 + jsr fp_put_addr_reg + jra fpc_movem_fin + +fpc_indirect: + fp_mode_addr_indirect + jra fpc_do_movem + +fpc_postinc: + fp_mode_addr_indirect_postinc + jra fpc_do_movem + +fpc_predecr: + fp_mode_addr_indirect_predec + jra fpc_do_movem + +fpc_disp16: + fp_mode_addr_indirect_disp16 + jra fpc_do_movem + +fpc_extmode0: + fp_mode_addr_indirect_extmode0 + jra fpc_do_movem + +fpc_extmode1: + fp_decode_addr_reg + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: + .long fpc_absolute_short, fpc_absolute_long + .long fpc_disp16, fpc_extmode0 + .long fpc_immediate, fp_ill + .long fp_ill, fp_ill + +fpc_absolute_short: + fp_mode_abs_short + jra fpc_do_movem + +fpc_absolute_long: + fp_mode_abs_long + jra fpc_do_movem + +fpc_immediate: + fp_get_pc %a0 + lea (%a0,%d1.w*4),%a1 + fp_put_pc %a1 + printf PDECODE,"#imm" +| jra fpc_do_movem +#if 0 + swap %d1 + lsl.l #5,%d1 + lea (FPD_FPCR,FPDATA),%a0 + jra 3f +1: move.l %d0,(%a0) +2: addq.l #4,%a0 +3: lsl.b #1,%d1 + jcs 1b + jne 2b + jra fpc_movem_fin +#endif + +fpc_do_movem: + swap %d1 | get fpu register list + lsl.l #5,%d1 + lea (FPD_FPCR,FPDATA),%a1 +1: btst #13,%d2 + jne 4f + + | move register from memory into fpu + jra 3f +1: printf PMOVEM,"(%p>%p)",2,%a0,%a1 + getuser.l (%a0)+,%d0,fp_err_ua1,%a0 + move.l %d0,(%a1) +2: addq.l #4,%a1 +3: lsl.b #1,%d1 + jcs 1b + jne 2b + jra fpc_movem_fin + + | move register from fpu into memory +1: printf PMOVEM,"(%p>%p)",2,%a1,%a0 + move.l (%a1),%d0 + putuser.l %d0,(%a0)+,fp_err_ua1,%a0 +2: addq.l #4,%a1 +4: lsl.b #1,%d1 + jcs 1b + jne 2b + +fpc_movem_fin: + and.l #0x0000fff0,(FPD_FPCR,FPDATA) + and.l #0x0ffffff8,(FPD_FPSR,FPDATA) + move.l (FPD_FPCR,FPDATA),%d0 + lsr.l #4,%d0 + moveq #3,%d1 + and.l %d0,%d1 + move.w %d1,(FPD_RND,FPDATA) + lsr.l #2,%d0 + moveq #3,%d1 + and.l %d0,%d1 + move.w %d1,(FPD_PREC,FPDATA) + printf PDECODE,"\n" +#if 0 + printf PMOVEM,"fpcr : %08x\n",1,FPDATA@(FPD_FPCR) + printf PMOVEM,"fpsr : %08x\n",1,FPDATA@(FPD_FPSR) + printf PMOVEM,"fpiar: %08x\n",1,FPDATA@(FPD_FPIAR) + clr.l %d0 + move.w (FPD_PREC,FPDATA),%d0 + printf PMOVEM,"prec : %04x\n",1,%d0 + move.w (FPD_RND,FPDATA),%d0 + printf PMOVEM,"rnd : %04x\n",1,%d0 +#endif + jra fp_end diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_scan.S linux/arch/m68k/math-emu/fp_scan.S --- v2.2.17/arch/m68k/math-emu/fp_scan.S Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_scan.S Fri Oct 13 23:36:54 2000 @@ -0,0 +1,478 @@ +/* + * fp_scan.S + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fp_emu.h" +#include "fp_decode.h" + + .globl fp_scan, fp_datasize + + .data + +| %d2 - first two instr words +| %d1 - operand size + +/* operand formats are: + + Long = 0, i.e. fmove.l + Single, i.e. fmove.s + Extended, i.e. fmove.x + Packed-BCD, i.e. fmove.p + Word, i.e. fmove.w + Double, i.e. fmove.d +*/ + + .text + +| On entry: +| FPDATA - base of emulated FPU registers + +fp_scan: +| normal fpu instruction? (this excludes fsave/frestore) + fp_get_pc %a0 + printf PDECODE,"%08x: ",1,%a0 + getuser.b (%a0),%d0,fp_err_ua1,%a0 +#if 1 + cmp.b #0xf2,%d0 | cpid = 1 +#else + cmp.b #0xfc,%d0 | cpid = 6 +#endif + jne fp_nonstd +| first two instruction words are kept in %d2 + getuser.l (%a0)+,%d2,fp_err_ua1,%a0 + fp_put_pc %a0 +fp_decode_cond: | seperate conditional instr + fp_decode_cond_instr_type + + .long fp_decode_move, fp_fscc + .long fp_fbccw, fp_fbccl + +fp_decode_move: | seperate move instr + fp_decode_move_instr_type + + .long fp_fgen_fp, fp_ill + .long fp_fgen_ea, fp_fmove_fp2mem + .long fp_fmovem_cr, fp_fmovem_cr + .long fp_fmovem_fp, fp_fmovem_fp + +| now all arithmetic instr and a few move instr are left +fp_fgen_fp: | source is a fpu register + clr.b (FPD_FPSR+2,FPDATA) | clear the exception byte + fp_decode_sourcespec + printf PDECODE,"f.x fp%d",1,%d0 + fp_get_fp_reg + lea (FPD_TEMPFP1,FPDATA),%a1 | copy src into a temp location + move.l (%a0)+,(%a1)+ + move.l (%a0)+,(%a1)+ + move.l (%a0),(%a1) + lea (-8,%a1),%a0 + jra fp_getdest + +fp_fgen_ea: | source is + clr.b (FPD_FPSR+2,FPDATA) | clear the exception byte + | sort out fmovecr, keep data size in %d1 + fp_decode_sourcespec + cmp.w #7,%d0 + jeq fp_fmovecr + move.w %d0,%d1 | store data size twice in %d1 + swap %d1 | one can be trashed below + move.w %d0,%d1 +#ifdef FPU_EMU_DEBUG + lea 0f,%a0 + clr.l %d0 + move.b (%a0,%d1.w),%d0 + printf PDECODE,"f.%c ",1,%d0 + + .data +0: .byte 'l','s','x','p','w','d','b',0 + .previous +#endif + +/* + fp_getsource, fp_getdest + + basically, we end up with a pointer to the source operand in + %a1, and a pointer to the destination operand in %a0. both + are, of course, 96-bit extended floating point numbers. +*/ + +fp_getsource: + | decode addressing mode for source + fp_decode_addr_mode + + .long fp_data, fp_ill + .long fp_indirect, fp_postinc + .long fp_predecr, fp_disp16 + .long fp_extmode0, fp_extmode1 + + | addressing mode: data register direct +fp_data: + fp_mode_data_direct + jsr fp_get_data_reg + lea (FPD_TEMPFP1,FPDATA),%a0 + jmp ([0f:w,%pc,%d1.w*4]) + + .align 4 +0: + .long fp_data_long, fp_data_single + .long fp_ill, fp_ill + .long fp_data_word, fp_ill + .long fp_data_byte, fp_ill + + | data types that fit in an integer data register +fp_data_byte: + extb.l %d0 + jra fp_data_long + +fp_data_word: + ext.l %d0 + +fp_data_long: + jsr fp_conv_long2ext + jra fp_getdest + +fp_data_single: + jsr fp_conv_single2ext + jra fp_getdest + + | addressing mode: address register indirect +fp_indirect: + fp_mode_addr_indirect + jra fp_fetchsource + + | addressing mode: address register indirect with postincrement +fp_postinc: + fp_mode_addr_indirect_postinc + jra fp_fetchsource + + | addressing mode: address register indirect with predecrement +fp_predecr: + fp_mode_addr_indirect_predec + jra fp_fetchsource + + | addressing mode: address register/programm counter indirect + | with 16bit displacement +fp_disp16: + fp_mode_addr_indirect_disp16 + jra fp_fetchsource + + | all other indirect addressing modes will finally end up here +fp_extmode0: + fp_mode_addr_indirect_extmode0 + jra fp_fetchsource + +| all pc relative addressing modes and immediate/absolute modes end up here +| the first ones are sent to fp_extmode0 or fp_disp16 +| and only the latter are handled here +fp_extmode1: + fp_decode_addr_reg + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: + .long fp_abs_short, fp_abs_long + .long fp_disp16, fp_extmode0 + .long fp_immediate, fp_ill + .long fp_ill, fp_ill + + | addressing mode: absolute short +fp_abs_short: + fp_mode_abs_short + jra fp_fetchsource + + | addressing mode: absolute long +fp_abs_long: + fp_mode_abs_long + jra fp_fetchsource + + | addressing mode: immediate data +fp_immediate: + printf PDECODE,"#" + fp_get_pc %a0 + move.w (fp_datasize,%d1.w*2),%d0 + addq.w #1,%d0 + and.w #-2,%d0 +#ifdef FPU_EMU_DEBUG + movem.l %d0/%d1,-(%sp) + movel %a0,%a1 + clr.l %d1 + jra 2f +1: getuser.b (%a1)+,%d1,fp_err_ua1,%a1 + printf PDECODE,"%02x",1,%d1 +2: dbra %d0,1b + movem.l (%sp)+,%d0/%d1 +#endif + lea (%a0,%d0.w),%a1 + fp_put_pc %a1 +| jra fp_fetchsource + +fp_fetchsource: + move.l %a0,%a1 + swap %d1 + lea (FPD_TEMPFP1,FPDATA),%a0 + jmp ([0f:w,%pc,%d1.w*4]) + + .align 4 +0: .long fp_long, fp_single + .long fp_ext, fp_pack + .long fp_word, fp_double + .long fp_byte, fp_ill + +fp_long: + getuser.l (%a1),%d0,fp_err_ua1,%a1 + jsr fp_conv_long2ext + jra fp_getdest + +fp_single: + getuser.l (%a1),%d0,fp_err_ua1,%a1 + jsr fp_conv_single2ext + jra fp_getdest + +fp_ext: + getuser.l (%a1)+,%d0,fp_err_ua1,%a1 + lsr.l #8,%d0 + lsr.l #7,%d0 + lsr.w #1,%d0 + move.l %d0,(%a0)+ + getuser.l (%a1)+,%d0,fp_err_ua1,%a1 + move.l %d0,(%a0)+ + getuser.l (%a1),%d0,fp_err_ua1,%a1 + move.l %d0,(%a0) + subq.l #8,%a0 + jra fp_getdest + +fp_pack: + /* not supported yet */ + jra fp_ill + +fp_word: + getuser.w (%a1),%d0,fp_err_ua1,%a1 + ext.l %d0 + jsr fp_conv_long2ext + jra fp_getdest + +fp_double: + jsr fp_conv_double2ext + jra fp_getdest + +fp_byte: + getuser.b (%a1),%d0,fp_err_ua1,%a1 + extb.l %d0 + jsr fp_conv_long2ext +| jra fp_getdest + +fp_getdest: + move.l %a0,%a1 + bfextu %d2{#22,#3},%d0 + printf PDECODE,",fp%d\n",1,%d0 + fp_get_fp_reg + movem.l %a0/%a1,-(%sp) + pea fp_finalrounding + bfextu %d2{#25,#7},%d0 + jmp ([0f:w,%pc,%d0*4]) + + .align 4 +0: + .long fp_fmove_mem2fp, fp_fint, fp_fsinh, fp_fintrz + .long fp_fsqrt, fp_ill, fp_flognp1, fp_ill + .long fp_fetoxm1, fp_ftanh, fp_fatan, fp_ill + .long fp_fasin, fp_fatanh, fp_fsin, fp_ftan + .long fp_fetox, fp_ftwotox, fp_ftentox, fp_ill + .long fp_flogn, fp_flog10, fp_flog2, fp_ill + .long fp_fabs, fp_fcosh, fp_fneg, fp_ill + .long fp_facos, fp_fcos, fp_fgetexp, fp_fgetman + .long fp_fdiv, fp_fmod, fp_fadd, fp_fmul + .long fpa_fsgldiv, fp_frem, fp_fscale, fpa_fsglmul + .long fp_fsub, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_fsincos0, fp_fsincos1, fp_fsincos2, fp_fsincos3 + .long fp_fsincos4, fp_fsincos5, fp_fsincos6, fp_fsincos7 + .long fp_fcmp, fp_ill, fp_ftst, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_fsmove, fp_fssqrt, fp_ill, fp_ill + .long fp_fdmove, fp_fdsqrt, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_fsabs, fp_ill, fp_fsneg, fp_ill + .long fp_fdabs, fp_ill, fp_fdneg, fp_ill + .long fp_fsdiv, fp_ill, fp_fsadd, fp_fsmul + .long fp_fddiv, fp_ill, fp_fdadd, fp_fdmul + .long fp_fssub, fp_ill, fp_ill, fp_ill + .long fp_fdsub, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + .long fp_ill, fp_ill, fp_ill, fp_ill + + | Instructions follow + + | Move an (emulated) ROM constant +fp_fmovecr: + bfextu %d2{#27,#5},%d0 + printf PINSTR,"fp_fmovecr #%d",1,%d0 + move.l %d0,%d1 + add.l %d0,%d0 + add.l %d1,%d0 + lea (fp_constants,%d0*4),%a0 + move.l #0x801cc0ff,%d0 + addq.l #1,%d1 + lsl.l %d1,%d0 + jcc 1f + fp_set_sr FPSR_EXC_INEX2 | INEX2 exception +1: moveq #-128,%d0 | continue with fmove + and.l %d0,%d2 + jra fp_getdest + + .data + .align 4 +fp_constants: + .long 0x00004000,0xc90fdaa2,0x2168c235 | pi + .extend 0,0,0,0,0,0,0,0,0,0 + .long 0x00003ffd,0x9a209a84,0xfbcff798 | log10(2) + .long 0x00004000,0xadf85458,0xa2bb4a9a | e + .long 0x00003fff,0xb8aa3b29,0x5c17f0bc | log2(e) + .long 0x00003ffd,0xde5bd8a9,0x37287195 | log10(e) + .long 0x00000000,0x00000000,0x00000000 | 0.0 + .long 0x00003ffe,0xb17217f7,0xd1cf79ac | 1n(2) + .long 0x00004000,0x935d8ddd,0xaaa8ac17 | 1n(10) + | read this as "1.0 * 2^0" - note the high bit in the mantissa + .long 0x00003fff,0x80000000,0x00000000 | 10^0 + .long 0x00004002,0xa0000000,0x00000000 | 10^1 + .long 0x00004005,0xc8000000,0x00000000 | 10^2 + .long 0x0000400c,0x9c400000,0x00000000 | 10^4 + .long 0x00004019,0xbebc2000,0x00000000 | 10^8 + .long 0x00004034,0x8e1bc9bf,0x04000000 | 10^16 + .long 0x00004069,0x9dc5ada8,0x2b70b59e | 10^32 + .long 0x000040d3,0xc2781f49,0xffcfa6d5 | 10^64 + .long 0x000041a8,0x93ba47c9,0x80e98ce0 | 10^128 + .long 0x00004351,0xaa7eebfb,0x9df9de8e | 10^256 + .long 0x000046a3,0xe319a0ae,0xa60e91c7 | 10^512 + .long 0x00004d48,0xc9767586,0x81750c17 | 10^1024 + .long 0x00005a92,0x9e8b3b5d,0xc53d5de5 | 10^2048 + .long 0x00007525,0xc4605202,0x8a20979b | 10^4096 + .previous + +fp_fmove_mem2fp: + printf PINSTR,"fmove %p,%p\n",2,%a0,%a1 + move.l (%a1)+,(%a0)+ + move.l (%a1)+,(%a0)+ + move.l (%a1),(%a0) + subq.l #8,%a0 + rts + +fpa_fsglmul: + move.l #fp_finalrounding_single_fast,(%sp) + jra fp_fsglmul + +fpa_fsgldiv: + move.l #fp_finalrounding_single_fast,(%sp) + jra fp_fsgldiv + +.macro fp_dosingleprec instr + printf PINSTR,"single " + move.l #fp_finalrounding_single,(%sp) + jra \instr +.endm + +.macro fp_dodoubleprec instr + printf PINSTR,"double " + move.l #fp_finalrounding_double,(%sp) + jra \instr +.endm + +fp_fsmove: + fp_dosingleprec fp_fmove_mem2fp + +fp_fssqrt: + fp_dosingleprec fp_fsqrt + +fp_fdmove: + fp_dodoubleprec fp_fmove_mem2fp + +fp_fdsqrt: + fp_dodoubleprec fp_fsqrt + +fp_fsabs: + fp_dosingleprec fp_fabs + +fp_fsneg: + fp_dosingleprec fp_fneg + +fp_fdabs: + fp_dodoubleprec fp_fabs + +fp_fdneg: + fp_dodoubleprec fp_fneg + +fp_fsdiv: + fp_dosingleprec fp_fdiv + +fp_fsadd: + fp_dosingleprec fp_fadd + +fp_fsmul: + fp_dosingleprec fp_fmul + +fp_fddiv: + fp_dodoubleprec fp_fdiv + +fp_fdadd: + fp_dodoubleprec fp_fadd + +fp_fdmul: + fp_dodoubleprec fp_fmul + +fp_fssub: + fp_dosingleprec fp_fsub + +fp_fdsub: + fp_dodoubleprec fp_fsub + +fp_nonstd: + fp_get_pc %a0 + getuser.l (%a0),%d0,fp_err_ua1,%a0 + printf ,"nonstd ((%08x)=%08x)\n",2,%a0,%d0 + moveq #-1,%d0 + rts + + .data + .align 4 + + | data sizes corresponding to the operand formats +fp_datasize: + .word 4, 4, 12, 12, 2, 8, 1, 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_trig.c linux/arch/m68k/math-emu/fp_trig.c --- v2.2.17/arch/m68k/math-emu/fp_trig.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_trig.c Fri Oct 13 23:36:54 2000 @@ -0,0 +1,183 @@ +/* + + fp_trig.c: floating-point math routines for the Linux-m68k + floating point emulator. + + Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel. + + I hereby give permission, free of charge, to copy, modify, and + redistribute this software, in source or binary form, provided that + the above copyright notice and the following disclaimer are included + in all such copies. + + THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL + OR IMPLIED. + +*/ + +#include "fp_emu.h" +#include "fp_trig.h" + +struct fp_ext * +fp_fsin(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsin\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fcos(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fcos\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_ftan(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("ftan\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fasin(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fasin\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_facos(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("facos\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fatan(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fatan\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fsinh(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsinh\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fcosh(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fcosh\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_ftanh(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("ftanh\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fatanh(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fatanh\n"); + + fp_monadic_check(dest, src); + + return dest; +} + +struct fp_ext * +fp_fsincos0(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos0\n"); + + return dest; +} + +struct fp_ext * +fp_fsincos1(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos1\n"); + + return dest; +} + +struct fp_ext * +fp_fsincos2(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos2\n"); + + return dest; +} + +struct fp_ext * +fp_fsincos3(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos3\n"); + + return dest; +} + +struct fp_ext * +fp_fsincos4(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos4\n"); + + return dest; +} + +struct fp_ext * +fp_fsincos5(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos5\n"); + + return dest; +} + +struct fp_ext * +fp_fsincos6(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos6\n"); + + return dest; +} + +struct fp_ext * +fp_fsincos7(struct fp_ext *dest, struct fp_ext *src) +{ + uprint("fsincos7\n"); + + return dest; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_trig.h linux/arch/m68k/math-emu/fp_trig.h --- v2.2.17/arch/m68k/math-emu/fp_trig.h Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_trig.h Fri Oct 13 23:36:54 2000 @@ -0,0 +1,32 @@ +/* + + fp_trig.h: floating-point math routines for the Linux-m68k + floating point emulator. + + Copyright (c) 1998 David Huggins-Daines. + + I hereby give permission, free of charge, to copy, modify, and + redistribute this software, in source or binary form, provided that + the above copyright notice and the following disclaimer are included + in all such copies. + + THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL + OR IMPLIED. + +*/ + +#ifndef FP_TRIG_H +#define FP_TRIG_H + +#include "fp_emu.h" + +/* floating point trigonometric instructions: + + the arguments to these are in the "internal" extended format, that + is, an "exploded" version of the 96-bit extended fp format used by + the 68881. + + they return a status code, which should end up in %d0, if all goes + well. */ + +#endif /* FP_TRIG__H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/fp_util.S linux/arch/m68k/math-emu/fp_util.S --- v2.2.17/arch/m68k/math-emu/fp_util.S Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/fp_util.S Fri Oct 13 23:36:55 2000 @@ -0,0 +1,1454 @@ +/* + * fp_util.S + * + * Copyright Roman Zippel, 1997. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fp_emu.h" + +/* + * Here are lots of conversion and normalization functions mainly + * used by fp_scan.S + * Note that these functions are optimized for "normal" numbers, + * these are handled first and exit as fast as possible, this is + * especially important for fp_normalize_ext/fp_conv_ext2ext, as + * it's called very often. + * The register usage is optimized for fp_scan.S and which register + * is currently at that time unused, be careful if you want change + * something here. %d0 and %d1 is always usable, sometimes %d2 (or + * only the lower half) most function have to return the %a0 + * unmodified, so that the caller can immediatly reuse it. + */ + + .globl fp_ill, fp_end + + | exits from fp_scan: + | illegal instruction +fp_ill: + printf ,"fp_illegal\n" + rts + | completed instruction +fp_end: + tst.l (TASK_MM-8,%a2) + jmi 1f + tst.l (TASK_MM-4,%a2) + jmi 1f + tst.l (TASK_MM,%a2) + jpl 2f +1: printf ,"oops:%p,%p,%p\n",3,%a2@(TASK_MM-8),%a2@(TASK_MM-4),%a2@(TASK_MM) +2: clr.l %d0 + rts + + .globl fp_conv_long2ext, fp_conv_single2ext + .globl fp_conv_double2ext, fp_conv_ext2ext + .globl fp_normalize_ext, fp_normalize_double + .globl fp_normalize_single, fp_normalize_single_fast + .globl fp_conv_ext2double, fp_conv_ext2single + .globl fp_conv_ext2long, fp_conv_ext2short + .globl fp_conv_ext2byte + .globl fp_finalrounding_single, fp_finalrounding_single_fast + .globl fp_finalrounding_double + .globl fp_finalrounding, fp_finaltest, fp_final + +/* + * First several conversion functions from a source operand + * into the extended format. Note, that only fp_conv_ext2ext + * normalizes the number and is always called after the other + * conversion functions, which only move the information into + * fp_ext structure. + */ + + | fp_conv_long2ext: + | + | args: %d0 = source (32-bit long) + | %a0 = destination (ptr to struct fp_ext) + +fp_conv_long2ext: + printf PCONV,"l2e: %p -> %p(",2,%d0,%a0 + clr.l %d1 | sign defaults to zero + tst.l %d0 + jeq fp_l2e_zero | is source zero? + jpl 1f | positive? + moveq #1,%d1 + neg.l %d0 +1: swap %d1 + move.w #0x3fff+31,%d1 + move.l %d1,(%a0)+ | set sign / exp + move.l %d0,(%a0)+ | set mantissa + clr.l (%a0) + subq.l #8,%a0 | restore %a0 + printx PCONV,%a0@ + printf PCONV,")\n" + rts + | source is zero +fp_l2e_zero: + clr.l (%a0)+ + clr.l (%a0)+ + clr.l (%a0) + subq.l #8,%a0 + printx PCONV,%a0@ + printf PCONV,")\n" + rts + + | fp_conv_single2ext + | args: %d0 = source (single-precision fp value) + | %a0 = dest (struct fp_ext *) + +fp_conv_single2ext: + printf PCONV,"s2e: %p -> %p(",2,%d0,%a0 + move.l %d0,%d1 + lsl.l #8,%d0 | shift mantissa + lsr.l #8,%d1 | exponent / sign + lsr.l #7,%d1 + lsr.w #8,%d1 + jeq fp_s2e_small | zero / denormal? + cmp.w #0xff,%d1 | NaN / Inf? + jeq fp_s2e_large + bset #31,%d0 | set explizit bit + add.w #0x3fff-0x7f,%d1 | re-bias the exponent. +9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp + move.l %d0,(%a0)+ | high lword of fp_ext.mant + clr.l (%a0) | low lword = 0 + subq.l #8,%a0 + printx PCONV,%a0@ + printf PCONV,")\n" + rts + | zeros and denormalized +fp_s2e_small: + | exponent is zero, so explizit bit is already zero too + tst.l %d0 + jeq 9b + move.w #0x4000-0x7f,%d1 + jra 9b + | infinities and NAN +fp_s2e_large: + bclr #31,%d0 | clear explizit bit + move.w #0x7fff,%d1 + jra 9b + +fp_conv_double2ext: +#ifdef FPU_EMU_DEBUG + getuser.l %a1@(0),%d0,fp_err_ua2,%a1 + getuser.l %a1@(4),%d1,fp_err_ua2,%a1 + printf PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0 +#endif + getuser.l (%a1)+,%d0,fp_err_ua2,%a1 + move.l %d0,%d1 + lsl.l #8,%d0 | shift high mantissa + lsl.l #3,%d0 + lsr.l #8,%d1 | exponent / sign + lsr.l #7,%d1 + lsr.w #5,%d1 + jeq fp_d2e_small | zero / denormal? + cmp.w #0x7ff,%d1 | NaN / Inf? + jeq fp_d2e_large + bset #31,%d0 | set explizit bit + add.w #0x3fff-0x3ff,%d1 | re-bias the exponent. +9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp + move.l %d0,(%a0)+ + getuser.l (%a1)+,%d0,fp_err_ua2,%a1 + move.l %d0,%d1 + lsl.l #8,%d0 + lsl.l #3,%d0 + move.l %d0,(%a0) + moveq #21,%d0 + lsr.l %d0,%d1 + or.l %d1,-(%a0) + subq.l #4,%a0 + printx PCONV,%a0@ + printf PCONV,")\n" + rts + | zeros and denormalized +fp_d2e_small: + | exponent is zero, so explizit bit is already zero too + tst.l %d0 + jeq 9b + move.w #0x4000-0x3ff,%d1 + jra 9b + | infinities and NAN +fp_d2e_large: + bclr #31,%d0 | clear explizit bit + move.w #0x7fff,%d1 + jra 9b + + | fp_conv_ext2ext: + | originally used to get longdouble from userspace, now it's + | called before arithmetic operations to make sure the number + | is normalized [maybe rename it?]. + | args: %a0 = dest (struct fp_ext *) + | returns 0 in %d0 for a NaN, otherwise 1 + +fp_conv_ext2ext: + printf PCONV,"e2e: %p(",1,%a0 + printx PCONV,%a0@ + printf PCONV,"), " + move.l (%a0)+,%d0 + cmp.w #0x7fff,%d0 | Inf / NaN? + jeq fp_e2e_large + move.l (%a0),%d0 + jpl fp_e2e_small | zero / denorm? + | The high bit is set, so normalization is irrelevant. +fp_e2e_checkround: + subq.l #4,%a0 +#ifdef CONFIG_FPU_EMU_EXTRAPREC + move.b (%a0),%d0 + jne fp_e2e_round +#endif + printf PCONV,"%p(",1,%a0 + printx PCONV,%a0@ + printf PCONV,")\n" + moveq #1,%d0 + rts +#ifdef CONFIG_FPU_EMU_EXTRAPREC +fp_e2e_round: + fp_set_sr FPSR_EXC_INEX2 + clr.b (%a0) + move.w (FPD_RND,FPDATA),%d2 + jne fp_e2e_roundother | %d2 == 0, round to nearest + tst.b %d0 | test guard bit + jpl 9f | zero is closer + btst #0,(11,%a0) | test lsb bit + jne fp_e2e_doroundup | round to infinity + lsl.b #1,%d0 | check low bits + jeq 9f | round to zero +fp_e2e_doroundup: + addq.l #1,(8,%a0) + jcc 9f + addq.l #1,(4,%a0) + jcc 9f + move.w #0x8000,(4,%a0) + addq.w #1,(2,%a0) +9: printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +fp_e2e_roundother: + subq.w #2,%d2 + jcs 9b | %d2 < 2, round to zero + jhi 1f | %d2 > 2, round to +infinity + tst.b (1,%a0) | to -inf + jne fp_e2e_doroundup | negative, round to infinity + jra 9b | positive, round to zero +1: tst.b (1,%a0) | to +inf + jeq fp_e2e_doroundup | positive, round to infinity + jra 9b | negative, round to zero +#endif + | zeros and subnormals: + | try to normalize these anyway. +fp_e2e_small: + jne fp_e2e_small1 | high lword zero? + move.l (4,%a0),%d0 + jne fp_e2e_small2 +#ifdef CONFIG_FPU_EMU_EXTRAPREC + clr.l %d0 + move.b (-4,%a0),%d0 + jne fp_e2e_small3 +#endif + | Genuine zero. + clr.w -(%a0) + subq.l #2,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + moveq #1,%d0 + rts + | definitely subnormal, need to shift all 64 bits +fp_e2e_small1: + bfffo %d0{#0,#32},%d1 + move.w -(%a0),%d2 + sub.w %d1,%d2 + jcc 1f + | Pathologically small, denormalize. + add.w %d2,%d1 + clr.w %d2 +1: move.w %d2,(%a0)+ + move.w %d1,%d2 + jeq fp_e2e_checkround + | fancy 64-bit double-shift begins here + lsl.l %d2,%d0 + move.l %d0,(%a0)+ + move.l (%a0),%d0 + move.l %d0,%d1 + lsl.l %d2,%d0 + move.l %d0,(%a0) + neg.w %d2 + and.w #0x1f,%d2 + lsr.l %d2,%d1 + or.l %d1,-(%a0) +#ifdef CONFIG_FPU_EMU_EXTRAPREC +fp_e2e_extra1: + clr.l %d0 + move.b (-4,%a0),%d0 + neg.w %d2 + add.w #24,%d2 + jcc 1f + clr.b (-4,%a0) + lsl.l %d2,%d0 + or.l %d0,(4,%a0) + jra fp_e2e_checkround +1: addq.w #8,%d2 + lsl.l %d2,%d0 + move.b %d0,(-4,%a0) + lsr.l #8,%d0 + or.l %d0,(4,%a0) +#endif + jra fp_e2e_checkround + | pathologically small subnormal +fp_e2e_small2: + bfffo %d0{#0,#32},%d1 + add.w #32,%d1 + move.w -(%a0),%d2 + sub.w %d1,%d2 + jcc 1f + | Beyond pathologically small, denormalize. + add.w %d2,%d1 + clr.w %d2 +1: move.w %d2,(%a0)+ + ext.l %d1 + jeq fp_e2e_checkround + clr.l (4,%a0) + sub.w #32,%d2 + jcs 1f + lsl.l %d1,%d0 | lower lword needs only to be shifted + move.l %d0,(%a0) | into the higher lword +#ifdef CONFIG_FPU_EMU_EXTRAPREC + clr.l %d0 + move.b (-4,%a0),%d0 + clr.b (-4,%a0) + neg.w %d1 + add.w #32,%d1 + bfins %d0,(%a0){%d1,#8} +#endif + jra fp_e2e_checkround +1: neg.w %d1 | lower lword is splitted between + bfins %d0,(%a0){%d1,#32} | higher and lower lword +#ifndef CONFIG_FPU_EMU_EXTRAPREC + jra fp_e2e_checkround +#else + move.w %d1,%d2 + jra fp_e2e_extra1 + | These are extremely small numbers, that will mostly end up as zero + | anyway, so this is only important for correct rounding. +fp_e2e_small3: + bfffo %d0{#24,#8},%d1 + add.w #40,%d1 + move.w -(%a0),%d2 + sub.w %d1,%d2 + jcc 1f + | Pathologically small, denormalize. + add.w %d2,%d1 + clr.w %d2 +1: move.w %d2,(%a0)+ + ext.l %d1 + jeq fp_e2e_checkround + cmp.w #8,%d1 + jcs 2f +1: clr.b (-4,%a0) + sub.w #64,%d1 + jcs 1f + add.w #24,%d1 + lsl.l %d1,%d0 + move.l %d0,(%a0) + jra fp_e2e_checkround +1: neg.w %d1 + bfins %d0,(%a0){%d1,#8} + jra fp_e2e_checkround +2: lsl.l %d1,%d0 + move.b %d0,(-4,%a0) + lsr.l #8,%d0 + move.b %d0,(7,%a0) + jra fp_e2e_checkround +#endif +1: move.l %d0,%d1 | lower lword is splitted between + lsl.l %d2,%d0 | higher and lower lword + move.l %d0,(%a0) + move.l %d1,%d0 + neg.w %d2 + add.w #32,%d2 + lsr.l %d2,%d0 + move.l %d0,-(%a0) + jra fp_e2e_checkround + | Infinities and NaNs +fp_e2e_large: + move.l (%a0)+,%d0 + jne 3f +1: tst.l (%a0) + jne 4f + moveq #1,%d0 +2: subq.l #8,%a0 + printf PCONV,"%p(",1,%a0 + printx PCONV,%a0@ + printf PCONV,")\n" + rts + | we have maybe a NaN, shift off the highest bit +3: lsl.l #1,%d0 + jeq 1b + | we have a NaN, clear the return value +4: clrl %d0 + jra 2b + + +/* + * Normalization functions. Call these on the output of general + * FP operators, and before any conversion into the destination + * formats. fp_normalize_ext has always to be called first, the + * following conversion functions expect an already normalized + * number. + */ + + | fp_normalize_ext: + | normalize an extended in extended (unpacked) format, basically + | it does the same as fp_conv_ext2ext, additionally it also does + | the necessary postprocessing checks. + | args: %a0 (struct fp_ext *) + | NOTE: it does _not_ modify %a0/%a1 and the upper word of %d2 + +fp_normalize_ext: + printf PNORM,"ne: %p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,"), " + move.l (%a0)+,%d0 + cmp.w #0x7fff,%d0 | Inf / NaN? + jeq fp_ne_large + move.l (%a0),%d0 + jpl fp_ne_small | zero / denorm? + | The high bit is set, so normalization is irrelevant. +fp_ne_checkround: + subq.l #4,%a0 +#ifdef CONFIG_FPU_EMU_EXTRAPREC + move.b (%a0),%d0 + jne fp_ne_round +#endif + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +#ifdef CONFIG_FPU_EMU_EXTRAPREC +fp_ne_round: + fp_set_sr FPSR_EXC_INEX2 + clr.b (%a0) + move.w (FPD_RND,FPDATA),%d2 + jne fp_ne_roundother | %d2 == 0, round to nearest + tst.b %d0 | test guard bit + jpl 9f | zero is closer + btst #0,(11,%a0) | test lsb bit + jne fp_ne_doroundup | round to infinity + lsl.b #1,%d0 | check low bits + jeq 9f | round to zero +fp_ne_doroundup: + addq.l #1,(8,%a0) + jcc 9f + addq.l #1,(4,%a0) + jcc 9f + addq.w #1,(2,%a0) + move.w #0x8000,(4,%a0) +9: printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +fp_ne_roundother: + subq.w #2,%d2 + jcs 9b | %d2 < 2, round to zero + jhi 1f | %d2 > 2, round to +infinity + tst.b (1,%a0) | to -inf + jne fp_ne_doroundup | negative, round to infinity + jra 9b | positive, round to zero +1: tst.b (1,%a0) | to +inf + jeq fp_ne_doroundup | positive, round to infinity + jra 9b | negative, round to zero +#endif + | Zeros and subnormal numbers + | These are probably merely subnormal, rather than "denormalized" + | numbers, so we will try to make them normal again. +fp_ne_small: + jne fp_ne_small1 | high lword zero? + move.l (4,%a0),%d0 + jne fp_ne_small2 +#ifdef CONFIG_FPU_EMU_EXTRAPREC + clr.l %d0 + move.b (-4,%a0),%d0 + jne fp_ne_small3 +#endif + | Genuine zero. + clr.w -(%a0) + subq.l #2,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + | Subnormal. +fp_ne_small1: + bfffo %d0{#0,#32},%d1 + move.w -(%a0),%d2 + sub.w %d1,%d2 + jcc 1f + | Pathologically small, denormalize. + add.w %d2,%d1 + clr.w %d2 + fp_set_sr FPSR_EXC_UNFL +1: move.w %d2,(%a0)+ + move.w %d1,%d2 + jeq fp_ne_checkround + | This is exactly the same 64-bit double shift as seen above. + lsl.l %d2,%d0 + move.l %d0,(%a0)+ + move.l (%a0),%d0 + move.l %d0,%d1 + lsl.l %d2,%d0 + move.l %d0,(%a0) + neg.w %d2 + and.w #0x1f,%d2 + lsr.l %d2,%d1 + or.l %d1,-(%a0) +#ifdef CONFIG_FPU_EMU_EXTRAPREC +fp_ne_extra1: + clr.l %d0 + move.b (-4,%a0),%d0 + neg.w %d2 + add.w #24,%d2 + jcc 1f + clr.b (-4,%a0) + lsl.l %d2,%d0 + or.l %d0,(4,%a0) + jra fp_ne_checkround +1: addq.w #8,%d2 + lsl.l %d2,%d0 + move.b %d0,(-4,%a0) + lsr.l #8,%d0 + or.l %d0,(4,%a0) +#endif + jra fp_ne_checkround + | May or may not be subnormal, if so, only 32 bits to shift. +fp_ne_small2: + bfffo %d0{#0,#32},%d1 + add.w #32,%d1 + move.w -(%a0),%d2 + sub.w %d1,%d2 + jcc 1f + | Beyond pathologically small, denormalize. + add.w %d2,%d1 + clr.w %d2 + fp_set_sr FPSR_EXC_UNFL +1: move.w %d2,(%a0)+ + ext.l %d1 + jeq fp_ne_checkround + clr.l (4,%a0) + sub.w #32,%d1 + jcs 1f + lsl.l %d1,%d0 | lower lword needs only to be shifted + move.l %d0,(%a0) | into the higher lword +#ifdef CONFIG_FPU_EMU_EXTRAPREC + clr.l %d0 + move.b (-4,%a0),%d0 + clr.b (-4,%a0) + neg.w %d1 + add.w #32,%d1 + bfins %d0,(%a0){%d1,#8} +#endif + jra fp_ne_checkround +1: neg.w %d1 | lower lword is splitted between + bfins %d0,(%a0){%d1,#32} | higher and lower lword +#ifndef CONFIG_FPU_EMU_EXTRAPREC + jra fp_ne_checkround +#else + move.w %d1,%d2 + jra fp_ne_extra1 + | These are extremely small numbers, that will mostly end up as zero + | anyway, so this is only important for correct rounding. +fp_ne_small3: + bfffo %d0{#24,#8},%d1 + add.w #40,%d1 + move.w -(%a0),%d2 + sub.w %d1,%d2 + jcc 1f + | Pathologically small, denormalize. + add.w %d2,%d1 + clr.w %d2 +1: move.w %d2,(%a0)+ + ext.l %d1 + jeq fp_ne_checkround + cmp.w #8,%d1 + jcs 2f +1: clr.b (-4,%a0) + sub.w #64,%d1 + jcs 1f + add.w #24,%d1 + lsl.l %d1,%d0 + move.l %d0,(%a0) + jra fp_ne_checkround +1: neg.w %d1 + bfins %d0,(%a0){%d1,#8} + jra fp_ne_checkround +2: lsl.l %d1,%d0 + move.b %d0,(-4,%a0) + lsr.l #8,%d0 + move.b %d0,(7,%a0) + jra fp_ne_checkround +#endif + | Infinities and NaNs, again, same as above. +fp_ne_large: + move.l (%a0)+,%d0 + jne 3f +1: tst.l (%a0) + jne 4f +2: subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + | we have maybe a NaN, shift off the highest bit +3: move.l %d0,%d1 + lsl.l #1,%d1 + jne 4f + clr.l (-4,%a0) + jra 1b + | we have a NaN, test if it is signaling +4: bset #30,%d0 + jne 2b + fp_set_sr FPSR_EXC_SNAN + move.l %d0,(-4,%a0) + jra 2b + + | these next two do rounding as per the IEEE standard. + | values for the rounding modes appear to be: + | 0: Round to nearest + | 1: Round to zero + | 2: Round to -Infinity + | 3: Round to +Infinity + | both functions expect that fp_normalize was already + | called (and extended argument is already normalized + | as far as possible), these are used if there is different + | rounding precision is selected and before converting + | into single/double + + | fp_normalize_double: + | normalize an extended with double (52-bit) precision + | args: %a0 (struct fp_ext *) + +fp_normalize_double: + printf PNORM,"nd: %p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,"), " + move.l (%a0)+,%d2 + tst.w %d2 + jeq fp_nd_zero | zero / denormalized + cmp.w #0x7fff,%d2 + jeq fp_nd_huge | NaN / infinitive. + sub.w #0x4000-0x3ff,%d2 | will the exponent fit? + jcs fp_nd_small | too small. + cmp.w #0x7fe,%d2 + jcc fp_nd_large | too big. + addq.l #4,%a0 + move.l (%a0),%d0 | low lword of mantissa + | now, round off the low 11 bits. +fp_nd_round: + moveq #21,%d1 + lsl.l %d1,%d0 | keep 11 low bits. + jne fp_nd_checkround | Are they non-zero? + | nothing to do here +9: subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + | Be careful with the X bit! It contains the lsb + | from the shift above, it is needed for round to nearest. +fp_nd_checkround: + fp_set_sr FPSR_EXC_INEX2 | INEX2 bit + and.w #0xf800,(2,%a0) | clear bits 0-10 + move.w (FPD_RND,FPDATA),%d2 | rounding mode + jne 2f | %d2 == 0, round to nearest + tst.l %d0 | test guard bit + jpl 9b | zero is closer + | here we test the X bit by adding it to %d2 + clr.w %d2 | first set z bit, addx only clears it + addx.w %d2,%d2 | test lsb bit + | IEEE754-specified "round to even" behaviour. If the guard + | bit is set, then the number is odd, so rounding works like + | in grade-school arithmetic (i.e. 1.5 rounds to 2.0) + | Otherwise, an equal distance rounds towards zero, so as not + | to produce an odd number. This is strange, but it is what + | the standard says. + jne fp_nd_doroundup | round to infinity + lsl.l #1,%d0 | check low bits + jeq 9b | round to zero +fp_nd_doroundup: + | round (the mantissa, that is) towards infinity + add.l #0x800,(%a0) + jcc 9b | no overflow, good. + addq.l #1,-(%a0) | extend to high lword + jcc 1f | no overflow, good. + | Yow! we have managed to overflow the mantissa. Since this + | only happens when %d1 was 0xfffff800, it is now zero, so + | reset the high bit, and increment the exponent. + move.w #0x8000,(%a0) + addq.w #1,-(%a0) + cmp.w #0x43ff,(%a0)+ | exponent now overflown? + jeq fp_nd_large | yes, so make it infinity. +1: subq.l #4,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +2: subq.w #2,%d2 + jcs 9b | %d2 < 2, round to zero + jhi 3f | %d2 > 2, round to +infinity + | Round to +Inf or -Inf. High word of %d2 contains the + | sign of the number, by the way. + swap %d2 | to -inf + tst.b %d2 + jne fp_nd_doroundup | negative, round to infinity + jra 9b | positive, round to zero +3: swap %d2 | to +inf + tst.b %d2 + jeq fp_nd_doroundup | positive, round to infinity + jra 9b | negative, round to zero + | Exponent underflow. Try to make a denormal, and set it to + | the smallest possible fraction if this fails. +fp_nd_small: + fp_set_sr FPSR_EXC_UNFL | set UNFL bit + move.w #0x3c01,(-2,%a0) | 2**-1022 + neg.w %d2 | degree of underflow + cmp.w #32,%d2 | single or double shift? + jcc 1f + | Again, another 64-bit double shift. + move.l (%a0),%d0 + move.l %d0,%d1 + lsr.l %d2,%d0 + move.l %d0,(%a0)+ + move.l (%a0),%d0 + lsr.l %d2,%d0 + neg.w %d2 + add.w #32,%d2 + lsl.l %d2,%d1 + or.l %d1,%d0 + move.l (%a0),%d1 + move.l %d0,(%a0) + | Check to see if we shifted off any significant bits + lsl.l %d2,%d1 + jeq fp_nd_round | Nope, round. + bset #0,%d0 | Yes, so set the "sticky bit". + jra fp_nd_round | Now, round. + | Another 64-bit single shift and store +1: sub.w #32,%d2 + cmp.w #32,%d2 | Do we really need to shift? + jcc 2f | No, the number is too small. + move.l (%a0),%d0 + clr.l (%a0)+ + move.l %d0,%d1 + lsr.l %d2,%d0 + neg.w %d2 + add.w #32,%d2 + | Again, check to see if we shifted off any significant bits. + tst.l (%a0) + jeq 1f + bset #0,%d0 | Sticky bit. +1: move.l %d0,(%a0) + lsl.l %d2,%d1 + jeq fp_nd_round + bset #0,%d0 + jra fp_nd_round + | Sorry, the number is just too small. +2: clr.l (%a0)+ + clr.l (%a0) + moveq #1,%d0 | Smallest possible fraction, + jra fp_nd_round | round as desired. + | zero and denormalized +fp_nd_zero: + tst.l (%a0)+ + jne 1f + tst.l (%a0) + jne 1f + subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts | zero. nothing to do. + | These are not merely subnormal numbers, but true denormals, + | i.e. pathologically small (exponent is 2**-16383) numbers. + | It is clearly impossible for even a normal extended number + | with that exponent to fit into double precision, so just + | write these ones off as "too darn small". +1: fp_set_sr FPSR_EXC_UNFL | Set UNFL bit + clr.l (%a0) + clr.l -(%a0) + move.w #0x3c01,-(%a0) | i.e. 2**-1022 + addq.l #6,%a0 + moveq #1,%d0 + jra fp_nd_round | round. + | Exponent overflow. Just call it infinity. +fp_nd_large: + move.w #0x7ff,%d0 + and.w (6,%a0),%d0 + jeq 1f + fp_set_sr FPSR_EXC_INEX2 +1: fp_set_sr FPSR_EXC_OVFL + move.w (FPD_RND,FPDATA),%d2 + jne 3f | %d2 = 0 round to nearest +1: move.w #0x7fff,(-2,%a0) + clr.l (%a0)+ + clr.l (%a0) +2: subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +3: subq.w #2,%d2 + jcs 5f | %d2 < 2, round to zero + jhi 4f | %d2 > 2, round to +infinity + tst.b (-3,%a0) | to -inf + jne 1b + jra 5f +4: tst.b (-3,%a0) | to +inf + jeq 1b +5: move.w #0x43fe,(-2,%a0) + moveq #-1,%d0 + move.l %d0,(%a0)+ + move.w #0xf800,%d0 + move.l %d0,(%a0) + jra 2b + | Infinities or NaNs +fp_nd_huge: + subq.l #4,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + + | fp_normalize_single: + | normalize an extended with single (23-bit) precision + | args: %a0 (struct fp_ext *) + +fp_normalize_single: + printf PNORM,"ns: %p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,") " + addq.l #2,%a0 + move.w (%a0)+,%d2 + jeq fp_ns_zero | zero / denormalized + cmp.w #0x7fff,%d2 + jeq fp_ns_huge | NaN / infinitive. + sub.w #0x4000-0x7f,%d2 | will the exponent fit? + jcs fp_ns_small | too small. + cmp.w #0xfe,%d2 + jcc fp_ns_large | too big. + move.l (%a0)+,%d0 | get high lword of mantissa +fp_ns_round: + tst.l (%a0) | check the low lword + jeq 1f + | Set a sticky bit if it is non-zero. This should only + | affect the rounding in what would otherwise be equal- + | distance situations, which is what we want it to do. + bset #0,%d0 +1: clr.l (%a0) | zap it from memory. + | now, round off the low 8 bits of the hi lword. + tst.b %d0 | 8 low bits. + jne fp_ns_checkround | Are they non-zero? + | nothing to do here + subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +fp_ns_checkround: + fp_set_sr FPSR_EXC_INEX2 | INEX2 bit + clr.b -(%a0) | clear low byte of high lword + subq.l #3,%a0 + move.w (FPD_RND,FPDATA),%d2 | rounding mode + jne 2f | %d2 == 0, round to nearest + tst.b %d0 | test guard bit + jpl 9f | zero is closer + btst #8,%d0 | test lsb bit + | round to even behaviour, see above. + jne fp_ns_doroundup | round to infinity + lsl.b #1,%d0 | check low bits + jeq 9f | round to zero +fp_ns_doroundup: + | round (the mantissa, that is) towards infinity + add.l #0x100,(%a0) + jcc 9f | no overflow, good. + | Overflow. This means that the %d1 was 0xffffff00, so it + | is now zero. We will set the mantissa to reflect this, and + | increment the exponent (checking for overflow there too) + move.w #0x8000,(%a0) + addq.w #1,-(%a0) + cmp.w #0x407f,(%a0)+ | exponent now overflown? + jeq fp_ns_large | yes, so make it infinity. +9: subq.l #4,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + | check nondefault rounding modes +2: subq.w #2,%d2 + jcs 9b | %d2 < 2, round to zero + jhi 3f | %d2 > 2, round to +infinity + tst.b (-3,%a0) | to -inf + jne fp_ns_doroundup | negative, round to infinity + jra 9b | positive, round to zero +3: tst.b (-3,%a0) | to +inf + jeq fp_ns_doroundup | positive, round to infinity + jra 9b | negative, round to zero + | Exponent underflow. Try to make a denormal, and set it to + | the smallest possible fraction if this fails. +fp_ns_small: + fp_set_sr FPSR_EXC_UNFL | set UNFL bit + move.w #0x3f81,(-2,%a0) | 2**-126 + neg.w %d2 | degree of underflow + cmp.w #32,%d2 | single or double shift? + jcc 2f + | a 32-bit shift. + move.l (%a0),%d0 + move.l %d0,%d1 + lsr.l %d2,%d0 + move.l %d0,(%a0)+ + | Check to see if we shifted off any significant bits. + neg.w %d2 + add.w #32,%d2 + lsl.l %d2,%d1 + jeq 1f + bset #0,%d0 | Sticky bit. + | Check the lower lword +1: tst.l (%a0) + jeq fp_ns_round + clr (%a0) + bset #0,%d0 | Sticky bit. + jra fp_ns_round + | Sorry, the number is just too small. +2: clr.l (%a0)+ + clr.l (%a0) + moveq #1,%d0 | Smallest possible fraction, + jra fp_ns_round | round as desired. + | Exponent overflow. Just call it infinity. +fp_ns_large: + tst.b (3,%a0) + jeq 1f + fp_set_sr FPSR_EXC_INEX2 +1: fp_set_sr FPSR_EXC_OVFL + move.w (FPD_RND,FPDATA),%d2 + jne 3f | %d2 = 0 round to nearest +1: move.w #0x7fff,(-2,%a0) + clr.l (%a0)+ + clr.l (%a0) +2: subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +3: subq.w #2,%d2 + jcs 5f | %d2 < 2, round to zero + jhi 4f | %d2 > 2, round to +infinity + tst.b (-3,%a0) | to -inf + jne 1b + jra 5f +4: tst.b (-3,%a0) | to +inf + jeq 1b +5: move.w #0x407e,(-2,%a0) + move.l #0xffffff00,(%a0)+ + clr.l (%a0) + jra 2b + | zero and denormalized +fp_ns_zero: + tst.l (%a0)+ + jne 1f + tst.l (%a0) + jne 1f + subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts | zero. nothing to do. + | These are not merely subnormal numbers, but true denormals, + | i.e. pathologically small (exponent is 2**-16383) numbers. + | It is clearly impossible for even a normal extended number + | with that exponent to fit into single precision, so just + | write these ones off as "too darn small". +1: fp_set_sr FPSR_EXC_UNFL | Set UNFL bit + clr.l (%a0) + clr.l -(%a0) + move.w #0x3f81,-(%a0) | i.e. 2**-126 + addq.l #6,%a0 + moveq #1,%d0 + jra fp_ns_round | round. + | Infinities or NaNs +fp_ns_huge: + subq.l #4,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + + | fp_normalize_single_fast: + | normalize an extended with single (23-bit) precision + | this is only used by fsgldiv/fsgdlmul, where the + | operand is not completly normalized. + | args: %a0 (struct fp_ext *) + +fp_normalize_single_fast: + printf PNORM,"nsf: %p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,") " + addq.l #2,%a0 + move.w (%a0)+,%d2 + cmp.w #0x7fff,%d2 + jeq fp_nsf_huge | NaN / infinitive. + move.l (%a0)+,%d0 | get high lword of mantissa +fp_nsf_round: + tst.l (%a0) | check the low lword + jeq 1f + | Set a sticky bit if it is non-zero. This should only + | affect the rounding in what would otherwise be equal- + | distance situations, which is what we want it to do. + bset #0,%d0 +1: clr.l (%a0) | zap it from memory. + | now, round off the low 8 bits of the hi lword. + tst.b %d0 | 8 low bits. + jne fp_nsf_checkround | Are they non-zero? + | nothing to do here + subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +fp_nsf_checkround: + fp_set_sr FPSR_EXC_INEX2 | INEX2 bit + clr.b -(%a0) | clear low byte of high lword + subq.l #3,%a0 + move.w (FPD_RND,FPDATA),%d2 | rounding mode + jne 2f | %d2 == 0, round to nearest + tst.b %d0 | test guard bit + jpl 9f | zero is closer + btst #8,%d0 | test lsb bit + | round to even behaviour, see above. + jne fp_nsf_doroundup | round to infinity + lsl.b #1,%d0 | check low bits + jeq 9f | round to zero +fp_nsf_doroundup: + | round (the mantissa, that is) towards infinity + add.l #0x100,(%a0) + jcc 9f | no overflow, good. + | Overflow. This means that the %d1 was 0xffffff00, so it + | is now zero. We will set the mantissa to reflect this, and + | increment the exponent (checking for overflow there too) + move.w #0x8000,(%a0) + addq.w #1,-(%a0) + cmp.w #0x407f,(%a0)+ | exponent now overflown? + jeq fp_nsf_large | yes, so make it infinity. +9: subq.l #4,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + | check nondefault rounding modes +2: subq.w #2,%d2 + jcs 9b | %d2 < 2, round to zero + jhi 3f | %d2 > 2, round to +infinity + tst.b (-3,%a0) | to -inf + jne fp_nsf_doroundup | negative, round to infinity + jra 9b | positive, round to zero +3: tst.b (-3,%a0) | to +inf + jeq fp_nsf_doroundup | positive, round to infinity + jra 9b | negative, round to zero + | Exponent overflow. Just call it infinity. +fp_nsf_large: + tst.b (3,%a0) + jeq 1f + fp_set_sr FPSR_EXC_INEX2 +1: fp_set_sr FPSR_EXC_OVFL + move.w (FPD_RND,FPDATA),%d2 + jne 3f | %d2 = 0 round to nearest +1: move.w #0x7fff,(-2,%a0) + clr.l (%a0)+ + clr.l (%a0) +2: subq.l #8,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts +3: subq.w #2,%d2 + jcs 5f | %d2 < 2, round to zero + jhi 4f | %d2 > 2, round to +infinity + tst.b (-3,%a0) | to -inf + jne 1b + jra 5f +4: tst.b (-3,%a0) | to +inf + jeq 1b +5: move.w #0x407e,(-2,%a0) + move.l #0xffffff00,(%a0)+ + clr.l (%a0) + jra 2b + | Infinities or NaNs +fp_nsf_huge: + subq.l #4,%a0 + printf PNORM,"%p(",1,%a0 + printx PNORM,%a0@ + printf PNORM,")\n" + rts + + | conv_ext2int (macro): + | Generates a subroutine that converts an extended value to an + | integer of a given size, again, with the appropriate type of + | rounding. + + | Macro arguments: + | s: size, as given in an assembly instruction. + | b: number of bits in that size. + + | Subroutine arguments: + | %a0: source (struct fp_ext *) + + | Returns the integer in %d0 (like it should) + +.macro conv_ext2int s,b + .set inf,(1<<(\b-1))-1 | i.e. MAXINT + printf PCONV,"e2i%d: %p(",2,#\b,%a0 + printx PCONV,%a0@ + printf PCONV,") " + addq.l #2,%a0 + move.w (%a0)+,%d2 | exponent + jeq fp_e2i_zero\b | zero / denorm (== 0, here) + cmp.w #0x7fff,%d2 + jeq fp_e2i_huge\b | Inf / NaN + sub.w #0x3ffe,%d2 + jcs fp_e2i_small\b + cmp.w #\b,%d2 + jhi fp_e2i_large\b + move.l (%a0),%d0 + move.l %d0,%d1 + lsl.l %d2,%d1 + jne fp_e2i_round\b + tst.l (4,%a0) + jne fp_e2i_round\b + neg.w %d2 + add.w #32,%d2 + lsr.l %d2,%d0 +9: tst.w (-4,%a0) + jne 1f + tst.\s %d0 + jmi fp_e2i_large\b + printf PCONV,"-> %p\n",1,%d0 + rts +1: neg.\s %d0 + jeq 1f + jpl fp_e2i_large\b +1: printf PCONV,"-> %p\n",1,%d0 + rts +fp_e2i_round\b: + fp_set_sr FPSR_EXC_INEX2 | INEX2 bit + neg.w %d2 + add.w #32,%d2 + .if \b>16 + jeq 5f + .endif + lsr.l %d2,%d0 + move.w (FPD_RND,FPDATA),%d2 | rounding mode + jne 2f | %d2 == 0, round to nearest + tst.l %d1 | test guard bit + jpl 9b | zero is closer + btst %d2,%d0 | test lsb bit (%d2 still 0) + jne fp_e2i_doroundup\b + lsl.l #1,%d1 | check low bits + jne fp_e2i_doroundup\b + tst.l (4,%a0) + jeq 9b +fp_e2i_doroundup\b: + addq.l #1,%d0 + jra 9b + | check nondefault rounding modes +2: subq.w #2,%d2 + jcs 9b | %d2 < 2, round to zero + jhi 3f | %d2 > 2, round to +infinity + tst.w (-4,%a0) | to -inf + jne fp_e2i_doroundup\b | negative, round to infinity + jra 9b | positive, round to zero +3: tst.w (-4,%a0) | to +inf + jeq fp_e2i_doroundup\b | positive, round to infinity + jra 9b | negative, round to zero + | we are only want -2**127 get correctly rounded here, + | since the guard bit is in the lower lword. + | everything else ends up anyway as overflow. + .if \b>16 +5: move.w (FPD_RND,FPDATA),%d2 | rounding mode + jne 2b | %d2 == 0, round to nearest + move.l (4,%a0),%d1 | test guard bit + jpl 9b | zero is closer + lsl.l #1,%d1 | check low bits + jne fp_e2i_doroundup\b + jra 9b + .endif +fp_e2i_zero\b: + clr.l %d0 + tst.l (%a0)+ + jne 1f + tst.l (%a0) + jeq 3f +1: subq.l #4,%a0 + fp_clr_sr FPSR_EXC_UNFL | fp_normalize_ext has set this bit +fp_e2i_small\b: + fp_set_sr FPSR_EXC_INEX2 + clr.l %d0 + move.w (FPD_RND,FPDATA),%d2 | rounding mode + subq.w #2,%d2 + jcs 3f | %d2 < 2, round to nearest/zero + jhi 2f | %d2 > 2, round to +infinity + tst.w (-4,%a0) | to -inf + jeq 3f + subq.\s #1,%d0 + jra 3f +2: tst.w (-4,%a0) | to +inf + jne 3f + addq.\s #1,%d0 +3: printf PCONV,"-> %p\n",1,%d0 + rts +fp_e2i_large\b: + fp_set_sr FPSR_EXC_OPERR + move.\s #inf,%d0 + tst.w (-4,%a0) + jeq 1f + addq.\s #1,%d0 +1: printf PCONV,"-> %p\n",1,%d0 + rts +fp_e2i_huge\b: + move.\s (%a0),%d0 + tst.l (%a0) + jne 1f + tst.l (%a0) + jeq fp_e2i_large\b + | fp_normalize_ext has set this bit already + | and made the number nonsignaling +1: fp_tst_sr FPSR_EXC_SNAN + jne 1f + fp_set_sr FPSR_EXC_OPERR +1: printf PCONV,"-> %p\n",1,%d0 + rts +.endm + +fp_conv_ext2long: + conv_ext2int l,32 + +fp_conv_ext2short: + conv_ext2int w,16 + +fp_conv_ext2byte: + conv_ext2int b,8 + +fp_conv_ext2double: + jsr fp_normalize_double + printf PCONV,"e2d: %p(",1,%a0 + printx PCONV,%a0@ + printf PCONV,"), " + move.l (%a0)+,%d2 + cmp.w #0x7fff,%d2 + jne 1f + move.w #0x7ff,%d2 + move.l (%a0)+,%d0 + jra 2f +1: sub.w #0x3fff-0x3ff,%d2 + move.l (%a0)+,%d0 + jmi 2f + clr.w %d2 +2: lsl.w #5,%d2 + lsl.l #7,%d2 + lsl.l #8,%d2 + move.l %d0,%d1 + lsl.l #1,%d0 + lsr.l #4,%d0 + lsr.l #8,%d0 + or.l %d2,%d0 + putuser.l %d0,(%a1)+,fp_err_ua2,%a1 + moveq #21,%d0 + lsl.l %d0,%d1 + move.l (%a0),%d0 + lsr.l #4,%d0 + lsr.l #7,%d0 + or.l %d1,%d0 + putuser.l %d0,(%a1),fp_err_ua2,%a1 +#ifdef FPU_EMU_DEBUG + getuser.l %a1@(-4),%d0,fp_err_ua2,%a1 + getuser.l %a1@(0),%d1,fp_err_ua2,%a1 + printf PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1 +#endif + rts + +fp_conv_ext2single: + jsr fp_normalize_single + printf PCONV,"e2s: %p(",1,%a0 + printx PCONV,%a0@ + printf PCONV,"), " + move.l (%a0)+,%d1 + cmp.w #0x7fff,%d1 + jne 1f + move.w #0xff,%d1 + move.l (%a0)+,%d0 + jra 2f +1: sub.w #0x3fff-0x7f,%d1 + move.l (%a0)+,%d0 + jmi 2f + clr.w %d1 +2: lsl.w #8,%d1 + lsl.l #7,%d1 + lsl.l #8,%d1 + bclr #31,%d0 + lsr.l #8,%d0 + or.l %d1,%d0 + printf PCONV,"%08x\n",1,%d0 + rts + + | special return addresses for instr that + | encode the rounding precision in the opcode + | (e.g. fsmove,fdmove) + +fp_finalrounding_single: + addq.l #8,%sp + jsr fp_normalize_ext + jsr fp_normalize_single + jra fp_finaltest + +fp_finalrounding_single_fast: + addq.l #8,%sp + jsr fp_normalize_ext + jsr fp_normalize_single_fast + jra fp_finaltest + +fp_finalrounding_double: + addq.l #8,%sp + jsr fp_normalize_ext + jsr fp_normalize_double + jra fp_finaltest + + | fp_finaltest: + | set the emulated status register based on the outcome of an + | emulated instruction. + +fp_finalrounding: + addq.l #8,%sp +| printf ,"f: %p\n",1,%a0 + jsr fp_normalize_ext + move.w (FPD_PREC,FPDATA),%d0 + subq.w #1,%d0 + jcs fp_finaltest + jne 1f + jsr fp_normalize_single + jra 2f +1: jsr fp_normalize_double +2:| printf ,"f: %p\n",1,%a0 +fp_finaltest: + | First, we do some of the obvious tests for the exception + | status byte and condition code bytes of fp_sr here, so that + | they do not have to be handled individually by every + | emulated instruction. + clr.l %d0 + addq.l #1,%a0 + tst.b (%a0)+ | sign + jeq 1f + bset #FPSR_CC_NEG-24,%d0 | N bit +1: cmp.w #0x7fff,(%a0)+ | exponent + jeq 2f + | test for zero + moveq #FPSR_CC_Z-24,%d1 + tst.l (%a0)+ + jne 9f + tst.l (%a0) + jne 9f + jra 8f + | infinitiv and NAN +2: moveq #FPSR_CC_NAN-24,%d1 + move.l (%a0)+,%d2 + lsl.l #1,%d2 | ignore high bit + jne 8f + tst.l (%a0) + jne 8f + moveq #FPSR_CC_INF-24,%d1 +8: bset %d1,%d0 +9: move.b %d0,(FPD_FPSR+0,FPDATA) | set condition test result + | move instructions enter here + | Here, we test things in the exception status byte, and set + | other things in the accrued exception byte accordingly. + | Emulated instructions can set various things in the former, + | as defined in fp_emu.h. +fp_final: + move.l (FPD_FPSR,FPDATA),%d0 +#if 0 + btst #FPSR_EXC_SNAN,%d0 | EXC_SNAN + jne 1f + btst #FPSR_EXC_OPERR,%d0 | EXC_OPERR + jeq 2f +1: bset #FPSR_AEXC_IOP,%d0 | set IOP bit +2: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL + jeq 1f + bset #FPSR_AEXC_OVFL,%d0 | set OVFL bit +1: btst #FPSR_EXC_UNFL,%d0 | EXC_UNFL + jeq 1f + btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2 + jeq 1f + bset #FPSR_AEXC_UNFL,%d0 | set UNFL bit +1: btst #FPSR_EXC_DZ,%d0 | EXC_INEX1 + jeq 1f + bset #FPSR_AEXC_DZ,%d0 | set DZ bit +1: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL + jne 1f + btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2 + jne 1f + btst #FPSR_EXC_INEX1,%d0 | EXC_INEX1 + jeq 2f +1: bset #FPSR_AEXC_INEX,%d0 | set INEX bit +2: move.l %d0,(FPD_FPSR,FPDATA) +#else + | same as above, greatly optimized, but untested (yet) + move.l %d0,%d2 + lsr.l #5,%d0 + move.l %d0,%d1 + lsr.l #4,%d1 + or.l %d0,%d1 + and.b #0x08,%d1 + move.l %d2,%d0 + lsr.l #6,%d0 + or.l %d1,%d0 + move.l %d2,%d1 + lsr.l #4,%d1 + or.b #0xdf,%d1 + and.b %d1,%d0 + move.l %d2,%d1 + lsr.l #7,%d1 + and.b #0x80,%d1 + or.b %d1,%d0 + and.b #0xf8,%d0 + or.b %d0,%d2 + move.l %d2,(FPD_FPSR,FPDATA) +#endif + move.b (FPD_FPSR+2,FPDATA),%d0 + and.b (FPD_FPCR+2,FPDATA),%d0 + jeq 1f + printf ,"send signal!!!\n" +1: jra fp_end diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/math-emu/multi_arith.h linux/arch/m68k/math-emu/multi_arith.h --- v2.2.17/arch/m68k/math-emu/multi_arith.h Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/math-emu/multi_arith.h Fri Oct 13 23:36:55 2000 @@ -0,0 +1,822 @@ +/* multi_arith.h: multi-precision integer arithmetic functions, needed + to do extended-precision floating point. + + (c) 1998 David Huggins-Daines. + + Somewhat based on arch/alpha/math-emu/ieee-math.c, which is (c) + David Mosberger-Tang. + + You may copy, modify, and redistribute this file under the terms of + the GNU General Public License, version 2, or any later version, at + your convenience. */ + +/* Note: + + These are not general multi-precision math routines. Rather, they + implement the subset of integer arithmetic that we need in order to + multiply, divide, and normalize 128-bit unsigned mantissae. */ + +#ifndef MULTI_ARITH_H +#define MULTI_ARITH_H + +#if 0 /* old code... */ + +/* Unsigned only, because we don't need signs to multiply and divide. */ +typedef unsigned int int128[4]; + +/* Word order */ +enum { + MSW128, + NMSW128, + NLSW128, + LSW128 +}; + +/* big-endian */ +#define LO_WORD(ll) (((unsigned int *) &ll)[1]) +#define HI_WORD(ll) (((unsigned int *) &ll)[0]) + +/* Convenience functions to stuff various integer values into int128s */ + +extern inline void zero128(int128 a) +{ + a[LSW128] = a[NLSW128] = a[NMSW128] = a[MSW128] = 0; +} + +/* Human-readable word order in the arguments */ +extern inline void set128(unsigned int i3, + unsigned int i2, + unsigned int i1, + unsigned int i0, + int128 a) +{ + a[LSW128] = i0; + a[NLSW128] = i1; + a[NMSW128] = i2; + a[MSW128] = i3; +} + +/* Convenience functions (for testing as well) */ +extern inline void int64_to_128(unsigned long long src, + int128 dest) +{ + dest[LSW128] = (unsigned int) src; + dest[NLSW128] = src >> 32; + dest[NMSW128] = dest[MSW128] = 0; +} + +extern inline void int128_to_64(const int128 src, + unsigned long long *dest) +{ + *dest = src[LSW128] | (long long) src[NLSW128] << 32; +} + +extern inline void put_i128(const int128 a) +{ + printk("%08x %08x %08x %08x\n", a[MSW128], a[NMSW128], + a[NLSW128], a[LSW128]); +} + +/* Internal shifters: + + Note that these are only good for 0 < count < 32. + */ + +extern inline void _lsl128(unsigned int count, int128 a) +{ + a[MSW128] = (a[MSW128] << count) | (a[NMSW128] >> (32 - count)); + a[NMSW128] = (a[NMSW128] << count) | (a[NLSW128] >> (32 - count)); + a[NLSW128] = (a[NLSW128] << count) | (a[LSW128] >> (32 - count)); + a[LSW128] <<= count; +} + +extern inline void _lsr128(unsigned int count, int128 a) +{ + a[LSW128] = (a[LSW128] >> count) | (a[NLSW128] << (32 - count)); + a[NLSW128] = (a[NLSW128] >> count) | (a[NMSW128] << (32 - count)); + a[NMSW128] = (a[NMSW128] >> count) | (a[MSW128] << (32 - count)); + a[MSW128] >>= count; +} + +/* Should be faster, one would hope */ + +extern inline void lslone128(int128 a) +{ + asm volatile ("lsl.l #1,%0\n" + "roxl.l #1,%1\n" + "roxl.l #1,%2\n" + "roxl.l #1,%3\n" + : + "=d" (a[LSW128]), + "=d"(a[NLSW128]), + "=d"(a[NMSW128]), + "=d"(a[MSW128]) + : + "0"(a[LSW128]), + "1"(a[NLSW128]), + "2"(a[NMSW128]), + "3"(a[MSW128])); +} + +extern inline void lsrone128(int128 a) +{ + asm volatile ("lsr.l #1,%0\n" + "roxr.l #1,%1\n" + "roxr.l #1,%2\n" + "roxr.l #1,%3\n" + : + "=d" (a[MSW128]), + "=d"(a[NMSW128]), + "=d"(a[NLSW128]), + "=d"(a[LSW128]) + : + "0"(a[MSW128]), + "1"(a[NMSW128]), + "2"(a[NLSW128]), + "3"(a[LSW128])); +} + +/* Generalized 128-bit shifters: + + These bit-shift to a multiple of 32, then move whole longwords. */ + +extern inline void lsl128(unsigned int count, int128 a) +{ + int wordcount, i; + + if (count % 32) + _lsl128(count % 32, a); + + if (0 == (wordcount = count / 32)) + return; + + /* argh, gak, endian-sensitive */ + for (i = 0; i < 4 - wordcount; i++) { + a[i] = a[i + wordcount]; + } + for (i = 3; i >= 4 - wordcount; --i) { + a[i] = 0; + } +} + +extern inline void lsr128(unsigned int count, int128 a) +{ + int wordcount, i; + + if (count % 32) + _lsr128(count % 32, a); + + if (0 == (wordcount = count / 32)) + return; + + for (i = 3; i >= wordcount; --i) { + a[i] = a[i - wordcount]; + } + for (i = 0; i < wordcount; i++) { + a[i] = 0; + } +} + +extern inline int orl128(int a, int128 b) +{ + b[LSW128] |= a; +} + +extern inline int btsthi128(const int128 a) +{ + return a[MSW128] & 0x80000000; +} + +/* test bits (numbered from 0 = LSB) up to and including "top" */ +extern inline int bftestlo128(int top, const int128 a) +{ + int r = 0; + + if (top > 31) + r |= a[LSW128]; + if (top > 63) + r |= a[NLSW128]; + if (top > 95) + r |= a[NMSW128]; + + r |= a[3 - (top / 32)] & ((1 << (top % 32 + 1)) - 1); + + return (r != 0); +} + +/* Aargh. We need these because GCC is broken */ +/* FIXME: do them in assembly, for goodness' sake! */ +extern inline void mask64(int pos, unsigned long long *mask) +{ + *mask = 0; + + if (pos < 32) { + LO_WORD(*mask) = (1 << pos) - 1; + return; + } + LO_WORD(*mask) = -1; + HI_WORD(*mask) = (1 << (pos - 32)) - 1; +} + +extern inline void bset64(int pos, unsigned long long *dest) +{ + /* This conditional will be optimized away. Thanks, GCC! */ + if (pos < 32) + asm volatile ("bset %1,%0":"=m" + (LO_WORD(*dest)):"id"(pos)); + else + asm volatile ("bset %1,%0":"=m" + (HI_WORD(*dest)):"id"(pos - 32)); +} + +extern inline int btst64(int pos, unsigned long long dest) +{ + if (pos < 32) + return (0 != (LO_WORD(dest) & (1 << pos))); + else + return (0 != (HI_WORD(dest) & (1 << (pos - 32)))); +} + +extern inline void lsl64(int count, unsigned long long *dest) +{ + if (count < 32) { + HI_WORD(*dest) = (HI_WORD(*dest) << count) + | (LO_WORD(*dest) >> count); + LO_WORD(*dest) <<= count; + return; + } + count -= 32; + HI_WORD(*dest) = LO_WORD(*dest) << count; + LO_WORD(*dest) = 0; +} + +extern inline void lsr64(int count, unsigned long long *dest) +{ + if (count < 32) { + LO_WORD(*dest) = (LO_WORD(*dest) >> count) + | (HI_WORD(*dest) << (32 - count)); + HI_WORD(*dest) >>= count; + return; + } + count -= 32; + LO_WORD(*dest) = HI_WORD(*dest) >> count; + HI_WORD(*dest) = 0; +} +#endif + +extern inline void fp_denormalize(struct fp_ext *reg, unsigned int cnt) +{ + reg->exp += cnt; + + switch (cnt) { + case 0 ... 8: + reg->lowmant = reg->mant.m32[1] << (8 - cnt); + reg->mant.m32[1] = (reg->mant.m32[1] >> cnt) | + (reg->mant.m32[0] << (32 - cnt)); + reg->mant.m32[0] = reg->mant.m32[0] >> cnt; + break; + case 9 ... 32: + reg->lowmant = reg->mant.m32[1] >> (cnt - 8); + if (reg->mant.m32[1] << (40 - cnt)) + reg->lowmant |= 1; + reg->mant.m32[1] = (reg->mant.m32[1] >> cnt) | + (reg->mant.m32[0] << (32 - cnt)); + reg->mant.m32[0] = reg->mant.m32[0] >> cnt; + break; + case 33 ... 39: + asm volatile ("bfextu %1{%2,#8},%0" : "=d" (reg->lowmant) + : "m" (reg->mant.m32[0]), "d" (64 - cnt)); + if (reg->mant.m32[1] << (40 - cnt)) + reg->lowmant |= 1; + reg->mant.m32[1] = reg->mant.m32[0] >> (cnt - 32); + reg->mant.m32[0] = 0; + break; + case 40 ... 71: + reg->lowmant = reg->mant.m32[0] >> (cnt - 40); + if ((reg->mant.m32[0] << (72 - cnt)) || reg->mant.m32[1]) + reg->lowmant |= 1; + reg->mant.m32[1] = reg->mant.m32[0] >> (cnt - 32); + reg->mant.m32[0] = 0; + break; + default: + reg->lowmant = reg->mant.m32[0] || reg->mant.m32[1]; + reg->mant.m32[0] = 0; + reg->mant.m32[1] = 0; + break; + } +} + +extern inline int fp_overnormalize(struct fp_ext *reg) +{ + int shift; + + if (reg->mant.m32[0]) { + asm ("bfffo %1{#0,#32},%0" : "=d" (shift) : "dm" (reg->mant.m32[0])); + reg->mant.m32[0] = (reg->mant.m32[0] << shift) | (reg->mant.m32[1] >> (32 - shift)); + reg->mant.m32[1] = (reg->mant.m32[1] << shift); + } else { + asm ("bfffo %1{#0,#32},%0" : "=d" (shift) : "dm" (reg->mant.m32[1])); + reg->mant.m32[0] = (reg->mant.m32[1] << shift); + reg->mant.m32[1] = 0; + shift += 32; + } + + return shift; +} + +extern inline int fp_addmant(struct fp_ext *dest, struct fp_ext *src) +{ + int carry; + + /* we assume here, gcc only insert move and a clr instr */ + asm volatile ("add.b %1,%0" : "=d,g" (dest->lowmant) + : "g,d" (src->lowmant), "0,0" (dest->lowmant)); + asm volatile ("addx.l %1,%0" : "=d" (dest->mant.m32[1]) + : "d" (src->mant.m32[1]), "0" (dest->mant.m32[1])); + asm volatile ("addx.l %1,%0" : "=d" (dest->mant.m32[0]) + : "d" (src->mant.m32[0]), "0" (dest->mant.m32[0])); + asm volatile ("addx.l %0,%0" : "=d" (carry) : "0" (0)); + + return carry; +} + +extern inline int fp_addcarry(struct fp_ext *reg) +{ + if (++reg->exp == 0x7fff) { + if (reg->mant.m64) + fp_set_sr(FPSR_EXC_INEX2); + reg->mant.m64 = 0; + fp_set_sr(FPSR_EXC_OVFL); + return 0; + } + reg->lowmant = (reg->mant.m32[1] << 7) | (reg->lowmant ? 1 : 0); + reg->mant.m32[1] = (reg->mant.m32[1] >> 1) | + (reg->mant.m32[0] << 31); + reg->mant.m32[0] = (reg->mant.m32[0] >> 1) | 0x80000000; + + return 1; +} + +extern inline void fp_submant(struct fp_ext *dest, struct fp_ext *src1, struct fp_ext *src2) +{ + /* we assume here, gcc only insert move and a clr instr */ + asm volatile ("sub.b %1,%0" : "=d,g" (dest->lowmant) + : "g,d" (src2->lowmant), "0,0" (src1->lowmant)); + asm volatile ("subx.l %1,%0" : "=d" (dest->mant.m32[1]) + : "d" (src2->mant.m32[1]), "0" (src1->mant.m32[1])); + asm volatile ("subx.l %1,%0" : "=d" (dest->mant.m32[0]) + : "d" (src2->mant.m32[0]), "0" (src1->mant.m32[0])); +} + +#define fp_mul64(desth, destl, src1, src2) ({ \ + asm ("mulu.l %2,%1:%0" : "=d" (destl), "=d" (desth) \ + : "g" (src1), "0" (src2)); \ +}) +#define fp_div64(quot, rem, srch, srcl, div) \ + asm ("divu.l %2,%1:%0" : "=d" (quot), "=d" (rem) \ + : "dm" (div), "1" (srch), "0" (srcl)) +#define fp_add64(dest1, dest2, src1, src2) ({ \ + asm ("add.l %1,%0" : "=d,dm" (dest2) \ + : "dm,d" (src2), "0,0" (dest2)); \ + asm ("addx.l %1,%0" : "=d" (dest1) \ + : "d" (src1), "0" (dest1)); \ +}) +#define fp_addx96(dest, src) ({ \ + /* we assume here, gcc only insert move and a clr instr */ \ + asm volatile ("add.l %1,%0" : "=d,g" (dest->m32[2]) \ + : "g,d" (temp.m32[1]), "0,0" (dest->m32[2])); \ + asm volatile ("addx.l %1,%0" : "=d" (dest->m32[1]) \ + : "d" (temp.m32[0]), "0" (dest->m32[1])); \ + asm volatile ("addx.l %1,%0" : "=d" (dest->m32[0]) \ + : "d" (0), "0" (dest->m32[0])); \ +}) +#define fp_sub64(dest, src) ({ \ + asm ("sub.l %1,%0" : "=d,dm" (dest.m32[1]) \ + : "dm,d" (src.m32[1]), "0,0" (dest.m32[1])); \ + asm ("subx.l %1,%0" : "=d" (dest.m32[0]) \ + : "d" (src.m32[0]), "0" (dest.m32[0])); \ +}) +#define fp_sub96c(dest, srch, srcm, srcl) ({ \ + char carry; \ + asm ("sub.l %1,%0" : "=d,dm" (dest.m32[2]) \ + : "dm,d" (srcl), "0,0" (dest.m32[2])); \ + asm ("subx.l %1,%0" : "=d" (dest.m32[1]) \ + : "d" (srcm), "0" (dest.m32[1])); \ + asm ("subx.l %2,%1; scs %0" : "=d" (carry), "=d" (dest.m32[0]) \ + : "d" (srch), "1" (dest.m32[0])); \ + carry; \ +}) + +extern inline void fp_multiplymant(union fp_mant128 *dest, struct fp_ext *src1, struct fp_ext *src2) +{ + union fp_mant64 temp; + + fp_mul64(dest->m32[0], dest->m32[1], src1->mant.m32[0], src2->mant.m32[0]); + fp_mul64(dest->m32[2], dest->m32[3], src1->mant.m32[1], src2->mant.m32[1]); + + fp_mul64(temp.m32[0], temp.m32[1], src1->mant.m32[0], src2->mant.m32[1]); + fp_addx96(dest, temp); + + fp_mul64(temp.m32[0], temp.m32[1], src1->mant.m32[1], src2->mant.m32[0]); + fp_addx96(dest, temp); +} + +extern inline void fp_dividemant(union fp_mant128 *dest, struct fp_ext *src, struct fp_ext *div) +{ + union fp_mant128 tmp; + union fp_mant64 tmp64; + unsigned long *mantp = dest->m32; + unsigned long fix, rem, first, dummy; + int i; + + /* the algorithm below requires dest to be smaller than div, + but both have the high bit set */ + if (src->mant.m64 >= div->mant.m64) { + fp_sub64(src->mant, div->mant); + *mantp = 1; + } else + *mantp = 0; + mantp++; + + /* basic idea behind this algorithm: we can't divide two 64bit numbers + (AB/CD) directly, but we can calculate AB/C0, but this means this + quotient is off by C0/CD, so we have to multiply the first result + to fix the result, after that we have nearly the correct result + and only a few corrections are needed. */ + + /* C0/CD can be precalculated, but it's an 64bit division again, but + we can make it a bit easier, by dividing first through C so we get + 10/1D and now only a single shift and the value fits into 32bit. */ + fix = 0x80000000; + dummy = div->mant.m32[1] / div->mant.m32[0] + 1; + dummy = (dummy >> 1) | fix; + fp_div64(fix, dummy, fix, 0, dummy); + fix--; + + for (i = 0; i < 3; i++, mantp++) { + if (src->mant.m32[0] == div->mant.m32[0]) { + fp_div64(first, rem, 0, src->mant.m32[1], div->mant.m32[0]); + + fp_mul64(*mantp, dummy, first, fix); + *mantp += fix; + } else { + fp_div64(first, rem, src->mant.m32[0], src->mant.m32[1], div->mant.m32[0]); + + fp_mul64(*mantp, dummy, first, fix); + } + + fp_mul64(tmp.m32[0], tmp.m32[1], div->mant.m32[0], first - *mantp); + fp_add64(tmp.m32[0], tmp.m32[1], 0, rem); + tmp.m32[2] = 0; + + fp_mul64(tmp64.m32[0], tmp64.m32[1], *mantp, div->mant.m32[1]); + fp_sub96c(tmp, 0, tmp64.m32[0], tmp64.m32[1]); + + src->mant.m32[0] = tmp.m32[1]; + src->mant.m32[1] = tmp.m32[2]; + + while (!fp_sub96c(tmp, 0, div->mant.m32[0], div->mant.m32[1])) { + src->mant.m32[0] = tmp.m32[1]; + src->mant.m32[1] = tmp.m32[2]; + *mantp += 1; + } + } +} + +#if 0 +extern inline unsigned int fp_fls128(union fp_mant128 *src) +{ + unsigned long data; + unsigned int res, off; + + if ((data = src->m32[0])) + off = 0; + else if ((data = src->m32[1])) + off = 32; + else if ((data = src->m32[2])) + off = 64; + else if ((data = src->m32[3])) + off = 96; + else + return 128; + + asm ("bfffo %1{#0,#32},%0" : "=d" (res) : "dm" (data)); + return res + off; +} + +extern inline void fp_shiftmant128(union fp_mant128 *src, int shift) +{ + unsigned long sticky; + + switch (shift) { + case 0: + return; + case 1: + asm volatile ("lsl.l #1,%0" + : "=d" (src->m32[3]) : "0" (src->m32[3])); + asm volatile ("roxl.l #1,%0" + : "=d" (src->m32[2]) : "0" (src->m32[2])); + asm volatile ("roxl.l #1,%0" + : "=d" (src->m32[1]) : "0" (src->m32[1])); + asm volatile ("roxl.l #1,%0" + : "=d" (src->m32[0]) : "0" (src->m32[0])); + return; + case 2 ... 31: + src->m32[0] = (src->m32[0] << shift) | (src->m32[1] >> (32 - shift)); + src->m32[1] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift)); + src->m32[2] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift)); + src->m32[3] = (src->m32[3] << shift); + return; + case 32 ... 63: + shift -= 32; + src->m32[0] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift)); + src->m32[1] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift)); + src->m32[2] = (src->m32[3] << shift); + src->m32[3] = 0; + return; + case 64 ... 95: + shift -= 64; + src->m32[0] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift)); + src->m32[1] = (src->m32[3] << shift); + src->m32[2] = src->m32[3] = 0; + return; + case 96 ... 127: + shift -= 96; + src->m32[0] = (src->m32[3] << shift); + src->m32[1] = src->m32[2] = src->m32[3] = 0; + return; + case -31 ... -1: + shift = -shift; + sticky = 0; + if (src->m32[3] << (32 - shift)) + sticky = 1; + src->m32[3] = (src->m32[3] >> shift) | (src->m32[2] << (32 - shift)) | sticky; + src->m32[2] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift)); + src->m32[1] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift)); + src->m32[0] = (src->m32[0] >> shift); + return; + case -63 ... -32: + shift = -shift - 32; + sticky = 0; + if ((src->m32[2] << (32 - shift)) || src->m32[3]) + sticky = 1; + src->m32[3] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift)) | sticky; + src->m32[2] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift)); + src->m32[1] = (src->m32[0] >> shift); + src->m32[0] = 0; + return; + case -95 ... -64: + shift = -shift - 64; + sticky = 0; + if ((src->m32[1] << (32 - shift)) || src->m32[2] || src->m32[3]) + sticky = 1; + src->m32[3] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift)) | sticky; + src->m32[2] = (src->m32[0] >> shift); + src->m32[1] = src->m32[0] = 0; + return; + case -127 ... -96: + shift = -shift - 96; + sticky = 0; + if ((src->m32[0] << (32 - shift)) || src->m32[1] || src->m32[2] || src->m32[3]) + sticky = 1; + src->m32[3] = (src->m32[0] >> shift) | sticky; + src->m32[2] = src->m32[1] = src->m32[0] = 0; + return; + } + + if (shift < 0 && (src->m32[0] || src->m32[1] || src->m32[2] || src->m32[3])) + src->m32[3] = 1; + else + src->m32[3] = 0; + src->m32[2] = 0; + src->m32[1] = 0; + src->m32[0] = 0; +} +#endif + +extern inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src, int shift) +{ + unsigned long tmp; + + switch (shift) { + case 0: + dest->mant.m64 = src->m64[0]; + dest->lowmant = src->m32[2] >> 24; + if (src->m32[3] || (src->m32[2] << 8)) + dest->lowmant |= 1; + break; + case 1: + asm volatile ("lsl.l #1,%0" + : "=d" (tmp) : "0" (src->m32[2])); + asm volatile ("roxl.l #1,%0" + : "=d" (dest->mant.m32[1]) : "0" (src->m32[1])); + asm volatile ("roxl.l #1,%0" + : "=d" (dest->mant.m32[0]) : "0" (src->m32[0])); + dest->lowmant = tmp >> 24; + if (src->m32[3] || (tmp << 8)) + dest->lowmant |= 1; + break; + case 31: + asm volatile ("lsr.l #1,%1; roxr.l #1,%0" + : "=d" (dest->mant.m32[0]) + : "d" (src->m32[0]), "0" (src->m32[1])); + asm volatile ("roxr.l #1,%0" + : "=d" (dest->mant.m32[1]) : "0" (src->m32[2])); + asm volatile ("roxr.l #1,%0" + : "=d" (tmp) : "0" (src->m32[3])); + dest->lowmant = tmp >> 24; + if (src->m32[3] << 7) + dest->lowmant |= 1; + break; + case 32: + dest->mant.m32[0] = src->m32[1]; + dest->mant.m32[1] = src->m32[2]; + dest->lowmant = src->m32[3] >> 24; + if (src->m32[3] << 8) + dest->lowmant |= 1; + break; + } +} + +#if 0 /* old code... */ +extern inline int fls(unsigned int a) +{ + int r; + + asm volatile ("bfffo %1{#0,#32},%0" + : "=d" (r) : "md" (a)); + return r; +} + +/* fls = "find last set" (cf. ffs(3)) */ +extern inline int fls128(const int128 a) +{ + if (a[MSW128]) + return fls(a[MSW128]); + if (a[NMSW128]) + return fls(a[NMSW128]) + 32; + /* XXX: it probably never gets beyond this point in actual + use, but that's indicative of a more general problem in the + algorithm (i.e. as per the actual 68881 implementation, we + really only need at most 67 bits of precision [plus + overflow]) so I'm not going to fix it. */ + if (a[NLSW128]) + return fls(a[NLSW128]) + 64; + if (a[LSW128]) + return fls(a[LSW128]) + 96; + else + return -1; +} + +extern inline int zerop128(const int128 a) +{ + return !(a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]); +} + +extern inline int nonzerop128(const int128 a) +{ + return (a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]); +} + +/* Addition and subtraction */ +/* Do these in "pure" assembly, because "extended" asm is unmanageable + here */ +extern inline void add128(const int128 a, int128 b) +{ + /* rotating carry flags */ + unsigned int carry[2]; + + carry[0] = a[LSW128] > (0xffffffff - b[LSW128]); + b[LSW128] += a[LSW128]; + + carry[1] = a[NLSW128] > (0xffffffff - b[NLSW128] - carry[0]); + b[NLSW128] = a[NLSW128] + b[NLSW128] + carry[0]; + + carry[0] = a[NMSW128] > (0xffffffff - b[NMSW128] - carry[1]); + b[NMSW128] = a[NMSW128] + b[NMSW128] + carry[1]; + + b[MSW128] = a[MSW128] + b[MSW128] + carry[0]; +} + +/* Note: assembler semantics: "b -= a" */ +extern inline void sub128(const int128 a, int128 b) +{ + /* rotating borrow flags */ + unsigned int borrow[2]; + + borrow[0] = b[LSW128] < a[LSW128]; + b[LSW128] -= a[LSW128]; + + borrow[1] = b[NLSW128] < a[NLSW128] + borrow[0]; + b[NLSW128] = b[NLSW128] - a[NLSW128] - borrow[0]; + + borrow[0] = b[NMSW128] < a[NMSW128] + borrow[1]; + b[NMSW128] = b[NMSW128] - a[NMSW128] - borrow[1]; + + b[MSW128] = b[MSW128] - a[MSW128] - borrow[0]; +} + +/* Poor man's 64-bit expanding multiply */ +extern inline void mul64(unsigned long long a, + unsigned long long b, + int128 c) +{ + unsigned long long acc; + int128 acc128; + + zero128(acc128); + zero128(c); + + /* first the low words */ + if (LO_WORD(a) && LO_WORD(b)) { + acc = (long long) LO_WORD(a) * LO_WORD(b); + c[NLSW128] = HI_WORD(acc); + c[LSW128] = LO_WORD(acc); + } + /* Next the high words */ + if (HI_WORD(a) && HI_WORD(b)) { + acc = (long long) HI_WORD(a) * HI_WORD(b); + c[MSW128] = HI_WORD(acc); + c[NMSW128] = LO_WORD(acc); + } + /* The middle words */ + if (LO_WORD(a) && HI_WORD(b)) { + acc = (long long) LO_WORD(a) * HI_WORD(b); + acc128[NMSW128] = HI_WORD(acc); + acc128[NLSW128] = LO_WORD(acc); + add128(acc128, c); + } + /* The first and last words */ + if (HI_WORD(a) && LO_WORD(b)) { + acc = (long long) HI_WORD(a) * LO_WORD(b); + acc128[NMSW128] = HI_WORD(acc); + acc128[NLSW128] = LO_WORD(acc); + add128(acc128, c); + } +} + +/* Note: unsigned */ +extern inline int cmp128(int128 a, int128 b) +{ + if (a[MSW128] < b[MSW128]) + return -1; + if (a[MSW128] > b[MSW128]) + return 1; + if (a[NMSW128] < b[NMSW128]) + return -1; + if (a[NMSW128] > b[NMSW128]) + return 1; + if (a[NLSW128] < b[NLSW128]) + return -1; + if (a[NLSW128] > b[NLSW128]) + return 1; + + return (signed) a[LSW128] - b[LSW128]; +} + +inline void div128(int128 a, int128 b, int128 c) +{ + int128 mask; + + /* Algorithm: + + Shift the divisor until it's at least as big as the + dividend, keeping track of the position to which we've + shifted it, i.e. the power of 2 which we've multiplied it + by. + + Then, for this power of 2 (the mask), and every one smaller + than it, subtract the mask from the dividend and add it to + the quotient until the dividend is smaller than the raised + divisor. At this point, divide the dividend and the mask + by 2 (i.e. shift one place to the right). Lather, rinse, + and repeat, until there are no more powers of 2 left. */ + + /* FIXME: needless to say, there's room for improvement here too. */ + + /* Shift up */ + /* XXX: since it just has to be "at least as big", we can + probably eliminate this horribly wasteful loop. I will + have to prove this first, though */ + set128(0, 0, 0, 1, mask); + while (cmp128(b, a) < 0 && !btsthi128(b)) { + lslone128(b); + lslone128(mask); + } + + /* Shift down */ + zero128(c); + do { + if (cmp128(a, b) >= 0) { + sub128(b, a); + add128(mask, c); + } + lsrone128(mask); + lsrone128(b); + } while (nonzerop128(mask)); + + /* The remainder is in a... */ +} +#endif + +#endif /* MULTI_ARITH_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c --- v2.2.17/arch/m68k/mm/fault.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mm/fault.c Fri Oct 13 23:30:47 2000 @@ -19,6 +19,48 @@ extern void die_if_kernel(char *, struct pt_regs *, long); extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */ +int send_fault_sig(struct pt_regs *regs) +{ + if (user_mode(regs)) { + force_sig_info(current->buserr_info.si_signo, + ¤t->buserr_info, current); + } else { + unsigned long fixup; + + /* Are we prepared to handle this kernel fault? */ + if ((fixup = search_exception_table(regs->pc))) { + struct pt_regs *tregs; + /* Create a new four word stack frame, discarding the old + one. */ + regs->stkadj = frame_extra_sizes[regs->format]; + tregs = (struct pt_regs *)((ulong)regs + regs->stkadj); + tregs->vector = regs->vector; + tregs->format = 0; + tregs->pc = fixup; + tregs->sr = regs->sr; + return -1; + } + + if (current->buserr_info.si_signo == SIGBUS) + force_sig_info(current->buserr_info.si_signo, + ¤t->buserr_info, current); + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long)current->buserr_info.si_addr < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel access"); + printk(" at virtual address %p\n", current->buserr_info.si_addr); + die_if_kernel("Oops", regs, 0 /*error_code*/); + do_exit(SIGKILL); + } + + return 1; +} + /* * This routine handles page faults. It determines the problem, and * then passes it off to one of the appropriate routines. @@ -30,12 +72,11 @@ * If this routine detects a bad access, it returns 1, otherwise it * returns 0. */ -asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, - unsigned long error_code) +int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) { struct mm_struct *mm = current->mm; struct vm_area_struct * vma; - unsigned long fixup; int write; #ifdef DEBUG @@ -56,23 +97,23 @@ vma = find_vma(mm, address); if (!vma) - goto bad_area; + goto map_err; if (vma->vm_flags & VM_IO) - goto bad_area; + goto acc_err; if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; + goto map_err; if (user_mode(regs)) { /* Accessing the stack below usp is always a bug. The "+ 256" is there due to some instructions doing pre-decrement on the stack and that doesn't show up until later. */ if (address + 256 < rdusp()) - goto bad_area; + goto map_err; } if (expand_stack(vma, address)) - goto bad_area; + goto map_err; /* * Ok, we have a good vm_area for this memory access, so @@ -85,14 +126,14 @@ /* fall through */ case 2: /* write, not present */ if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; + goto acc_err; write++; break; case 1: /* read, present */ - goto bad_area; + goto acc_err; case 0: /* read, not present */ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) - goto bad_area; + goto acc_err; } /* @@ -101,77 +142,42 @@ * the fault. */ if (!handle_mm_fault(current, vma, address, write)) - goto do_sigbus; + goto bus_err; /* There seems to be a missing invalidate somewhere in do_no_page. * Until I found it, this one cures the problem and makes * 1.2 run on the 68040 (Martin Apel). */ + if (CPU_IS_040_OR_060) flush_tlb_page(vma, address); - up(&mm->mmap_sem); - return 0; -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: up(&mm->mmap_sem); - - /* User mode accesses just cause a SIGSEGV */ - if (user_mode(regs)) { - siginfo_t info; - info.si_signo = SIGSEGV; - info.si_code = SEGV_MAPERR; - info.si_addr = (void *)address; - force_sig_info(SIGSEGV, &info, current); - return 1; - } + return 0; no_context: - /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(regs->pc)) != 0) { - struct pt_regs *tregs; - /* Create a new four word stack frame, discarding the old - one. */ - regs->stkadj = frame_extra_sizes[regs->format]; - tregs = (struct pt_regs *)((ulong)regs + regs->stkadj); - tregs->vector = regs->vector; - tregs->format = 0; - tregs->pc = fixup; - tregs->sr = regs->sr; - return -1; - } + current->buserr_info.si_signo = SIGBUS; + current->buserr_info.si_addr = (void *)address; + return send_fault_sig(regs); + +bus_err: + current->buserr_info.si_signo = SIGBUS; + current->buserr_info.si_code = BUS_ADRERR; + current->buserr_info.si_addr = (void *)address; + goto send_sig; + +map_err: + current->buserr_info.si_signo = SIGSEGV; + current->buserr_info.si_code = SEGV_MAPERR; + current->buserr_info.si_addr = (void *)address; + goto send_sig; + +acc_err: + current->buserr_info.si_signo = SIGSEGV; + current->buserr_info.si_code = SEGV_ACCERR; + current->buserr_info.si_addr = (void *)address; -/* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - if ((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - } else - printk(KERN_ALERT "Unable to handle kernel access"); - printk(" at virtual address %08lx\n",address); - die_if_kernel("Oops", regs, error_code); - do_exit(SIGKILL); - -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -do_sigbus: +send_sig: up(&mm->mmap_sem); - - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - force_sig(SIGBUS, current); - - /* Kernel mode? Handle exceptions or die */ - if (!user_mode(regs)) - goto no_context; - - return 1; + return send_fault_sig(regs); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.2.17/arch/m68k/mm/init.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mm/init.c Fri Oct 13 23:30:47 2000 @@ -139,6 +139,7 @@ } static pmd_t *last_pgtable __initdata = NULL; +static pmd_t *zero_pgtable __initdata = NULL; __initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp)) { @@ -236,7 +237,8 @@ #ifdef DEBUG printk ("[zero map]"); #endif - pte_dir = (pte_t *)kernel_ptr_table(memavailp); + zero_pgtable = kernel_ptr_table(memavailp); + pte_dir = (pte_t *)zero_pgtable; pmd_dir->pmd[0] = virt_to_phys(pte_dir) | _PAGE_TABLE | _PAGE_ACCESSED; pte_val(*pte_dir++) = 0; @@ -380,7 +382,7 @@ "pmove %0,%%crp\n\t" ".chip 68k" : /* no outputs */ - : "m" (task[0]->tss.crp[0])); + : "m" (task[0]->tss.crp[1]|_PAGE_TABLE)); #ifdef DEBUG printk ("set crp\n"); #endif @@ -450,6 +452,9 @@ if (pgd_present(kernel_pg_dir[i])) init_pointer_table(pgd_page(kernel_pg_dir[i])); } + /* insert also pointer table that we used to unmap the zero page */ + if (zero_pgtable) + init_pointer_table((unsigned long)zero_pgtable); printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c --- v2.2.17/arch/m68k/mm/kmap.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mm/kmap.c Fri Oct 13 23:30:47 2000 @@ -25,6 +25,7 @@ #undef DEBUG #define PTRTREESIZE (256*1024) +#define ROOTTREESIZE (32*1024*1024) /* * For 040/060 we can use the virtual memory area like other architectures, @@ -189,7 +190,20 @@ printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr); #endif pgd_dir = pgd_offset_k(virtaddr); - pmd_dir = pmd_alloc_kernel(pgd_dir, virtaddr); + if (CPU_IS_020_OR_030) { + if (!(virtaddr & (ROOTTREESIZE-1)) && + size >= ROOTTREESIZE) { + pgd_val(*pgd_dir) = physaddr; + size -= ROOTTREESIZE; + virtaddr += ROOTTREESIZE; + physaddr += ROOTTREESIZE; + continue; + } + } + if (!pgd_present(*pgd_dir)) + pmd_dir = pmd_alloc_kernel(pgd_dir, virtaddr); + else + pmd_dir = pmd_offset(pgd_dir, virtaddr); if (!pmd_dir) { printk("ioremap: no mem for pmd_dir\n"); return NULL; @@ -201,7 +215,10 @@ virtaddr += PTRTREESIZE; size -= PTRTREESIZE; } else { - pte_dir = pte_alloc_kernel(pmd_dir, virtaddr); + if (!pmd_present(*pmd_dir)) + pte_dir = pte_alloc_kernel(pmd_dir, virtaddr); + else + pte_dir = pte_offset(pmd_dir, virtaddr); if (!pte_dir) { printk("ioremap: no mem for pte_dir\n"); return NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c --- v2.2.17/arch/m68k/mvme147/config.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mvme147/config.c Fri Oct 13 23:30:47 2000 @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -62,6 +63,14 @@ void (*tick_handler)(int, void *, struct pt_regs *); + +int mvme147_parse_bootinfo(const struct bi_record *bi) +{ + if (bi->tag == BI_VME_TYPE || bi->tag == BI_VME_BRDINFO) + return 0; + else + return 1; +} int mvme147_kbdrate (struct kbd_repeat *k) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mvme16x/Makefile linux/arch/m68k/mvme16x/Makefile --- v2.2.17/arch/m68k/mvme16x/Makefile Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mvme16x/Makefile Fri Oct 13 23:30:47 2000 @@ -9,6 +9,6 @@ O_TARGET := mvme16x.o O_OBJS := config.o 16xints.o rtc.o -#OX_OBJS = ksyms.o +OX_OBJS := mvme16x_ksyms.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c --- v2.2.17/arch/m68k/mvme16x/config.c Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/mvme16x/config.c Fri Oct 13 23:30:47 2000 @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ int atari_SCC_reset_done = 1; /* So SCC doesn't get reset */ u_long atari_mch_cookie = 0; +extern unsigned long mvme_bdid; static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE; @@ -72,6 +74,14 @@ unsigned short mvme16x_config; +int mvme16x_parse_bootinfo(const struct bi_record *bi) +{ + if (bi->tag == BI_VME_TYPE || bi->tag == BI_VME_BRDINFO) + return 0; + else + return 1; +} + int mvme16x_kbdrate (struct kbd_repeat *k) { return 0; @@ -92,7 +102,7 @@ static void mvme16x_get_model(char *model) { - p_bdid p = (p_bdid)mvme_bdid_ptr; + p_bdid p = (p_bdid)&mvme_bdid; char suf[4]; suf[1] = p->brdsuffix[0]; @@ -106,7 +116,7 @@ static int mvme16x_get_hardware_list(char *buffer) { - p_bdid p = (p_bdid)mvme_bdid_ptr; + p_bdid p = (p_bdid)&mvme_bdid; int len = 0; if (p->brdno == 0x0162 || p->brdno == 0x0172) @@ -134,7 +144,7 @@ __initfunc(void config_mvme16x(void)) { - p_bdid p = (p_bdid)mvme_bdid_ptr; + p_bdid p = (p_bdid)&mvme_bdid; char id[40]; mach_sched_init = mvme16x_sched_init; @@ -200,7 +210,7 @@ static void mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp) { - p_bdid p = (p_bdid)mvme_bdid_ptr; + p_bdid p = (p_bdid)&mvme_bdid; unsigned long *new = (unsigned long *)vectors; unsigned long *old = (unsigned long *)0xffe00000; volatile unsigned char uc, *ucp; @@ -233,7 +243,7 @@ void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) { - p_bdid p = (p_bdid)mvme_bdid_ptr; + p_bdid p = (p_bdid)&mvme_bdid; int irq; tick_handler = timer_routine; @@ -299,19 +309,22 @@ extern void mvme167_serial_console_setup(int cflag); extern void serial167_write(struct console *co, const char *str, unsigned cnt); +extern int serial167_wait_key(struct console *co); extern void vme_scc_write(struct console *co, const char *str, unsigned cnt); +extern int vme_scc_wait_key(struct console *co); void mvme16x_init_console_port (struct console *co, int cflag) { - p_bdid p = (p_bdid)mvme_bdid_ptr; + p_bdid p = (p_bdid)&mvme_bdid; switch (p->brdno) { #ifdef CONFIG_MVME162_SCC case 0x0162: case 0x0172: - co->write = vme_scc_write; + co->write = vme_scc_write; + co->wait_key = vme_scc_wait_key; return; #endif #ifdef CONFIG_SERIAL167 @@ -319,7 +332,8 @@ case 0x0167: case 0x0176: case 0x0177: - co->write = serial167_write; + co->write = serial167_write; + co->wait_key = serial167_wait_key; mvme167_serial_console_setup (cflag); return; #endif @@ -371,4 +385,27 @@ } restore_flags(flags); } + + +int vme_scc_wait_key (struct console *co) +{ + volatile unsigned char *p = (volatile char *)MVME_SCC_A_ADDR; + unsigned long flags; + int c; + + /* wait for rx buf filled */ + while ((*p & 0x01) == 0) + ; + + save_flags(flags); + cli(); + + *p = 8; + scc_delay(); + c = *p; + + restore_flags(flags); + return c; +} + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mvme16x/mvme16x_ksyms.c linux/arch/m68k/mvme16x/mvme16x_ksyms.c --- v2.2.17/arch/m68k/mvme16x/mvme16x_ksyms.c Thu Jan 1 01:00:00 1970 +++ linux/arch/m68k/mvme16x/mvme16x_ksyms.c Fri Oct 13 23:36:55 2000 @@ -0,0 +1,6 @@ +#include +#include +#include +#include + +EXPORT_SYMBOL(mvme16x_config); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds --- v2.2.17/arch/m68k/vmlinux.lds Fri Apr 21 12:45:46 2000 +++ linux/arch/m68k/vmlinux.lds Tue Sep 5 22:20:06 2000 @@ -35,6 +35,7 @@ _edata = .; /* End of data section */ + . = ALIGN(16); .data.cacheline_aligned : { *(.data.cacheline_aligned) } @@ -42,6 +43,13 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(8192); __init_end = .; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile --- v2.2.17/arch/ppc/boot/Makefile Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/boot/Makefile Wed Nov 8 23:00:33 2000 @@ -10,7 +10,7 @@ # modified by Cort (cort@cs.nmt.edu) # .c.s: - $(CC) $(CFLAGS) -S -o $*.s $< + $(CC) $(CFLAGS) -I$(HPATH) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/boot/vreset.c linux/arch/ppc/boot/vreset.c --- v2.2.17/arch/ppc/boot/vreset.c Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/boot/vreset.c Wed Nov 8 23:00:33 2000 @@ -24,7 +24,7 @@ extern char *vidmem; extern int lines, cols; /* estimate for delay */ -unsigned long loops_per_sec = 50000000;; +unsigned long loops_per_jiffy = 50000000/HZ; /* * VGA Register */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile --- v2.2.17/arch/ppc/coffboot/Makefile Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/coffboot/Makefile Wed Nov 8 23:00:33 2000 @@ -7,11 +7,11 @@ CC = $(CROSS_COMPILE)gcc LD = $(CROSS_COMPILE)ld -CFLAGS = $(CPPFLAGS) -O -fno-builtin +CFLAGS = $(CPPFLAGS) -O -fno-builtin -I$(HPATH) OBJCOPY = $(CROSS_COMPILE)objcopy 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 +CHRP_LD_ARGS = -Ttext 0x01000000 GZ = gzip -9 COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o @@ -24,18 +24,13 @@ 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 TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE) endif -ifeq ($(CONFIG_PMAC),y) +ifeq ($(CONFIG_POWERMAC),y) hack-coff: hack-coff.c $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/coffboot/chrpmain.c linux/arch/ppc/coffboot/chrpmain.c --- v2.2.17/arch/ppc/coffboot/chrpmain.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/coffboot/chrpmain.c Wed Nov 8 23:00:33 2000 @@ -18,13 +18,18 @@ #define get_16be(x) (*(unsigned short *)(x)) #define get_32be(x) (*(unsigned *)(x)) -#define RAM_START 0x00000000 -#define RAM_END (8<<20) +#define RAM_END (16 << 20) #define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) char *avail_ram; -char *end_avail; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; extern char _end[]; extern char image_data[]; @@ -56,23 +61,28 @@ im = image_data; len = image_len; /* claim 3MB starting at PROG_START */ - claim(PROG_START, 3 << 20, 0); + claim(PROG_START, PROG_SIZE, 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); + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%x\n", avail_ram); printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, 3 << 20, im, &len); + gunzip(dst, PROG_SIZE, im, &len); printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); } else { memmove(dst, im, len); } flush_cache(dst, len); +#if 0 stop_imac_ethernet(); stop_imac_usb(); +#endif sa = (unsigned long)PROG_START; printf("start address = 0x%x\n", sa); @@ -84,6 +94,7 @@ pause(); } +#if 0 #define eieio() asm volatile("eieio"); void stop_imac_ethernet(void) @@ -134,14 +145,35 @@ *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ eieio(); } +#endif + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; void *zalloc(void *x, unsigned items, unsigned size) { - void *p = avail_ram; + void *p; + struct memchunk **mpp, *mp; size *= items; size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; if (avail_ram > end_avail) { printf("oops... out of memory\n"); pause(); @@ -151,6 +183,17 @@ void zfree(void *x, void *addr, unsigned nb) { + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; } #define HEAD_CRC 2 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/config.in linux/arch/ppc/config.in --- v2.2.17/arch/ppc/config.in Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/config.in Wed Nov 8 23:00:33 2000 @@ -26,12 +26,12 @@ bool 'Altivec (G4) support' CONFIG_ALTIVEC fi -if [ "$CONFIG_ALL_PPC" != "y" ];then +if [ "$CONFIG_ALL_PPC" != "y" ]; then define_bool CONFIG_MACH_SPECIFIC y fi -if [ "$CONFIG_PPC64" != "y" ];then - define_bool CONFIG_6xx y +if [ "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" ]; then + define_bool CONFIG_POWERMAC y fi endmenu @@ -82,16 +82,7 @@ bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB - bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK -bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD -bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY -tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL -if [ "$CONFIG_MAC_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE -fi -tristate 'Support for /dev/rtc' CONFIG_PPC_RTC -bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT @@ -182,7 +173,27 @@ source drivers/char/Config.in source drivers/usb/Config.in -source fs/Config.in + +mainmenu_option next_comment +comment 'Mac device drivers' +if [ "$CONFIG_INPUT_KEYBDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "y" ]; then + bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID +fi +if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then + define_bool CONFIG_MAC_HID y + bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES + bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN +else + bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD + bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE +fi +tristate 'Support for /dev/rtc' CONFIG_PPC_RTC +bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY +tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL +if [ "$CONFIG_MAC_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE +fi +endmenu mainmenu_option next_comment comment 'Sound' @@ -193,6 +204,8 @@ fi endmenu + +source fs/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.2.17/arch/ppc/kernel/Makefile Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/Makefile Wed Nov 8 23:00:33 2000 @@ -36,20 +36,40 @@ ifeq ($(CONFIG_MBX),y) O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o -else +endif ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o prom.o openpic.o -else -ifneq ($(CONFIG_MBX),y) -O_OBJS += prep_time.o pmac_time.o chrp_time.o \ - pmac_setup.o pmac_support.o \ - prep_pci.o pmac_pci.o chrp_pci.o \ - residual.o prom.o openpic.o feature.o \ - prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o \ - gemini_pci.o gemini_prom.o gemini_setup.o -OX_OBJS += chrp_setup.o prep_setup.o endif + +PMAC_OBJS = pmac_time.o pmac_setup.o pmac_support.o pmac_pci.o pmac_pic.o \ + feature.o openpic.o open_pic.o prom.o +CHRP_OBJS = $(PMAC_OBJS) chrp_time.o chrp_pci.o i8259.o indirect_pci.o +CHRPX_OBJS = chrp_setup.o +PREP_OBJS = prep_time.o prep_pci.o residual.o prep_nvram.o i8259.o \ + indirect_pci.o openpic.o open_pic.o prom.o +PREPX_OBJS = prep_setup.o + +ifeq ($(CONFIG_ALL_PPC),y) +O_OBJS += $(sort $(PMAC_OBJS) $(PREP_OBJS) $(CHRP_OBJS)) +OX_OBJS += $(PMACX_OBJS) $(PREPX_OBJS) $(CHRPX_OBJS) +endif +ifeq ($(CONFIG_PMAC),y) +O_OBJS += $(PMAC_OBJS) +OX_OBJS += $(PMACX_OBJS) endif +ifeq ($(CONFIG_PREP),y) +O_OBJS += $(PREP_OBJS) +OX_OBJS += $(PREPX_OBJS) +endif +ifeq ($(CONFIG_CHRP),y) +O_OBJS += $(CHRP_OBJS) +OX_OBJS += $(CHRPX_OBJS) +endif + +GEMINI_OBJS = $(PREP_OBJS) gemini_pci.o gemini_prom.o gemini_setup.o +ifeq ($(CONFIG_GEMINI),y) +O_OBJS += $(GEMINI_OBJS) +OX_OBJS += $(PREPX_OBJS) endif ifdef CONFIG_SMP @@ -75,7 +95,7 @@ $(HOSTCC) -o find_name find_name.c checks: checks.c - $(HOSTCC) ${CFLAGS} -D__KERNEL__ -o checks checks.c + $(HOSTCC) ${CFLAGS} -D__KERNEL__ -I../../../include -o checks checks.c ./checks include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.2.17/arch/ppc/kernel/apus_setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/apus_setup.c Wed Nov 8 23:00:34 2000 @@ -624,7 +624,7 @@ ppc_md.kbd_unexpected_up = NULL; ppc_md.kbd_leds = NULL; ppc_md.kbd_init_hw = NULL; - ppc_md.kbd_sysrq_xlate = NULL; + ppc_md.sysrq_xlate = NULL; #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = apus_ide_insw; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.2.17/arch/ppc/kernel/chrp_pci.c Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/kernel/chrp_pci.c Wed Nov 8 23:00:34 2000 @@ -19,6 +19,7 @@ #include #include "pci.h" +#include "open_pic.h" /* LongTrail */ #define pci_config_addr(bus, dev, offset) \ @@ -286,7 +287,7 @@ for( dev=pci_devices ; dev; dev=dev->next ) { if ( dev->irq ) - dev->irq = openpic_to_irq( dev->irq ); + dev->irq = dev->irq + open_pic.irq_offset; /* these need to be absolute addrs for OF and Matrox FB -- Cort */ if ( dev->vendor == PCI_VENDOR_ID_MATROX ) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.2.17/arch/ppc/kernel/chrp_setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/chrp_setup.c Wed Nov 8 23:00:34 2000 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include #include "local_irq.h" @@ -67,7 +69,7 @@ int chrp_set_rtc_time(unsigned long nowtime); unsigned long rtas_event_scan_rate = 0, rtas_event_scan_ct = 0; void chrp_calibrate_decr(void); -void chrp_time_init(void); +long chrp_time_init(void); void chrp_setup_pci_ptrs(void); @@ -94,7 +96,7 @@ extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern int probingmem; -extern unsigned long loops_per_sec; +extern unsigned long loops_per_jiffy; unsigned long empty_zero_page[1024]; @@ -240,7 +242,7 @@ struct device_node *device; /* init to some ~sane value until calibrate_delay() runs */ - loops_per_sec = 50000000; + loops_per_jiffy = 50000000/HZ; #ifdef CONFIG_BLK_DEV_INITRD /* this is fine for chrp */ @@ -357,81 +359,6 @@ } } -void -chrp_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) -{ - int irq; - unsigned long bits = 0; - int openpic_eoi_done = 0; - -#ifdef __SMP__ - { - unsigned int loops = 1000000; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } -#endif /* __SMP__ */ - - irq = openpic_irq(smp_processor_id()); - if (irq == IRQ_8259_CASCADE) - { - /* - * This magic address generates a PCI IACK cycle. - * - * This should go in the above mask/ack code soon. -- Cort - */ - if ( chrp_int_ack_special ) - irq = *chrp_int_ack_special; - else - irq = i8259_irq(0); - /* - * Acknowledge as soon as possible to allow i8259 - * interrupt nesting */ - openpic_eoi(smp_processor_id()); - openpic_eoi_done = 1; - } - if (irq == OPENPIC_VEC_SPURIOUS) - { - /* - * Spurious interrupts should never be - * acknowledged - */ - ppc_spurious_interrupts++; - openpic_eoi_done = 1; - goto out; - } - bits = 1UL << irq; - - if (irq < 0) - { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - } - else - { - ppc_irq_dispatch_handler( regs, irq ); - } -out: - if (!openpic_eoi_done) - openpic_eoi(smp_processor_id()); -} - __initfunc(void chrp_init_IRQ(void)) { @@ -446,7 +373,7 @@ (*(unsigned long *)get_property(np, "8259-interrupt-acknowledge", NULL)); } - open_pic.irq_offset = 16; + open_pic.irq_offset = NUM_8259_INTERRUPTS; for ( i = 16 ; i < NR_IRQS ; i++ ) irq_desc[i].ctl = &open_pic; openpic_init(1); @@ -454,7 +381,7 @@ irq_desc[i].ctl = &i8259_pic; i8259_init(); #ifdef CONFIG_XMON - request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI), + request_irq(HYDRA_INT_ADB_NMI+open_pic.irq_offset, xmon_irq, 0, "NMI", 0); #endif /* CONFIG_XMON */ #ifdef __SMP__ @@ -487,8 +414,8 @@ 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; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif } else @@ -500,8 +427,8 @@ ppc_md.kbd_leds = mackbd_leds; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x69; + ppc_md.sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; #endif } #else @@ -512,8 +439,8 @@ 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; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif #endif #endif @@ -643,7 +570,7 @@ ppc_md.get_cpuinfo = chrp_get_cpuinfo; ppc_md.irq_cannonicalize = chrp_irq_cannonicalize; ppc_md.init_IRQ = chrp_init_IRQ; - ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.do_IRQ = open_pic_do_IRQ; ppc_md.init = chrp_init2; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c --- v2.2.17/arch/ppc/kernel/chrp_time.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/chrp_time.c Wed Nov 8 23:00:34 2000 @@ -31,18 +31,19 @@ static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; -__initfunc(void chrp_time_init(void)) +__initfunc(long chrp_time_init(void)) { struct device_node *rtcs; int base; rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); if (rtcs == NULL || rtcs->addrs == NULL) - return; + return 0; base = rtcs->addrs[0].address; nvram_as1 = 0; nvram_as0 = base; nvram_data = base + 1; + return 0; } int chrp_cmos_clock_read(int addr) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c --- v2.2.17/arch/ppc/kernel/feature.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/feature.c Wed Nov 8 23:00:34 2000 @@ -2,16 +2,13 @@ * arch/ppc/kernel/feature.c * * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * Ben. Herrenschmidt (bh40@calva.net) * * 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. * - * BenH: Changed implementation to work on multiple registers - * polarity is also taken into account. Removed delay (now - * responsibility of the caller). Added spinlocks. - * */ #include #include @@ -22,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -29,18 +28,30 @@ #undef DEBUG_FEATURE #define MAX_FEATURE_CONTROLLERS 2 -#define MAX_FEATURE_OFFSET 0x50 +#define MAX_FEATURE_OFFSET 0x100 #define FREG(c,r) (&(((c)->reg)[(r)>>2])) +/* Keylargo reg. access. */ +#define KL_FCR(r) (keylargo_base + ((r) >> 2)) +#define KL_IN(r) (in_le32(KL_FCR(r))) +#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v))) +#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v))) +#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v))) + +/* Uni-N reg. access. Note that Uni-N regs are big endian */ +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + typedef struct feature_bit { int reg; /* reg. offset from mac-io base */ unsigned int polarity; /* 0 = normal, 1 = inverse */ unsigned int mask; /* bit mask */ } fbit; -/* I don't have an OHare machine to test with, so I left those as they - * were. Someone with such a machine chould check out what OF says and - * try too see if they match the heathrow ones and should be changed too +/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500) */ static fbit feature_bits_ohare_pbook[] = { {0x38,0,0}, /* FEATURE_null */ @@ -69,13 +80,48 @@ {0x38,0,0}, /* FEATURE_IDE2_reset */ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ }; -/* Those bits are from a PowerBook. It's possible that desktop machines - * based on heathrow need a different definition or some bits removed +/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed + * the SCC related bits and init them once. They have proven to occasionally cause + * problems with the desktop units. */ static fbit feature_bits_heathrow[] = { {0x38,0,0}, /* FEATURE_null */ + {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,0}, /* FEATURE_Serial_enable */ + {0x38,0,0}, /* FEATURE_Serial_IO_A */ + {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ + {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ + {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ + {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ + {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ + {0x38,1,0}, /* FEATURE_Mediabay_reset */ + {0x38,1,0}, /* FEATURE_Mediabay_power */ + {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ + {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ + {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ + {0x38,1,0}, /* FEATURE_Modem_power */ + {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,1,0}, /* FEATURE_Sound_Power */ + {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x38,0,0}, /* FEATURE_IDE2_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ + {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ +}; + +/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet). + * Heathrow-based desktop macs (Beige G3s) are _not_ handled here + */ +static fbit feature_bits_wallstreet[] = { + {0x38,0,0}, /* FEATURE_null */ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ @@ -101,15 +147,17 @@ {0x38,0,0}, /* FEATURE_IDE2_reset */ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ }; /* * Those bits are from a 1999 G3 PowerBook, with a paddington chip. - * Mostly the same as the heathrow. + * Mostly the same as the heathrow. They are used on both PowerBooks + * and desktop machines using the paddington chip */ static fbit feature_bits_paddington[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,PADD_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */ @@ -134,37 +182,40 @@ {0x38,0,0}, /* FEATURE_IDE2_reset */ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ }; /* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...). + * Note: Different sets may be needed for iBook, especially for sound */ static fbit feature_bits_keylargo[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ - {0x38,0,0x00000054}, /* FEATURE_Serial_enable */ - {0x38,0,0}, /* FEATURE_Serial_IO_A */ - {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */ + {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */ + {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */ + {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ {0x38,0,0}, /* FEATURE_SWIM3_enable */ {0x38,0,0}, /* FEATURE_MESH_enable */ {0x3c,0,0}, /* FEATURE_IDE0_enable */ - {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */ + {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ {0x38,0,0}, /* FEATURE_IOBUS_enable */ {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */ {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ {0x3c,0,0x0}, /* FEATURE_IDE1_enable */ - {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */ + {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ {0x38,0,0}, /* FEATURE_BMac_reset */ {0x38,0,0}, /* FEATURE_BMac_IO_enable */ - {0x40,1,0x02000000}, /* FEATURE_Modem_power */ + {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ {0x38,0,0}, /* FEATURE_Sound_Power */ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */ - {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */ + {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ + {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */ {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */ + {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ }; /* definition of a feature controller object */ @@ -176,33 +227,93 @@ }; /* static functions */ -static void +static struct feature_controller* feature_add_controller(struct device_node *controller_device, fbit* bits); static struct feature_controller* feature_lookup_controller(struct device_node *device); -/* static varialbles */ +static void uninorth_init(void); +static void keylargo_init(void); +#ifdef CONFIG_PMAC_PBOOK +static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); +static void heathrow_wakeup(struct feature_controller* ctrler); +static void core99_prepare_for_sleep(struct feature_controller* ctrler); +static void core99_wake_up(struct feature_controller* ctrler); +#endif /* CONFIG_PMAC_PBOOK */ + +/* static variables */ static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS]; static int controller_count = 0; +/* Core99 stuffs */ +static volatile u32* uninorth_base; +static volatile u32* keylargo_base; +static struct feature_controller* keylargo; +static int uninorth_rev; +static int keylargo_rev; +static u32 board_features; + +#define FTR_NEED_OPENPIC_TWEAK 0x00000001 + +static struct board_features_t { + char* compatible; + u32 features; +} board_features_datas[] __init = +{ + { "PowerMac2,1", 0 }, /* iMac ? */ + { "PowerMac2,2", 0 }, /* iMac ? */ + { "PowerMac3,1", FTR_NEED_OPENPIC_TWEAK }, /* Sawtooth (G4) */ + { "PowerMac3,3", 0 }, /* Dual G4 or Cube ? */ + { "PowerMac5,1", 0 }, /* Dual G4 or Cube ? */ + { "PowerBook2,1", 0 }, /* iBook */ + { "PowerBook2,2", 0 }, /* iBook FireWire ? */ + { "PowerBook3,1", 0 }, /* PowerBook 2000 (Pismo) */ + { NULL, 0 } +}; void feature_init(void) { struct device_node *np; + u32* rev; + int i; + + /* Figure out motherboard type & options */ + for(i=0;board_features_datas[i].compatible;i++) + if (machine_is_compatible(board_features_datas[i].compatible)) { + board_features = board_features_datas[i].features; + break; + } + /* Track those poor mac-io's */ + np = find_devices("mac-io"); while (np != NULL) { /* KeyLargo contains several (5 ?) FCR registers in mac-io, * plus some gpio's which could eventually be handled here. */ if (device_is_compatible(np, "Keylargo")) { - feature_add_controller(np, feature_bits_keylargo); + struct feature_controller* ctrler = + feature_add_controller(np, feature_bits_keylargo); + if (ctrler) { + keylargo = ctrler; + keylargo_base = ctrler->reg; + rev = (u32 *)get_property(ctrler->device, "revision-id", NULL); + if (rev) + keylargo_rev = *rev; + } } else if (device_is_compatible(np, "paddington")) { feature_add_controller(np, feature_bits_paddington); + } else if (machine_is_compatible("AAPL,PowerBook1998")) { + feature_add_controller(np, feature_bits_wallstreet); } else { - feature_add_controller(np, feature_bits_heathrow); + struct feature_controller* ctrler = + feature_add_controller(np, feature_bits_heathrow); + if (ctrler) + out_le32(FREG(ctrler,HEATHROW_FEATURE_REG), + in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS); + } np = np->next; } @@ -218,6 +329,20 @@ } } + /* Locate core99 Uni-N */ + np = find_devices("uni-n"); + if (np && np->n_addrs > 0) { + uninorth_base = ioremap(np->addrs[0].address, 0x1000); + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + } + if (uninorth_base && keylargo_base) + printk("Uni-N revision: %d, KeyLargo revision: %d\n", + uninorth_rev, keylargo_rev); + if (uninorth_base) + uninorth_init(); + if (keylargo_base) + keylargo_init(); + if (controller_count) printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); @@ -232,7 +357,7 @@ #endif } -static void +static struct feature_controller* feature_add_controller(struct device_node *controller_device, fbit* bits) { struct feature_controller* controller; @@ -240,7 +365,7 @@ if (controller_count >= MAX_FEATURE_CONTROLLERS) { printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n", controller_device->full_name, MAX_FEATURE_CONTROLLERS); - return; + return NULL; } controller = &controllers[controller_count]; @@ -249,21 +374,27 @@ if (controller_device->n_addrs == 0) { printk(KERN_ERR "No addresses for %s\n", controller_device->full_name); - return; + return NULL; } + /* We remap the entire mac-io here. Normally, this will just + * give us back our already existing BAT mapping + */ controller->reg = (volatile u32 *)ioremap( - controller_device->addrs[0].address, MAX_FEATURE_OFFSET); + controller_device->addrs[0].address, + controller_device->addrs[0].size); if (bits == NULL) { printk(KERN_INFO "Twiddling the magic ohare bits\n"); out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES); - return; + return NULL; } spin_lock_init(&controller->lock); controller_count++; + + return controller; } static struct feature_controller* @@ -383,5 +514,371 @@ */ value = (in_le32(FREG(controller, bit->reg)) & bit->mask); return bit->polarity ? (value == 0) : (value == bit->mask); +} + +/* + * Core99 functions + * + * Note: We currently assume there is _one_ UniN chip and _one_ KeyLargo + * chip, which is the case on all Core99 machines so far + */ + +/* Only one GMAC is assumed */ +void +feature_set_gmac_power(struct device_node* device, int power) +{ + unsigned long flags; + + if (!uninorth_base || !keylargo) + return; + + spin_lock_irqsave(&keylargo->lock, flags); + if (power) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + spin_unlock_irqrestore(&keylargo->lock, flags); + udelay(20); +} + +void +feature_set_gmac_phy_reset(struct device_node* device, int reset) +{ + unsigned long flags; + + if (!keylargo_base || !keylargo) + return; + + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); + spin_unlock_irqrestore(&keylargo->lock, flags); +} + +/* Pass the node of the correct controller, please */ +void +feature_set_usb_power(struct device_node* device, int power) +{ + char* prop; + int number; + u32 reg; + + unsigned long flags; + + if (!keylargo_base || !keylargo) + return; + + prop = (char *)get_property(device, "AAPL,clock-id", NULL); + if (!prop) + return; + if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) + number = 0; + else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) + number = 2; + else + return; + + spin_lock_irqsave(&keylargo->lock, flags); + if (power) { + /* Turn ON */ + + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + } else { + KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } + reg = KL_IN(KEYLARGO_FCR4); + reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number)); + reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1)); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(10); + } else { + /* Turn OFF */ + + reg = KL_IN(KEYLARGO_FCR4); + reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number); + reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(1); + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } else { + KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } + udelay(1); + } + spin_unlock_irqrestore(&keylargo->lock, flags); +} + +/* Not yet implemented */ +void +feature_set_firewire_power(struct device_node* device, int power) +{ +} + +#ifdef CONFIG_SMP +void +feature_core99_kick_cpu1(void) +{ + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT); + udelay(1); + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE); +} +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_PMAC_PBOOK +void +feature_prepare_for_sleep(void) +{ + /* We assume gatwick is second */ + struct feature_controller* ctrler = &controllers[0]; + + if (!ctrler) + return; + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_prepare_for_sleep(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_prepare_for_sleep(ctrler); + return; + } +} + + +void +feature_wake_up(void) +{ + struct feature_controller* ctrler = &controllers[0]; + + if (!ctrler) + return; + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_wakeup(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_wake_up(ctrler); + return; + } +} + +static u32 save_fcr[5]; +static u32 save_mbcr; +static u32 save_gpio_levels[2]; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; + +static void +heathrow_prepare_for_sleep(struct feature_controller* ctrler) +{ + save_mbcr = in_le32(FREG(ctrler, 0x34)); + save_fcr[0] = in_le32(FREG(ctrler, 0x38)); + save_fcr[1] = in_le32(FREG(ctrler, 0x3c)); + + out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE); +} + +static void +heathrow_wakeup(struct feature_controller* ctrler) +{ + out_le32(FREG(ctrler, 0x38), save_fcr[0]); + out_le32(FREG(ctrler, 0x3c), save_fcr[1]); + out_le32(FREG(ctrler, 0x34), save_mbcr); + mdelay(1); + out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE); + mdelay(1); +} + + +static void +core99_prepare_for_sleep(struct feature_controller* ctrler) +{ + u32 temp; + int i; + u8* base8; + + /* + * Save various bits of KeyLargo + */ + + save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0); + save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; i= 2) + temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); + + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; + temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + KL_OUT(KEYLARGO_FCR3, temp); + + /* + * Put the host bridge to sleep + */ + + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); + + /* + * FIXME: A bit of black magic with OpenPIC (don't ask me why) + */ + if (board_features & FTR_NEED_OPENPIC_TWEAK) { + KL_BIS(0x506e0, 0x00400000); + KL_BIS(0x506e0, 0x80000000); + } +} + +static void +core99_wake_up(struct feature_controller* ctrler) +{ + int i; + u8* base8; + + /* + * Wakeup the host bridge + */ + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + + /* + * Restore KeyLargo + */ + + KL_OUT(KEYLARGO_MBCR, save_mbcr); + KL_OUT(KEYLARGO_FCR0, save_fcr[0]); + KL_OUT(KEYLARGO_FCR1, save_fcr[1]); + KL_OUT(KEYLARGO_FCR2, save_fcr[2]); + KL_OUT(KEYLARGO_FCR3, save_fcr[3]); + KL_OUT(KEYLARGO_FCR4, save_fcr[4]); + mdelay(1); + KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); + KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; inext; + } + if (gmac) + feature_set_gmac_power(gmac, 0); +} + +/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure + * OpenPIC is enabled + */ +static void +keylargo_init(void) +{ + KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.2.17/arch/ppc/kernel/gemini_setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/gemini_setup.c Wed Nov 8 23:00:34 2000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include "local_irq.h" @@ -166,8 +168,6 @@ ioremap( GEMINI_MPIC_ADDR, sizeof( struct OpenPIC )); } - -extern unsigned long loops_per_sec; extern int root_mountflags; extern char cmd_line[]; @@ -179,7 +179,7 @@ extern char cmd_line[]; - loops_per_sec = 50000000; + loops_per_jiffy = 50000000/HZ; #ifdef CONFIG_BLK_DEV_INITRD /* bootable off CDROM */ @@ -258,14 +258,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 */ -#define L2CR_L2I (0x00200000) /* global invalidate */ -#define L2CR_L2E (0x80000000) /* enable */ -#define L2CR_L2WT (0x00080000) /* write-through */ - void __init gemini_init_l2(void) { unsigned char reg; @@ -339,8 +331,7 @@ cache |= L2CR_L2WT; #endif cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE; - _set_L2CR(0); - _set_L2CR(cache|L2CR_L2I|L2CR_L2E); + _set_L2CR(cache|L2CR_L2E); } } @@ -390,7 +381,7 @@ #define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) /* ensure that the RTC is up and running */ -void __init gemini_time_init(void) +long __init gemini_time_init(void) { unsigned char reg; @@ -401,6 +392,7 @@ gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); } + return 0; } #undef DEBUG_RTC @@ -571,6 +563,6 @@ ppc_md.kbd_leds = NULL; ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = NULL; + ppc_md.sysrq_xlate = NULL; #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.2.17/arch/ppc/kernel/head.S Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/head.S Wed Nov 8 23:00:34 2000 @@ -23,6 +23,10 @@ * 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. + * + * 2000-04-10. + * Add sys_rt_sigreturn in DoSyscall Handler. + * Giovanna Ambrosini (ambrosini@lightning.ch). * */ @@ -258,66 +262,15 @@ __secondary_start: /* Switch MMU off, clear BATs and flush TLB */ bl mmu_off +mmu_off_return: bl clear_bats bl flush_tlbs - -/* Use the first pair of BAT registers to map the 1st 16MB - * of RAM to KERNELBASE. From this point on we can't safely - * call OF any more. - */ - lis r11,KERNELBASE@h - mfspr r9,PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 - bne 4f - ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f /* valid, block length = 8MB */ - oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ - oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ - mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */ - mtspr IBAT0L,r8 /* lower BAT register */ - mtspr IBAT1U,r9 - mtspr IBAT1L,r10 - b 5f -4: -#ifdef CONFIG_APUS - ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */ - ori r11,r11,0xfe /* set up an 8MB mapping */ - lis r8,CYBERBASEp@h - lwz r8,0(r8) - addis r8,r8,KERNELBASE@h - addi r8,r8,2 -#else - ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ - li r8,2 /* R/W access */ - /* - * If the MMU is off clear the bats. See clear_bat() -- Cort - */ -#ifndef CONFIG_GEMINI - /* - * allow secondary cpus to get at all of ram in early bootup - * since their init_task may be up there -- Cort - */ - oris r18,r8,0x10000000@h - oris r21,r11,(KERNELBASE+0x10000000)@h - mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */ - mtspr DBAT1U,r21 /* bit in upper BAT register */ - mtspr IBAT1L,r18 - mtspr IBAT1U,r21 - - oris r18,r8,0x20000000@h - oris r21,r11,(KERNELBASE+0x20000000)@h - mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ - mtspr DBAT2U,r21 /* bit in upper BAT register */ - mtspr IBAT2L,r18 - mtspr IBAT2U,r21 -#endif /* ndef CONFIG_GEMINI */ + bl setup_init_bats +#ifndef CONFIG_APUS +#ifdef CONFIG_BOOTX_TEXT + bl setup_disp_bat +#endif #endif - mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ - mtspr DBAT0U,r11 /* bit in upper BAT register */ - mtspr IBAT0L,r8 - mtspr IBAT0U,r11 -5: isync #ifdef CONFIG_APUS /* Unfortunately the APUS specific instructions bloat the * code so it cannot fit in the 0x100 bytes available. We have @@ -443,6 +396,15 @@ #endif /* CONFIG_8xx */ b turn_on_mmu +/* Hack for sleep on Core99 machines + */ +#ifdef CONFIG_POWERMAC + . = 0x80 +SleepVector: + .long 0 + .long 0 +#endif /* CONFIG_POWERMAC */ + /* * GCC sometimes accesses words at negative offsets from the stack * pointer, although the SysV ABI says it shouldn't. To cope with @@ -515,7 +477,7 @@ #endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) -#endif +#endif /* Machine check */ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) @@ -1383,11 +1345,7 @@ /* Construct the high word of the PPC-style PTE */ mfsrin r5,r3 /* get segment reg for segment */ rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ - -#ifndef __SMP__ /* do this later for SMP */ oris r5,r5,0x8000 /* set V (valid) bit */ -#endif - rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ /* Get the address of the primary PTE group in the hash table */ .globl hash_page_patch_A @@ -1499,6 +1457,7 @@ */ found_empty: found_slot: + clrlwi r5,r5,1 /* clear valid bit (0x80000000) */ stw r5,0(r3) /* clear V (valid) bit in PTE */ sync tlbsync @@ -1819,14 +1778,8 @@ blr #endif /* CONFIG_ALTIVEC */ -#else /* CONFIG_8xx */ - .globl giveup_fpu -giveup_fpu: - blr -#endif /* CONFIG_8xx */ - mmu_off: - addi r4, r3, __secondary_start - _start + addi r4, r3, mmu_off_return - _start mfmsr r3 andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ beqlr @@ -1892,6 +1845,12 @@ . = 0x4000 #endif +#else /* CONFIG_8xx */ + .globl giveup_fpu +giveup_fpu: + blr +#endif /* CONFIG_8xx */ + turn_on_mmu: mfmsr r0 ori r1,r0,MSR_DR|MSR_IR @@ -1984,6 +1943,7 @@ cror 14,14,18 bne 3,6f ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC|HID0_ABE /* for g3/g4, enable */ + rlwinm r11,r11,0,23,21 /* clear HID0_SPD */ li r3,0 mtspr ICTC,r3 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ @@ -2166,7 +2126,9 @@ 1: #endif /* SHOW_SYSCALLS */ cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */ + cmpi 1,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */ beq- 10f + beq- cr1,16f lwz r10,TASK_FLAGS(r2) andi. r10,r10,PF_TRACESYS bne- 50f @@ -2213,6 +2175,12 @@ /* sys_sigreturn */ 10: addi r3,r1,STACK_FRAME_OVERHEAD bl sys_sigreturn + cmpi 0,r3,0 /* Check for restarted system call */ + bge int_return + b 20b +/* sys_rt_sigreturn */ +16: addi r3,r1,STACK_FRAME_OVERHEAD + bl sys_rt_sigreturn cmpi 0,r3,0 /* Check for restarted system call */ bge int_return b 20b @@ -2883,30 +2851,6 @@ mtlr r4 blr #endif /* CONFIG_8xx */ - -/* - * 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 - .globl sdata -sdata: - .globl empty_zero_page -empty_zero_page: - .space 4096 - - .globl swapper_pg_dir -swapper_pg_dir: - .space 4096 - -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 /* * An undocumented "feature" of 604e requires that the v bit @@ -2951,4 +2895,117 @@ blt 1b sync blr + +/* Use the first pair of BAT registers to map the 1st 16MB + * of RAM to KERNELBASE. From this point on we can't safely + * call OF any more. + */ +setup_init_bats: + lis r11,KERNELBASE@h + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpi 0,r9,1 + bne 4f + ori r11,r11,4 /* set up BAT registers for 601 */ + li r8,0x7f /* valid, block length = 8MB */ + oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ + oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ + mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */ + mtspr IBAT0L,r8 /* lower BAT register */ + mtspr IBAT1U,r9 + mtspr IBAT1L,r10 + b 5f +4: +#ifdef CONFIG_APUS + ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */ + ori r11,r11,0xfe /* set up an 8MB mapping */ + lis r8,CYBERBASEp@h + lwz r8,0(r8) + addis r8,r8,KERNELBASE@h + addi r8,r8,2 +#else + ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ + li r8,2 /* R/W access */ + /* + * If the MMU is off clear the bats. See clear_bat() -- Cort + */ +#ifndef CONFIG_GEMINI + /* + * allow secondary cpus to get at all of ram in early bootup + * since their init_task may be up there -- Cort + */ + oris r18,r8,0x10000000@h + oris r21,r11,(KERNELBASE+0x10000000)@h + mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT1U,r21 /* bit in upper BAT register */ + mtspr IBAT1L,r18 + mtspr IBAT1U,r21 + oris r18,r8,0x20000000@h + oris r21,r11,(KERNELBASE+0x20000000)@h + mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT2U,r21 /* bit in upper BAT register */ + mtspr IBAT2L,r18 + mtspr IBAT2U,r21 +#endif /* ndef CONFIG_GEMINI */ +#endif + mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT0U,r11 /* bit in upper BAT register */ + mtspr IBAT0L,r8 + mtspr IBAT0U,r11 +5: isync + blr + +#ifdef CONFIG_BOOTX_TEXT +setup_disp_bat: + /* + * setup the display bat prepared for us in prom.c + */ + mflr r8 + bl reloc_offset + mtlr r8 + lis r8, disp_BATL@h + ori r8, r8, disp_BATL@l + add r8, r3, r8 + lwz r8, 0(r8) + lis r11, disp_BATU@h + ori r11, r11, disp_BATU@l + add r11, r3, r11 + lwz r11, 0(r11) + mtspr IBAT3L,r8 + mtspr IBAT3U,r11 + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpi 0,r9,1 + beq 1f + mtspr DBAT3L,r8 + mtspr DBAT3U,r11 +1: + blr +#endif + +/* + * 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 + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.2.17/arch/ppc/kernel/irq.c Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/kernel/irq.c Wed Nov 8 23:00:34 2000 @@ -61,7 +61,9 @@ #include "local_irq.h" -extern volatile unsigned long ipi_count; +extern atomic_t ipi_recv; +extern atomic_t ipi_sent; +void enable_irq(unsigned int irq_nr); void enable_irq(unsigned int irq_nr); void disable_irq(unsigned int irq_nr); @@ -137,20 +139,21 @@ if (!handler) { /* Free */ - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) - { - if (action->dev_id == dev_id) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - restore_flags(flags); - irq_kfree(action); - return 0; - } - } - return -ENOENT; + p = &irq_desc[irq].action; + while ((action = *p) != NULL && action->dev_id != dev_id) + p = &action->next; + if (action == NULL) + return -ENOENT; + + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + if (irq_desc[irq].action == NULL) + disable_irq(irq); + restore_flags(flags); + irq_kfree(action); + return 0; } action = (struct irqaction *) @@ -241,8 +244,10 @@ } #ifdef __SMP__ /* should this be per processor send/receive? */ - len += sprintf(buf+len, "IPI: %10lu\n", ipi_count); -#endif + /* should this be per processor send/receive? */ + len += sprintf(buf+len, "IPI: (recv/sent) %10lu/%lu\n", + atomic_read(&ipi_recv), atomic_read(&ipi_sent)); +#endif /* __SMP__ */ len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts); return len; } @@ -317,10 +322,14 @@ atomic_t global_bh_count; atomic_t global_bh_lock; +extern unsigned long *_get_SP(void); + static void show(char * str) { +#if 0 int i; unsigned long *stack; +#endif int cpu = smp_processor_id(); printk("\n%s, CPU %d:\n", str, cpu); @@ -332,6 +341,10 @@ atomic_read(&global_bh_count), ppc_local_bh_count[0], ppc_local_bh_count[1]); +#if 1 + printk(" CPU: %d last CPU: %d\n", current->processor,current->last_processor); + print_backtrace (_get_SP()); +#else stack = (unsigned long *) &str; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -339,6 +352,7 @@ printk("<[%08lx]> ", x); } } +#endif } static inline void wait_on_bh(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/mbx_pci.c linux/arch/ppc/kernel/mbx_pci.c --- v2.2.17/arch/ppc/kernel/mbx_pci.c Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/kernel/mbx_pci.c Wed Nov 8 23:00:34 2000 @@ -17,7 +17,9 @@ #include #include +#include +#include "pci.h" /* * This blows......The MBX uses the Tundra QSpan PCI bridge. When diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c --- v2.2.17/arch/ppc/kernel/mbx_setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/mbx_setup.c Wed Nov 8 23:00:34 2000 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -40,14 +41,25 @@ #include #include #include - +#include +#include #include + #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 pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; + extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, @@ -56,8 +68,6 @@ 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 @@ -453,8 +463,8 @@ 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; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.2.17/arch/ppc/kernel/misc.S Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/misc.S Thu Dec 7 14:55:01 2000 @@ -125,12 +125,33 @@ * Flush MMU TLB */ _GLOBAL(_tlbia) +#if defined(CONFIG_SMP) + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,10 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif /* CONFIG_SMP */ sync tlbia sync #ifdef __SMP__ tlbsync sync + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ + mtmsr r10 + SYNC #endif blr @@ -138,11 +159,32 @@ * Flush MMU TLB for a particular address */ _GLOBAL(_tlbie) +#if defined(CONFIG_SMP) + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,11 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif /* CONFIG_SMP */ tlbie r3 sync -#ifdef __SMP__ +#ifdef CONFIG_SMP tlbsync sync + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ + mtmsr r10 + SYNC #endif blr @@ -312,8 +354,10 @@ * The *_ns versions don't do byte-swapping. */ _GLOBAL(_insb) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 + blelr- 00: lbz r5,0(r3) eieio stbu r5,1(r4) @@ -321,8 +365,10 @@ blr _GLOBAL(_outsb) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 + blelr- 00: lbzu r5,1(r4) stb r5,0(r3) eieio @@ -330,8 +376,10 @@ blr _GLOBAL(_insw) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhbrx r5,0,r3 eieio sthu r5,2(r4) @@ -339,8 +387,10 @@ blr _GLOBAL(_outsw) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhzu r5,2(r4) eieio sthbrx r5,0,r3 @@ -348,8 +398,10 @@ blr _GLOBAL(_insl) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwbrx r5,0,r3 eieio stwu r5,4(r4) @@ -357,8 +409,10 @@ blr _GLOBAL(_outsl) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwzu r5,4(r4) stwbrx r5,0,r3 eieio @@ -367,8 +421,10 @@ _GLOBAL(ide_insw) _GLOBAL(_insw_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhz r5,0(r3) eieio sthu r5,2(r4) @@ -377,8 +433,10 @@ _GLOBAL(ide_outsw) _GLOBAL(_outsw_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhzu r5,2(r4) sth r5,0(r3) eieio @@ -386,8 +444,10 @@ blr _GLOBAL(_insl_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwz r5,0(r3) eieio stwu r5,4(r4) @@ -395,8 +455,10 @@ blr _GLOBAL(_outsl_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwzu r5,4(r4) stw r5,0(r3) eieio @@ -494,15 +556,13 @@ mfspr r3,HID0 blr -_GLOBAL(_get_ICTC) - mfspr r3,ICTC - blr - -_GLOBAL(_set_ICTC) - mtspr ICTC,r3 +_GLOBAL(_set_HID0) + sync + mtspr HID0, r3 + sync + isync /* Handle erratas in some cases */ blr - /* L2CR functions Copyright Š 1997-1998 by PowerLogix R & D, Inc. @@ -524,6 +584,17 @@ /* Thur, Dec. 12, 1998. - First public release, contributed by PowerLogix. + *********** + Sat, Aug. 7, 1999. + - Terry: Made sure code disabled interrupts before running. (Previously + it was assumed interrupts were already disabled). + - Terry: Updated for tentative G4 support. 4MB of memory is now flushed + instead of 2MB. (Prob. only 3 is necessary). + - Terry: Updated for workaround to HID0[DPM] processor bug + during global invalidates. + *********** + Thu, July 13, 2000. + - Terry: Added isync to correct for an errata. Author: Terry Greeniaus (tgree@phys.ualberta.ca) Please e-mail updates to this file to me, thanks! @@ -562,82 +633,94 @@ causes cache pushes from the L1 cache to go to the L2 cache instead of to main memory. */ - +/* + * Summary: this procedure ignores the L2I bit in the value passed in, + * flushes the cache if it was already enabled, always invalidates the + * cache, then enables the cache if the L2E bit is set in the value + * passed in. + * -- paulus. + */ _GLOBAL(_set_L2CR) - /* Make sure this is a 750 chip */ + /* Make sure this is a 750 or 7400 chip */ mfspr r4,PVR rlwinm r4,r4,16,16,31 - cmplwi r4,0x0008 - beq thisIs750 - cmplwi r4,0x000c - beq thisIs750 - li r3,-1 - blr - -thisIs750: - /* Get the current enable bit of the L2CR into r4 */ - mfspr r4,L2CR - mfmsr r7 - - /* See if we want to perform a global inval this time. */ - rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */ - rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */ - rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ - rlwimi r3,r4,0,0,0 /* Keep the enable bit the same as it was. */ - bne dontDisableCache /* Only disable the cache if L2CRApply - has the enable bit off */ - -disableCache: - /* Disable the cache. First, we turn off interrupts. - An interrupt while we are flushing the cache could bring - in data which may not get properly flushed. */ - rlwinm r4,r7,0,17,15 /* Turn off EE bit */ + cmpwi r4,0x0008 + cmpwi cr1,r4,0x000c + cror 2,2,4*cr1+2 + bne 99f + + /* Turn off interrupts and data relocation. */ + mfmsr r7 /* Save MSR in r7 */ + rlwinm r4,r7,0,17,15 + rlwinm r4,r4,0,28,26 /* Turn off DR bit */ sync mtmsr r4 sync + + /* Get the current enable bit of the L2CR into r4 */ + mfspr r4,L2CR -/* - Now, read the first 2MB of memory to put new data in the cache. - (Actually we only need the size of the L2 cache plus the size - of the L1 cache, but 2MB will cover everything just to be safe). -*/ - lis r4,0x0001 + /* Tweak some bits */ + rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */ + rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ + rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ + + /* Check to see if we need to flush */ + rlwinm. r4,r4,0,0,0 + beq 2f + + /* Flush the cache. First, read the first 4MB of memory (physical) to + * put new data in the cache. (Actually we only need + * the size of the L2 cache plus the size of the L1 cache, but 4MB will + * cover everything just to be safe). + */ + + /**** Might be a good idea to set L2DO here - to prevent instructions + from getting into the cache. But since we invalidate + the next time we enable the cache it doesn't really matter. + ****/ + + lis r4,0x0002 mtctr r4 - lis r4,KERNELBASE@h -1: lwzx r0,r0,r4 - addi r4,r4,0x0020 /* Go to start of next cache line */ + li r4,0 +1: + lwzx r0,r0,r4 + addi r4,r4,32 /* Go to start of next cache line */ bdnz 1b - /* Now, flush the first 2MB of memory */ - lis r4,0x0001 + /* Now, flush the first 4MB of memory */ + lis r4,0x0002 mtctr r4 - lis r4,KERNELBASE@h + li r4,0 sync -2: dcbf r0,r4 - addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz 2b - - /* Turn off the L2CR enable bit. */ - rlwinm r3,r3,0,1,31 - -dontDisableCache: - /* Set up the L2CR configuration bits */ +1: + dcbf r0,r4 + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + +2: + /* Set up the L2CR configuration bits (and switch L2 off) */ sync mtspr L2CR,r3 sync - /* Reenable interrupts if necessary. */ - mtmsr r7 + /* Before we perform the global invalidation, we must disable dynamic + * power management via HID0[DPM] to work around a processor bug where + * DPM can possibly interfere with the state machine in the processor + * that invalidates the L2 cache tags. + */ + mfspr r8,HID0 /* Save HID0 in r8 */ + rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */ sync - - cmplwi r6,0 - beq noInval - + mtspr HID0,r4 /* Disable DPM */ + sync + /* Perform a global invalidation */ oris r3,r3,0x0020 sync mtspr L2CR,r3 sync + isync /* For errata */ /* Wait for the invalidation to complete */ 3: mfspr r3,L2CR @@ -649,27 +732,38 @@ mtspr L2CR,r3 sync -noInval: + /* Restore HID0[DPM] to whatever it was before */ + sync + mtspr 1008,r8 + sync + /* See if we need to enable the cache */ cmplwi r5,0 - beqlr + beq 4f /* Enable the cache */ oris r3,r3,0x8000 mtspr L2CR,r3 sync + + /* Restore MSR (restores EE and DR bits to original state) */ +4: sync + mtmsr r7 + sync + blr + +99: li r3,-1 blr _GLOBAL(_get_L2CR) /* Make sure this is a 750 chip */ mfspr r3,PVR - rlwinm r3,r3,16,16,31 - cmplwi r3,0x0008 - beq 1f - cmplwi r3,0x000c + srwi r3,r3,16 + cmpwi r3,0x0008 + cmpwi cr1,r3,0x000c li r3,0 + cror 2,2,4*cr1+2 bnelr -1: /* Return the L2CR contents */ mfspr r3,L2CR blr @@ -677,16 +771,6 @@ /* --- End of PowerLogix code --- */ -/* -_GLOBAL(_get_L2CR) - mfspr r3,L2CR - blr - -_GLOBAL(_set_L2CR) - mtspr L2CR,r3 - blr - -*/ /* * These are used in the alignment trap handler when emulating @@ -944,11 +1028,7 @@ .long sys_getresuid /* 165 */ .long sys_query_module .long sys_poll -#ifdef CONFIG_NFSD .long sys_nfsservctl -#else - .long sys_ni_syscall -#endif .long sys_setresgid .long sys_getresgid /* 170 */ .long sys_prctl @@ -970,4 +1050,18 @@ .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ .long sys_vfork - .space (NR_syscalls-183)*4 + .long sys_ni_syscall /* 190 */ /* MacOnLinux - old */ + .long sys_ni_syscall /* 191 */ /* Unused */ + .long sys_ni_syscall /* 192 - reserved - mmap2 */ + .long sys_ni_syscall /* 193 - reserved - truncate64 */ + .long sys_ni_syscall /* 194 - reserved - ftruncate64 */ + .long sys_ni_syscall /* 195 - reserved - stat64 */ + .long sys_ni_syscall /* 196 - reserved - lstat64 */ + .long sys_ni_syscall /* 197 - reserved - fstat64 */ + .long sys_pciconfig_read /* 198 */ + .long sys_pciconfig_write /* 199 */ + .long sys_pciconfig_iobase /* 200 */ + .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ + .rept NR_syscalls-201 + .long sys_ni_syscall + .endr diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.2.17/arch/ppc/kernel/open_pic.c Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/kernel/open_pic.c Wed Nov 8 23:00:34 2000 @@ -1,48 +1,126 @@ +/* + * open_pic.c + * + * Common support routines for platforms with an OpenPIC interrupt controller + * + */ + #include #include #include #include #include #include +#include #include "open_pic.h" #include "i8259.h" -#ifdef __SMP__ -void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) -{ - smp_message_recv(cpl-OPENPIC_VEC_IPI); -} -#endif /* __SMP__ */ +extern volatile unsigned char *chrp_int_ack_special; -void chrp_mask_and_ack_irq(unsigned int irq_nr) +void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake) { - if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) - i8259_pic.mask_and_ack(irq_nr); -} + int irq; + int openpic_eoi_done = 0; -static void chrp_mask_irq(unsigned int irq_nr) -{ - if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) - i8259_pic.disable(irq_nr); +#ifdef __SMP__ + { + unsigned int loops = 1000000; + while (test_bit(0, &global_irq_lock)) { + if (smp_processor_id() == global_irq_holder) { + printk("uh oh, interrupt while we hold global irq lock!\n"); +#ifdef CONFIG_XMON + xmon(0); +#endif + break; + } + if (loops-- == 0) { + printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); +#ifdef CONFIG_XMON + xmon(0); +#endif + } + } + } +#endif /* __SMP__ */ + + irq = openpic_irq(smp_processor_id()); + /* make sure open_pic.irq_offset is set to something! + * do we really need the _MACH_Pmac test?? + */ + if (!(_machine == _MACH_Pmac) && (irq == open_pic.irq_offset)) + { + /* + * This magic address generates a PCI IACK cycle. + * + * This should go in the above mask/ack code soon. -- Cort + */ + if ( chrp_int_ack_special ) + irq = *chrp_int_ack_special; +#ifndef CONFIG_PMAC + else + irq = i8259_irq(0); +#endif + /* + * Acknowledge as soon as possible to allow i8259 + * interrupt nesting */ + openpic_eoi(smp_processor_id()); + openpic_eoi_done = 1; + } + if (irq == OPENPIC_VEC_SPURIOUS) + { + /* + * Spurious interrupts should never be + * acknowledged + */ + ppc_spurious_interrupts++; + openpic_eoi_done = 1; + goto out; + } + + if (irq < 0) + { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } else - openpic_disable_irq(irq_nr-open_pic.irq_offset); + { + ppc_irq_dispatch_handler( regs, irq ); + } +out: + if (!openpic_eoi_done) + openpic_eoi(smp_processor_id()); } -static void chrp_unmask_irq(unsigned int irq_nr) +#ifdef __SMP__ +void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { - if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) - i8259_pic.enable(irq_nr); - else - openpic_enable_irq(irq_nr-open_pic.irq_offset); + smp_message_recv(cpl-OPENPIC_VEC_IPI); } +#endif /* __SMP__ */ + struct hw_interrupt_type open_pic = { " OpenPIC ", NULL, NULL, NULL, - chrp_unmask_irq, - chrp_mask_irq, - chrp_mask_and_ack_irq, + openpic_enable_irq, + openpic_disable_irq, + /* Theorically, the mask&ack should be NULL for OpenPIC. However, doing + * so shows tons of bogus interrupts coming in. + * This problem is apparently due to the common code always calling + * unmask(). I apparently (need more test) fixed it in the 2.4 new IRQ + * management by cleanly implementing the handler's end() function, so + * neither mask nor unmask are needed. In the meantime, the fix below will + * work for 2.2 -Benh + * + * Hopefully this will fix my bogus interrups on MTX + * I merged everthing together so we don't have the same code in three + * places. This might cause stability problems, but I'd rather + * get it right once than three different times because someone forgot + * to make the same change to PReP or something --Troy + */ + openpic_disable_irq, 0 }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h --- v2.2.17/arch/ppc/kernel/open_pic.h Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/kernel/open_pic.h Wed Nov 8 23:00:34 2000 @@ -6,6 +6,7 @@ extern struct hw_interrupt_type open_pic; +void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake); 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); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c --- v2.2.17/arch/ppc/kernel/openpic.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/openpic.c Wed Nov 8 23:00:34 2000 @@ -175,7 +175,10 @@ * Note: We might want to adjust priorities too. */ -__initfunc(void openpic_init(int main_pic)) +/* Not an init func, called on pbook wakeup --BenH */ +void +__init +openpic_init(int main_pic) { u_int t, i; u_int timerfreq; @@ -227,7 +230,7 @@ /* Initialize IPI interrupts */ for (i = 0; i < OPENPIC_NUM_IPI; i++) { - openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i); + openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i); } if (_machine != _MACH_Pmac) { @@ -264,7 +267,7 @@ openpic_initirq( np->intrs[j].line, pri, np->intrs[j].line, - np->intrs[j].sense, + 0, np->intrs[j].sense); irq_desc[np->intrs[j].line].level = np->intrs[j].sense; } @@ -309,6 +312,10 @@ { openpic_setfield(&OpenPIC->Global.Global_Configuration0, OPENPIC_CONFIG_RESET); + /* Wait for reset to complete */ + while(openpic_readfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET)) + ; } @@ -459,12 +466,12 @@ 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<= NumSources) + return; openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { @@ -509,15 +520,30 @@ OPENPIC_MASK)); } +u_int openpic_get_enable(u_int irq) +{ + if (irq < 0 || irq >= NumSources) + return 0; + return !openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_MASK); +} + void openpic_disable_irq(u_int irq) { - check_arg_irq(irq); + u32 vp; + + /* on SMP, we get IPI vector numbers here, we should handle them + * or at least ignore them. + */ + if (irq < 0 || irq >= NumSources) + return; openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { - mb(); - } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_MASK)); + mb(); /* sync is probably useless here */ + vp = openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_MASK | OPENPIC_ACTIVITY); + } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); } /* @@ -564,3 +590,50 @@ OPENPIC_SENSE_LEVEL, (sense ? OPENPIC_SENSE_LEVEL : 0)); } + +#ifdef CONFIG_PMAC_PBOOK +static u32 save_ipi_vp[OPENPIC_NUM_IPI]; +static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES]; +static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES]; +static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS]; + +__pmac +void +openpic_sleep_save_intrs(void) +{ + int i; + + for (i=0; iGlobal.IPI_Vector_Priority(i)); + for (i=0; iSource[i].Vector_Priority); + save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination); + } + for (i=0; iProcessor[i].Current_Task_Priority); + openpic_set_priority(i, 0xf); + } +} + +__pmac +void +openpic_sleep_restore_intrs(void) +{ + int i; + + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); + openpic_maptimer(i, 0); + } + for (i=0; iGlobal.IPI_Vector_Priority(i), save_ipi_vp[i]); + for (i=0; iSource[i].Vector_Priority, save_irq_src_vp[i]); + openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]); + } + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); + openpic_disable_8259_pass_through(); + for (i=0; iProcessor[i].Current_Task_Priority, save_cpu_task_pri[i]); +} +#endif /* CONFIG_PMAC_PBOOK */ \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.2.17/arch/ppc/kernel/pci.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/pci.c Wed Nov 8 23:00:34 2000 @@ -10,15 +10,20 @@ #include #include #include +#include +#include +#include #include #include #include #include +#include #include #include #include #include +#include #include "pci.h" @@ -105,3 +110,156 @@ } } #endif + + +void * +pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) +{ + if (!ppc_md.pci_dev_io_base) { + /* Please, someone fix this for non-pmac machines, we + * need either the virtual or physical PCI IO base + */ + return 0; + } + return ppc_md.pci_dev_io_base(bus, devfn, physical); +} + +void * +pci_dev_mem_base(unsigned char bus, unsigned char devfn) +{ + /* Default memory base is 0 (1:1 mapping) */ + if (!ppc_md.pci_dev_mem_base) { + /* Please, someone fix this for non-pmac machines.*/ + return 0; + } + return ppc_md.pci_dev_mem_base(bus, devfn); +} + +/* Returns the root-bridge number (Uni-N number) of a device */ +int +pci_dev_root_bridge(unsigned char bus, unsigned char devfn) +{ + /* Defaults to 0 */ + if (!ppc_md.pci_dev_root_bridge) + return 0; + return ppc_md.pci_dev_root_bridge(bus, devfn); +} + +/* + * Those syscalls are derived from the Alpha versions, they + * allow userland apps to retreive the per-device iobase and + * mem-base. They also provide wrapper for userland to do + * config space accesses. + * The "host_number" returns the number of the Uni-N sub bridge + */ + +asmlinkage int +sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + switch (len) { + case 1: + err = pcibios_read_config_byte(bus, dfn, off, &ubyte); + put_user(ubyte, buf); + break; + case 2: + err = pcibios_read_config_word(bus, dfn, off, &ushort); + put_user(ushort, (unsigned short *)buf); + break; + case 4: + err = pcibios_read_config_dword(bus, dfn, off, &uint); + put_user(uint, (unsigned int *)buf); + break; + default: + err = -EINVAL; + break; + } + return err; +} + +asmlinkage int +sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + switch (len) { + case 1: + err = get_user(ubyte, buf); + if (err) + break; + err = pcibios_write_config_byte(bus, dfn, off, ubyte); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 2: + err = get_user(ushort, (unsigned short *)buf); + if (err) + break; + err = pcibios_write_config_word(bus, dfn, off, ushort); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 4: + err = get_user(uint, (unsigned int *)buf); + if (err) + break; + err = pcibios_write_config_dword(bus, dfn, off, uint); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + default: + err = -EINVAL; + break; + } + return err; +} + +/* Provide information on locations of various I/O regions in physical + * memory. Do this on a per-card basis so that we choose the right + * root bridge. + * Note that the returned IO or memory base is a physical address + */ + +asmlinkage long +sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) +{ + long result = -EOPNOTSUPP; + + switch (which) { + case IOBASE_BRIDGE_NUMBER: + return (long)pci_dev_root_bridge(bus, devfn); + case IOBASE_MEMORY: + return (long)pci_dev_mem_base(bus, devfn); + case IOBASE_IO: + result = (long)pci_dev_io_base(bus, devfn, 1); + if (result == 0) + result = -EOPNOTSUPP; + break; + } + + return result; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.2.17/arch/ppc/kernel/pmac_pci.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/pmac_pci.c Wed Nov 8 23:00:34 2000 @@ -32,6 +32,8 @@ struct device_node* node; volatile unsigned int* cfg_addr; volatile unsigned int* cfg_data; + void* iobase; + void* iobase_phys; }; static struct uninorth_data uninorth_bridges[3]; @@ -83,6 +85,81 @@ return 0; } +/* This routines figures out on which root bridge a given PCI device + * is attached. + * + * WARNING: When passed the address of the bridge itself (11), it must + * return the AGP bus. Currently, it returns 0, which is by + * chance the AGP one. We may have to improve that however... + */ +__pmac +int +pmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn) +{ + struct device_node *node, *bridge_node; + int bridge = uninorth_default; + + if (uninorth_count == 0) + return 0; + if (bus == 0 && PCI_SLOT(dev_fn) < 11) + return 0; + + /* We look for the OF device corresponding to this bus/devfn pair. If we + * don't find it, we default to the external PCI */ + bridge_node = NULL; + node = find_pci_device_OFnode(bus, dev_fn & 0xf8); + if (node) { + /* note: we don't stop on the first occurence since we need to go + * up to the root bridge */ + do { + if (node->type && !strcmp(node->type, "pci") + && device_is_compatible(node, "uni-north")) + bridge_node = node; + node=node->parent; + } while (node); + } + if (bridge_node) { + int i; + for (i=0;i max_bus || (bp = bridges[bus]) == 0) + return 0; + return physical ? bp->io_base_phys : bp->io_base; + } + return physical ? uninorth_bridges[bridge].iobase_phys + : uninorth_bridges[bridge].iobase; +} + +__pmac +void * +pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn) +{ + return 0; +} + /* This function only works for bus 0, uni-N uses a different mecanism for * other busses (see below) */ @@ -99,48 +176,20 @@ |1UL) -/* We should really use RTAS here, unfortunately, it's not available with BootX. - * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff - * later, once I have something that works enough with BootX. - */ __pmac static unsigned int uni_north_access_data(unsigned char bus, unsigned char dev_fn, unsigned char offset) { - struct device_node *node, *bridge_node; - int bridge = uninorth_default; + int bridge; unsigned int caddr; - if (bus == 0) { - if (PCI_SLOT(dev_fn) < 11) { - return 0; - } - /* We look for the OF device corresponding to this bus/devfn pair. If we - * don't find it, we default to the external PCI */ - bridge_node = NULL; - node = find_pci_device_OFnode(bus, dev_fn & 0xf8); - if (node) { - /* note: we don't stop on the first occurence since we need to go - * up to the root bridge */ - do { - if (!strcmp(node->type, "pci")) - bridge_node = node; - node=node->parent; - } while (node); - } - if (bridge_node) { - int i; - for (i=0;icfg_data, val); } +static int __init +fixup_one_level_bus_range(struct device_node *node, int higher) +{ + for (; node != 0;node = node->sibling) { + int * bus_range; + unsigned int *class_code; + int len; + + /* For PCI<->PCI bridges or CardBus bridges, we go down */ + class_code = (unsigned int *) get_property(node, "class-code", 0); + if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && + (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) + continue; + bus_range = (int *) get_property(node, "bus-range", &len); + if (bus_range != NULL && len > 2 * sizeof(int)) { + if (bus_range[1] > higher) + higher = bus_range[1]; + } + higher = fixup_one_level_bus_range(node->child, higher); + } + return higher; +} + +/* This routine fixes the "bus-range" property of all bridges in the + * system since they tend to have their "last" member wrong on macs + * + * Note that the bus numbers manipulated here are OF bus numbers, they + * are not Linux bus numbers. + */ +static void __init +fixup_bus_range(struct device_node *bridge) +{ + int * bus_range; + int len; + + /* Lookup the "bus-range" property for the hose */ + bus_range = (int *) get_property(bridge, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s\n", + bridge->full_name); + return; + } + bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); +} __initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)) { @@ -596,6 +689,7 @@ dev->full_name); continue; } + fixup_bus_range(dev); bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s\n", @@ -613,6 +707,9 @@ uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000); uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000); uninorth_bridges[i].node = dev; + uninorth_bridges[i].iobase_phys = (void *)addr->address; + /* is 0x10000 enough for io space ? */ + uninorth_bridges[i].iobase = (void *)ioremap(addr->address, 0x10000); /* XXX This is the bridge with the PCI expansion bus. This is also the * address of the bus that will receive type 1 config accesses and io * accesses. Appears to be correct for iMac DV and G4 Sawtooth too. @@ -630,8 +727,8 @@ if (device_is_compatible(dev, "uni-north")) { bp->cfg_addr = 0; bp->cfg_data = 0; - /* is 0x10000 enough for io space ? */ - bp->io_base = (void *)ioremap(addr->address, 0x10000); + bp->io_base = uninorth_bridges[uninorth_count-1].iobase; + bp->io_base_phys = uninorth_bridges[uninorth_count-1].iobase_phys; } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ bp->cfg_addr = (volatile unsigned int *) @@ -639,6 +736,7 @@ bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); bp->io_base = (void *) ioremap(0xfe000000, 0x20000); + bp->io_base_phys = (void *)0xfe000000; if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(bp, 1); #if 0 /* Disabled for now, HW problems ??? */ @@ -651,6 +749,7 @@ bp->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); bp->io_base = (void *) ioremap(addr->address, 0x10000); + bp->io_base_phys = (void *)addr->address; } if (isa_io_base == 0) isa_io_base = (unsigned long) bp->io_base; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.2.17/arch/ppc/kernel/pmac_pic.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/pmac_pic.c Wed Nov 8 23:00:34 2000 @@ -10,6 +10,7 @@ #include #include #include "pmac_pic.h" +#include "open_pic.h" struct pmac_irq_hw { unsigned int flag; @@ -28,7 +29,8 @@ static int max_irqs; static int max_real_irqs; -static int has_openpic = 0; + +extern u_int openpic_read(volatile u_int *addr); #define MAXCOUNT 10000000 @@ -106,18 +108,6 @@ pmac_set_irq_mask(irq_nr); } -static void pmac_openpic_mask_irq(unsigned int irq_nr) -{ - openpic_disable_irq(irq_nr); -} - -static void pmac_openpic_unmask_irq(unsigned int irq_nr) -{ - openpic_enable_irq(irq_nr); -} - - - struct hw_interrupt_type pmac_pic = { " PMAC-PIC ", NULL, @@ -140,17 +130,6 @@ 0 }; -struct hw_interrupt_type pmac_open_pic = { - " OpenPIC ", - NULL, - NULL, - NULL, - pmac_openpic_unmask_irq, - pmac_openpic_mask_irq, - NULL,/*pmac_openpic_mask_irq,*/ - 0 -}; - static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) { int irq, bits; @@ -179,6 +158,8 @@ int cpu, int isfake) { + extern void psurge_smp_message_recv(void); + int irq; unsigned long bits = 0; @@ -193,7 +174,7 @@ if (xmon_2nd) xmon(regs); #endif - pmac_smp_message_recv(); + psurge_smp_message_recv(); goto out; } /* could be here due to a do_fake_interrupt call but we don't @@ -221,29 +202,6 @@ } #endif /* __SMP__ */ - /* Yeah, I know, this could be a separate do_IRQ function */ - if (has_openpic) { - irq = openpic_irq(0); - if (irq == OPENPIC_VEC_SPURIOUS) { - /* Spurious interrupts should never be ack'ed */ - ppc_spurious_interrupts++; - } else { - /* Can this happen ? (comes from CHRP code) */ - if (irq < 0) { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - } else { - if (!irq_desc[irq].level) - openpic_eoi(0); - ppc_irq_dispatch_handler( regs, irq ); - if (irq_desc[irq].level) - openpic_eoi(0); - } - } - return; - } - for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { int i = irq >> 5; bits = ld_le32(&pmac_irq_hw[i]->flag) @@ -398,6 +356,8 @@ struct device_node *irqctrler; volatile struct pmac_irq_hw *addr; int second_irq; + u_int t; + int nr_irq; /* We first try to detect Apple's new Core99 chipset, since mac-io * is quite different on those machines and contains an IBM MPIC2. @@ -412,18 +372,38 @@ OpenPIC = (volatile struct OpenPIC *) ioremap(irqctrler->addrs[0].address, irqctrler->addrs[0].size); - for ( i = 0 ; i < NR_IRQS ; i++ ) { - irq_desc[i].ctl = &pmac_open_pic; + /* from openpic.c code... --Troy + * dynamically figure out how many interrupts + * We should really do something like panic + * if nr_irq >= OPENPIC_VEC_IPI + */ + t = openpic_read(&OpenPIC->Global.Feature_Reporting0); + nr_irq = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> + OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; + + for ( i = 0 ; i < nr_irq ; i++ ) { + irq_desc[i].ctl = &open_pic; irq_desc[i].level = 0; } + ppc_md.do_IRQ = open_pic_do_IRQ; + open_pic.irq_offset = 0; openpic_init(1); - has_openpic = 1; #ifdef CONFIG_XMON pswitch = find_devices("programmer-switch"); if (pswitch && pswitch->n_intrs) request_irq(pswitch->intrs[0].line, xmon_irq, 0, "NMI - XMON", 0); #endif /* CONFIG_XMON */ +#ifdef __SMP__ + 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__ */ return; } irqctrler = NULL; @@ -507,17 +487,20 @@ * sleep_save_intrs() saves the states of all interrupt enables * and disables all interupts except for the nominated one. * sleep_restore_intrs() restores the states of all interrupt enables. + * + * TODO: Those should be sleep notifiers with high priority. */ unsigned int sleep_save_mask[2]; void -sleep_save_intrs(int viaint) +pmac_sleep_save_intrs(int viaint) { sleep_save_mask[0] = ppc_cached_irq_mask[0]; sleep_save_mask[1] = ppc_cached_irq_mask[1]; ppc_cached_irq_mask[0] = 0; ppc_cached_irq_mask[1] = 0; - set_bit(viaint, ppc_cached_irq_mask); + if (viaint > 0) + set_bit(viaint, ppc_cached_irq_mask); out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); if (max_real_irqs > 32) out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); @@ -526,9 +509,10 @@ } void -sleep_restore_intrs(void) +pmac_sleep_restore_intrs(void) { int i; + out_le32(&pmac_irq_hw[0]->enable, 0); if (max_real_irqs > 32) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.2.17/arch/ppc/kernel/pmac_setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/pmac_setup.c Wed Nov 8 23:00:34 2000 @@ -57,19 +57,20 @@ #include #include #include - +#include #include + #include "local_irq.h" #include "pmac_pic.h" #undef SHOW_GATWICK_IRQS -void pmac_time_init(void); -unsigned long pmac_get_rtc_time(void); -int pmac_set_rtc_time(unsigned long nowtime); -void pmac_read_rtc_time(void); -void pmac_calibrate_decr(void); -void pmac_setup_pci_ptrs(void); +extern long pmac_time_init(void); +extern unsigned long pmac_get_rtc_time(void); +extern int pmac_set_rtc_time(unsigned long nowtime); +extern void pmac_read_rtc_time(void); +extern void pmac_calibrate_decr(void); +extern void pmac_setup_pci_ptrs(void); extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); @@ -79,22 +80,29 @@ extern void mackbd_leds(unsigned char leds); extern void mackbd_init_hw(void); #ifdef CONFIG_MAGIC_SYSRQ -unsigned char mackbd_sysrq_xlate[128]; +extern unsigned char mackbd_sysrq_xlate[128]; +extern unsigned char mac_hid_kbd_sysrq_xlate[128]; +extern unsigned char pckbd_sysrq_xlate[128]; #endif /* CONFIG_MAGIC_SYSRQ */ -extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); +extern int keyboard_sends_linux_keycodes; +extern int mac_hid_kbd_translate(unsigned char scancode, + unsigned char *keycode, char raw_mode); +extern char mac_hid_kbd_unexpected_up(unsigned char keycode); +extern void mac_hid_init_hw(void); + extern void pmac_nvram_update(void); +extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn); +extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn); +extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn); + unsigned char drive_info; int ppc_override_l2cr = 0; int ppc_override_l2cr_value; +static int current_root_goodness = -1; + extern char saved_command_line[]; extern int pmac_newworld; @@ -104,7 +112,26 @@ extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); static void init_p2pbridge(void); -static void init_uninorth(void); + +#ifdef CONFIG_SMP +volatile static long int core99_l2_cache; +void core99_init_l2(void) +{ + int cpu = smp_processor_id(); + + if ( (_get_PVR() >> 16) != 8 && (_get_PVR() >> 16) != 12 ) + return; + + if (cpu == 0){ + core99_l2_cache = _get_L2CR(); + printk("CPU0: L2CR is %lx\n", core99_l2_cache); + } else { + printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); + _set_L2CR(core99_l2_cache); + printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); + } +} +#endif /* CONFIG_SMP */ __pmac int @@ -247,7 +274,7 @@ struct device_node *cpu; int *fp; - /* Set loops_per_sec to a half-way reasonable value, + /* Set loops_per_jiffy to a half-way reasonable value, for use until calibrate_delay gets called. */ cpu = find_type_devices("cpu"); if (cpu != 0) { @@ -260,13 +287,13 @@ case 10: /* mach V (604ev5) */ case 12: /* G4 */ case 20: /* 620 */ - loops_per_sec = *fp; + loops_per_jiffy = *fp / HZ; break; default: /* 601, 603, etc. */ - loops_per_sec = *fp / 2; + loops_per_jiffy = *fp / (2*HZ); } } else - loops_per_sec = 50000000; + loops_per_jiffy = 50000000 / HZ; } /* this area has the CPU identification register @@ -277,9 +304,10 @@ *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); init_p2pbridge(); - init_uninorth(); - /* Checks "l2cr-value" property in the registry */ + /* Checks "l2cr-value" property in the registry + * And enable G3/G4 Dynamic Power Management + */ if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) { struct device_node *np = find_devices("cpus"); if (np == 0) @@ -291,9 +319,11 @@ ppc_override_l2cr = 1; ppc_override_l2cr_value = *l2cr; _set_L2CR(0); - _set_L2CR(ppc_override_l2cr_value); + if (ppc_override_l2cr_value) + _set_L2CR(ppc_override_l2cr_value); } } + _set_HID0(_get_HID0() | HID0_DPM); } if (ppc_override_l2cr) @@ -302,6 +332,10 @@ ? "enabled" : "disabled"); feature_init(); +#ifdef CONFIG_SMP + core99_init_l2(); +#endif + #ifdef CONFIG_KGDB zs_kgdb_hook(0); #endif @@ -368,38 +402,6 @@ } } -__initfunc(static void init_uninorth(void)) -{ - /* - * Turns OFF the gmac clock. The gmac driver will turn - * it back ON when the interface is enabled. This save - * power on portables. - * - * Note: We could also try to turn OFF the PHY. Since this - * has to be done by both the gmac driver and this code, - * I'll probably end-up moving some of this out of the - * modular gmac driver into a non-modular stub containing - * some basic PHY management and power management stuffs - */ - struct device_node* uni_n = find_devices("uni-n"); - struct device_node* gmac = find_devices("ethernet"); - unsigned long* addr; - - if (!uni_n || uni_n->n_addrs < 1) - return; - addr = ioremap(uni_n->addrs[0].address, 0x300); - - while(gmac) { - if (device_is_compatible(gmac, "gmac")) - break; - gmac = gmac->next; - } - if (gmac) { - *(addr + 8) &= ~0x00000002UL; - eieio(); - } -} - extern char *bootpath; extern char *bootdevice; void *boot_host; @@ -481,13 +483,14 @@ /* can't be initfunc - can be called whenever a disk is first accessed */ __pmac -void note_bootable_part(kdev_t dev, int part) +void note_bootable_part(kdev_t dev, int part, int goodness) { static int found_boot = 0; char *p; /* Do nothing if the root has been set already. */ - if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)) + if ((goodness < current_root_goodness) && + (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))) return; p = strstr(saved_command_line, "root="); if (p != NULL && (p == saved_command_line || p[-1] == ' ')) @@ -500,7 +503,7 @@ if (boot_dev == 0 || dev == boot_dev) { ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part); boot_dev = NODEV; - printk(" (root on %d)", part); + current_root_goodness = goodness; } } @@ -655,7 +658,8 @@ ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; -#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD) +#ifdef CONFIG_VT +#ifdef CONFIG_MAC_KEYBOARD ppc_md.kbd_setkeycode = mackbd_setkeycode; ppc_md.kbd_getkeycode = mackbd_getkeycode; ppc_md.kbd_translate = mackbd_translate; @@ -663,10 +667,30 @@ ppc_md.kbd_leds = mackbd_leds; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x69; + ppc_md.sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; #endif +#elif defined(CONFIG_INPUT_ADBHID) + ppc_md.kbd_setkeycode = 0; + ppc_md.kbd_getkeycode = 0; + ppc_md.kbd_translate = mac_hid_kbd_translate; + ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up; + ppc_md.kbd_leds = 0; + ppc_md.kbd_init_hw = mac_hid_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + ppc_md.sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; + } else +#endif /* CONFIG_MAC_ADBKEYCODES */ + { + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; + } #endif +#endif /* CONFIG_MAC_KEYBOARD */ +#endif /* CONFIG_VT */ #if defined(CONFIG_BLK_DEV_IDE_PMAC) ppc_ide_md.insw = pmac_ide_insw; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c --- v2.2.17/arch/ppc/kernel/pmac_support.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/pmac_support.c Wed Nov 8 23:00:34 2000 @@ -24,6 +24,7 @@ #include #include #include +#include #undef DEBUG @@ -66,6 +67,12 @@ static int core99_bank = 0; static int nvram_partitions[3]; +static struct backlight_controller *backlighter = NULL; +static void* backlighter_data = NULL; +static int backlight_autosave = 0; +static int backlight_level = BACKLIGHT_MAX; +static int backlight_enabled = 1; + /* FIXME: kmalloc fails to allocate the image now that I had to move it * before time_init(). For now, I allocate a static buffer here * but it's a waste of space on all but core99 machines @@ -73,12 +80,12 @@ #if 0 static char* nvram_image; #else -__pmac static char nvram_image[NVRAM_SIZE]; +static char nvram_image[NVRAM_SIZE]; #endif extern int pmac_newworld; -static u8 +static u8 __pmac chrp_checksum(struct chrp_header* hdr) { u8 *ptr; @@ -90,7 +97,7 @@ return sum; } -static u32 +static u32 __pmac core99_calc_adler(u8 *buffer) { int cnt; @@ -113,7 +120,7 @@ return (high << 16) | low; } -static u32 +static u32 __pmac core99_check(u8* datas) { struct core99_header* hdr99 = (struct core99_header*)datas; @@ -139,7 +146,7 @@ return hdr99->generation; } -static int +static int __pmac core99_erase_bank(int bank) { int stat, i; @@ -163,7 +170,7 @@ return 0; } -static int +static int __pmac core99_write_bank(int bank, u8* datas) { int i, stat = 0; @@ -191,7 +198,7 @@ return 0; } -static void +static void __pmac lookup_partitions(void) { u8 buffer[17]; @@ -281,7 +288,8 @@ } 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 && adb_controller->kind == ADB_VIAPMU) { + } else if (nvram_naddrs == 0 && adb_controller && + adb_controller->kind == ADB_VIAPMU) { nvram_naddrs = -1; } else { printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", @@ -290,7 +298,7 @@ lookup_partitions(); } -void +void __pmac pmac_nvram_update(void) { struct core99_header* hdr99; @@ -317,7 +325,7 @@ printk("nvram: Error writing bank %d\n", core99_bank); } -unsigned char +unsigned char __pmac nvram_read_byte(int addr) { struct adb_request req; @@ -342,7 +350,7 @@ return 0; } -void +void __pmac nvram_write_byte(unsigned char val, int addr) { struct adb_request req; @@ -373,13 +381,13 @@ eieio(); } -int +int __pmac pmac_get_partition(int partition) { return nvram_partitions[partition]; } -u8 +u8 __pmac pmac_xpram_read(int xpaddr) { int offset = nvram_partitions[pmac_nvram_XPRAM]; @@ -390,7 +398,7 @@ return nvram_read_byte(xpaddr + offset); } -void +void __pmac pmac_xpram_write(int xpaddr, u8 data) { int offset = nvram_partitions[pmac_nvram_XPRAM]; @@ -399,5 +407,120 @@ return; nvram_write_byte(xpaddr + offset, data); +} + +void __pmac +register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type) +{ + struct device_node* bk_node; + char *prop; + int valid = 0; + + bk_node = find_devices("backlight"); + + /* Special case for the old PowerBooks, they don't yet have + * the property we expect + */ + backlight_autosave = machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500"); + if ((backlight_autosave + || machine_is_compatible("AAPL,PowerBook1998") + || machine_is_compatible("PowerBook1,1")) + && !strcmp(type, "pmu")) + valid = 1; + else if (bk_node) { + prop = get_property(bk_node, "backlight-control", NULL); + if (prop && !strncmp(prop, type, strlen(type))) + valid = 1; + } + if (!valid) + return; + backlighter = ctrler; + backlighter_data = data; + + if (bk_node && !backlight_autosave) + prop = get_property(bk_node, "bklt", NULL); + else + prop = NULL; + if (prop) { + backlight_level = ((*prop)+1) >> 1; + if (backlight_level > BACKLIGHT_MAX) + backlight_level = BACKLIGHT_MAX; + } + + if (backlight_autosave) { + struct adb_request req; + pmu_request(&req, NULL, 2, 0xd9, 0); + while (!req.complete) + pmu_poll(); + backlight_level = req.reply[1] >> 4; + } + + if (!backlighter->set_enable(1, backlight_level, data)) + backlight_enabled = 1; + + printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n", + type, backlight_level); +} + +void __pmac +unregister_backlight_controller(struct backlight_controller *ctrler, void *data) +{ + /* We keep the current backlight level (for now) */ + if (ctrler == backlighter && data == backlighter_data) + backlighter = NULL; +} + +int __pmac +set_backlight_enable(int enable) +{ + int rc; + + if (!backlighter) + return -ENODEV; + rc = backlighter->set_enable(enable, backlight_level, backlighter_data); + if (!rc) + backlight_enabled = enable; + return rc; +} + +int __pmac +get_backlight_enable(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_enabled; +} + +int __pmac +set_backlight_level(int level) +{ + int rc = 0; + + if (!backlighter) + return -ENODEV; + if (level < BACKLIGHT_MIN) + level = BACKLIGHT_OFF; + if (level > BACKLIGHT_MAX) + level = BACKLIGHT_MAX; + if (backlight_enabled) + rc = backlighter->set_level(level, backlighter_data); + if (!rc) + backlight_level = level; + if (!rc && !backlight_autosave) { + level <<=1; + if (level & 0x10) + level |= 0x01; + // -- todo: save to property "bklt" + } + return rc; +} + +int __pmac +get_backlight_level(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_level; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.2.17/arch/ppc/kernel/pmac_time.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/pmac_time.c Wed Nov 8 23:00:34 2000 @@ -53,7 +53,7 @@ extern struct timezone sys_tz; __init -void pmac_time_init(void) +long pmac_time_init(void) { s32 delta = 0; int dst; @@ -66,16 +66,13 @@ dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, dst ? "on" : "off"); - sys_tz.tz_minuteswest = -delta/60; - /* I _suppose_ this is 0:off, 1:on */ - sys_tz.tz_dsttime = dst; + return -delta; } __pmac unsigned long pmac_get_rtc_time(void) { struct adb_request req; - int offset = sys_tz.tz_minuteswest * 60; /* Get the time from the RTC */ if (adb_controller == 0) @@ -92,7 +89,7 @@ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); return (req.reply[3] << 24) + (req.reply[4] << 16) - + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET + offset; + + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; case ADB_VIAPMU: if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) { printk("pmac_read_rtc_time: pmu_request failed\n"); @@ -104,7 +101,7 @@ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); return (req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET + offset; + + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET; default: return 0; } @@ -115,7 +112,7 @@ struct adb_request req; int dst, delta; - nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60; + nowtime += RTC_OFFSET; /* Set the time in the RTC */ if (adb_controller == 0) @@ -146,15 +143,6 @@ default: return 0; } - - /* write the timezone offset back into the xpram */ - delta = sys_tz.tz_minuteswest * -60; - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0x9, delta >> 16); - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xa, delta >> 8); - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xb, delta); - dst = pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 8); - dst = sys_tz.tz_dsttime? (dst | 0x80): (dst & ~0x80); - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 8, dst); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.2.17/arch/ppc/kernel/ppc_htab.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/ppc_htab.c Wed Nov 8 23:00:34 2000 @@ -587,9 +587,8 @@ buffer += len; left -= len; _set_L2CR(0); - _set_L2CR(val); - while ( _get_L2CR() & 0x1 ) - /* wait for invalidate to finish */; + if (val) + _set_L2CR(val); } else { p = buf; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.2.17/arch/ppc/kernel/ppc_ksyms.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/ppc_ksyms.c Wed Nov 8 23:00:34 2000 @@ -81,8 +81,10 @@ EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); +#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); +#endif EXPORT_SYMBOL(atomic_add); EXPORT_SYMBOL(atomic_sub); @@ -188,23 +190,13 @@ EXPORT_SYMBOL(_read_unlock); EXPORT_SYMBOL(_write_lock); EXPORT_SYMBOL(_write_unlock); -#endif +#endif /* __SMP__ */ EXPORT_SYMBOL(_machine); EXPORT_SYMBOL(ppc_md); - -EXPORT_SYMBOL(adb_request); -EXPORT_SYMBOL(adb_register); -EXPORT_SYMBOL(cuda_request); -EXPORT_SYMBOL(cuda_poll); -EXPORT_SYMBOL(pmu_request); -EXPORT_SYMBOL(pmu_poll); -#ifdef CONFIG_PMAC_PBOOK -EXPORT_SYMBOL(pmu_register_sleep_notifier); -EXPORT_SYMBOL(pmu_unregister_sleep_notifier); -EXPORT_SYMBOL(pmu_enable_irled); -#endif CONFIG_PMAC_PBOOK EXPORT_SYMBOL(abort); + +#ifndef CONFIG_MBX EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -215,25 +207,43 @@ EXPORT_SYMBOL(find_pci_device_OFnode); EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(get_property); +#endif /* CONFIG_MBX */ +#ifdef CONFIG_POWERMAC +EXPORT_SYMBOL(adb_request); +EXPORT_SYMBOL(adb_register); +EXPORT_SYMBOL(cuda_request); +EXPORT_SYMBOL(cuda_poll); +EXPORT_SYMBOL(pmu_request); +EXPORT_SYMBOL(pmu_poll); +#endif /* CONFIG_POWERMAC */ +#ifdef CONFIG_PMAC_PBOOK +EXPORT_SYMBOL(pmu_register_sleep_notifier); +EXPORT_SYMBOL(pmu_unregister_sleep_notifier); +EXPORT_SYMBOL(pmu_enable_irled); +#endif /* CONFIG_PMAC_PBOOK */ +#ifdef CONFIG_POWERMAC EXPORT_SYMBOL(pci_io_base); +EXPORT_SYMBOL(pci_dev_io_base); +EXPORT_SYMBOL(pci_dev_mem_base); EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(feature_set); EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); -#ifdef CONFIG_SCSI -EXPORT_SYMBOL(note_scsi_host); -#endif -EXPORT_SYMBOL(kd_mksound); -/*#ifdef CONFIG_PMAC */ +EXPORT_SYMBOL(feature_set_gmac_power); +EXPORT_SYMBOL(feature_set_gmac_phy_reset); +EXPORT_SYMBOL(feature_set_usb_power); +EXPORT_SYMBOL(feature_set_firewire_power); EXPORT_SYMBOL(nvram_read_byte); EXPORT_SYMBOL(nvram_write_byte); EXPORT_SYMBOL(pmac_xpram_read); EXPORT_SYMBOL(pmac_xpram_write); -/*#endif*/ /* CONFIG_PMAC */ -#ifdef CONFIG_PPC_RTC +#ifdef CONFIG_SCSI +EXPORT_SYMBOL(note_scsi_host); +#endif /* CONFIG_SCSI */ +#endif /* CONFIG_POWERMAC */ +EXPORT_SYMBOL(kd_mksound); EXPORT_SYMBOL(mktime); EXPORT_SYMBOL(to_tm); -#endif EXPORT_SYMBOL(abs); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.2.17/arch/ppc/kernel/prep_pci.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/prep_pci.c Wed Nov 8 23:00:34 2000 @@ -25,6 +25,7 @@ #include #include "pci.h" +#include "open_pic.h" #define MAX_DEVNR 22 @@ -42,8 +43,6 @@ /* Used for Motorola to store system config register */ static unsigned long *ProcInfo; -extern void chrp_do_IRQ(struct pt_regs *,int , int); - /* Tables for known hardware */ /* Motorola PowerStackII - Utah */ @@ -784,7 +783,7 @@ OpenPIC_InitSenses = mvme2600_openpic_initsenses; OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses); - ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.do_IRQ = open_pic_do_IRQ; /* If raven is present on Motorola store the system config register * for later use. @@ -1131,7 +1130,7 @@ if (n & 0xF0) { return (n & 0x0F); } else { - return(openpic_to_irq(n)); + return(n+open_pic.irq_offset); } } @@ -1168,6 +1167,17 @@ short_reg = 0x0000; pcibios_write_config_word(dev->bus->number, dev->devfn, 0x44, short_reg); + } + } + if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, dev))){ + if (OpenPIC){ + /* Disable LEGIRQ mode so PCI INTs are routed to + the 8259 */ + pci_write_config_dword(dev, 0x40, 0x10ff00a1); + } else { + /* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */ + pci_write_config_dword(dev, 0x40, 0x10ff08a1); } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.2.17/arch/ppc/kernel/prep_setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/prep_setup.c Wed Nov 8 23:00:34 2000 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -46,9 +47,10 @@ #include #include #include - - +#include #include +#include + #include "local_irq.h" #include "i8259.h" #include "open_pic.h" @@ -100,16 +102,12 @@ extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern int probingmem; -extern unsigned long loops_per_sec; #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ extern int rd_image_start; /* starting block # of image */ #endif -#ifdef CONFIG_VGA_CONSOLE -unsigned long vgacon_remap_base; -#endif __prep int @@ -218,7 +216,7 @@ unsigned char ucEquipPres1; /* init to some ~sane value until calibrate_delay() runs */ - loops_per_sec = 50000000; + loops_per_jiffy = 50000000/HZ; /* Set up floppy in PS/2 mode */ outb(0x09, SIO_CONFIG_RA); @@ -617,8 +615,14 @@ irq_desc[i].ctl = &i8259_pic; i8259_init(); #ifdef __SMP__ - request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action, + 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__ */ } @@ -857,8 +861,8 @@ 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; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.2.17/arch/ppc/kernel/process.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/process.c Wed Nov 8 23:00:34 2000 @@ -233,7 +233,7 @@ printk("["); for (; bits->bit != 0; ++bits) { if (val & bits->bit) { - printk("%s", bits->name); + printk("%s%s", sep, bits->name); sep = ", "; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.2.17/arch/ppc/kernel/prom.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/prom.c Wed Nov 8 23:00:34 2000 @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,6 +29,10 @@ #include #include #include +#include +#include +#include +#include /* * Properties whose value is longer than this get excluded from our @@ -109,6 +115,12 @@ #ifdef CONFIG_BOOTX_TEXT +/* + * The VGA font is in the _pmac section. Can't this cause problems with CHRP + * using some of the prom_xxxx functions ? + * All this need to be moved in a separate source file anyway + */ + static void clearscreen(void); static void flushscreen(void); @@ -116,6 +128,9 @@ void drawstring(const char *c); void drawhex(unsigned long v); static void scrollscreen(void); +static void prepare_disp_BAT(void); +static void boot_console_write(struct console *co, const char *s, + unsigned count); static void draw_byte(unsigned char c, long locX, long locY); static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb); @@ -128,10 +143,28 @@ static long g_max_loc_X = 0; static long g_max_loc_Y = 0; +unsigned long disp_BATL = 0; +unsigned long disp_BATU = 0; + #define cmapsz (16*256) static unsigned char vga_font[cmapsz]; +static struct console boot_cons = { + "boot", + boot_console_write, + NULL, + NULL, + NULL, + NULL, + NULL, + CON_PRINTBUFFER, + 0, + 0, + NULL +}; +static int boot_cons_registered = 0; + #endif /* CONFIG_BOOTX_TEXT */ @@ -243,7 +276,7 @@ return prom_args.args[nargs]; } -__init +/*__init*/ void prom_print(const char *msg) { @@ -399,6 +432,7 @@ } #ifdef CONFIG_BOOTX_TEXT + prepare_disp_BAT(); prom_print(RELOC("booting...\n")); flushscreen(); #endif @@ -573,7 +607,11 @@ * is in its holding pattern code. * * -- Cort + * + * This code crashes on some pmacs since the memory at 8M is not + * claim'ed and so can be unmapped. -- BenH */ + if (chrp) { extern void __secondary_hold(void); unsigned long i; @@ -599,7 +637,7 @@ } /* look for cpus */ - for (node = 0; prom_next_node(&node);) + for (node = 0; chrp && prom_next_node(&node);) { type[0] = 0; call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), @@ -642,6 +680,7 @@ if (!chrp && RELOC(disp_bi)) { RELOC(prom_stdout) = 0; clearscreen(); + prepare_disp_BAT(); prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); } #endif @@ -692,9 +731,50 @@ drawhex(val); drawstring("\n"); } + +/* Calc BAT values for mapping the display and store them + * in disp_BATH and disp_BATL. Those values are then used + * from head.S to map the display during identify_machine() + * and MMU_Init() + * + * For now, the display is mapped in place (1:1). This should + * be changed if the display physical address overlaps + * KERNELBASE, which is fortunately not the case on any machine + * I know of. This mapping is temporary and will disappear as + * soon as the setup done by MMU_Init() is applied + * + * For now, we align the BAT and then map 8Mb on 601 and 16Mb + * on other PPCs. This may cause trouble if the framebuffer + * is really badly aligned, but I didn't encounter this case + * yet. + */ +__init +static void +prepare_disp_BAT(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + unsigned long addr = (unsigned long)bi->dispDeviceBase; + + if ((_get_PVR() >> 16) != 1) { + /* 603, 604, G3, G4, ... */ + addr &= 0xFF000000UL; + RELOC(disp_BATU) = addr | (BL_16M<<2) | 2; + RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + } else { + /* 601 */ + addr &= 0xFF800000UL; + RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + RELOC(disp_BATL) = addr | BL_8M | 0x40; + } + bi->logicalDisplayBase = bi->dispDeviceBase; +} + #endif -static int prom_set_color(ihandle ih, int i, int r, int g, int b) +__init +static int +prom_set_color(ihandle ih, int i, int r, int g, int b) { struct prom_args prom_args; unsigned long offset = reloc_offset(); @@ -729,7 +809,7 @@ ihandle ih; int i; unsigned long offset = reloc_offset(); - char type[16], *path; + char type[16], *path, name[32]; static unsigned char default_colors[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, @@ -757,6 +837,12 @@ type, sizeof(type)); if (strcmp(type, RELOC("display")) != 0) continue; + name[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"), + name, sizeof(name)); + if (!strcmp(name, RELOC("offscreen-display"))) + continue; + /* It seems OF doesn't null-terminate the path :-( */ path = (char *) mem; memset(path, 0, 256); @@ -1189,7 +1275,7 @@ ((node->name && !strcmp(node->name, "open-pic")) || !node->name)) { for (i = 0; i < np->n_intrs; ++i) - np->intrs[i].line = openpic_to_irq(np->intrs[i].line); + np->intrs[i].line = np->intrs[i].line + NUM_8259_INTERRUPTS; } return mem_start; } @@ -1492,7 +1578,7 @@ /* CHRP machines */ np->n_intrs = l / (2 * sizeof(int)); for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = openpic_to_irq(*ip++); + np->intrs[i].line = (*ip++) + NUM_8259_INTERRUPTS; np->intrs[i].sense = *ip++; } } @@ -1637,9 +1723,17 @@ int l; for (np = allnodes; np != 0; np = np->allnext) { - char *pname = np->parent ? - (char *)get_property(np->parent, "name", &l) : 0; - if (pname && strcmp(pname, "mac-io") == 0) + int in_macio = 0; + struct device_node* parent = np->parent; + while(parent) { + char *pname = (char *)get_property(parent, "name", &l); + if (pname && strcmp(pname, "mac-io") == 0) { + in_macio = 1; + break; + } + parent = parent->parent; + } + if (in_macio) continue; reg = (unsigned int *) get_property(np, "reg", &l); if (reg == 0 || l < sizeof(struct reg_property)) @@ -1757,7 +1851,7 @@ struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) - if (strcmp(pp->name, name) == 0) { + if (pp->name && strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; return pp->value; @@ -1901,11 +1995,30 @@ void map_bootx_text(void) { + unsigned long base, offset, size; if (disp_bi == 0) return; - disp_bi->logicalDisplayBase = - ioremap((unsigned long) disp_bi->dispDeviceBase, - disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]); + base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL; + offset = ((unsigned long) disp_bi->dispDeviceBase) - base; + size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset + + disp_bi->dispDeviceRect[0]; + disp_bi->logicalDisplayBase = ioremap(base, size) + offset; +} + +__init +void +install_boot_console(void) +{ + register_console(&boot_cons); + boot_cons_registered = 1; +} + +void +remove_boot_console(void) +{ + if (boot_cons_registered) + unregister_console(&boot_cons); + boot_cons_registered = 0; } /* Calc the base address of a given point (x,y) */ @@ -1981,7 +2094,11 @@ unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; int i,j; - + +#ifdef CONFIG_POWERMAC + pmu_suspend(); +#endif + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) { unsigned long *src_ptr = src; @@ -1998,6 +2115,10 @@ *(dst_ptr++) = 0; dst += (bi->dispDeviceRowBytes >> 2); } + +#ifdef CONFIG_POWERMAC + pmu_resume(); +#endif } __pmac @@ -2041,6 +2162,16 @@ while (*c) drawchar(*c++); } + +#ifdef CONFIG_BOOTX_TEXT +__pmac +static void boot_console_write(struct console *co, const char *s, + unsigned count) +{ + while(count--) + drawchar(*s++); +} +#endif __pmac void diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.2.17/arch/ppc/kernel/setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/setup.c Wed Nov 8 23:00:34 2000 @@ -31,6 +31,7 @@ #endif #include #include +#include extern void pmac_init(unsigned long r3, unsigned long r4, @@ -68,9 +69,6 @@ unsigned long r6, unsigned long r7); -#ifdef CONFIG_BOOTX_TEXT -extern void map_bootx_text(void); -#endif #ifdef CONFIG_XMON extern void xmon_map_scc(void); #endif @@ -98,6 +96,12 @@ struct machdep_calls ppc_md; +#ifdef CONFIG_MAGIC_SYSRQ +unsigned long SYSRQ_KEY; +#endif /* CONFIG_MAGIC_SYSRQ */ +#ifdef CONFIG_VGA_CONSOLE +unsigned long vgacon_remap_base; +#endif /* copy of the residual data */ #ifndef CONFIG_MBX @@ -313,19 +317,11 @@ (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff); len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n", - (CD(loops_per_sec)+2500)/500000, - (CD(loops_per_sec)+2500)/5000 % 100); - bogosum += CD(loops_per_sec); + (CD(loops_per_jiffy)+2500)/(500000/HZ), + (CD(loops_per_jiffy)+2500)/(5000/HZ) % 100); + bogosum += CD(loops_per_jiffy); } -#ifdef __SMP__ - if ( i ) - len += sprintf(buffer+len, "\n"); - len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n", - (bogosum+2500)/500000, - (bogosum+2500)/5000 % 100); -#endif /* __SMP__ */ - /* * Ooh's and aah's info about zero'd pages in idle task */ @@ -490,15 +486,21 @@ switch (_machine) { +#ifdef CONFIG_POWERMAC case _MACH_Pmac: pmac_init(r3, r4, r5, r6, r7); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP) case _MACH_prep: prep_init(r3, r4, r5, r6, r7); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP) case _MACH_chrp: chrp_init(r3, r4, r5, r6, r7); break; +#endif #ifdef CONFIG_APUS case _MACH_apus: apus_init(r3, r4, r5, r6, r7); @@ -557,7 +559,8 @@ unsigned long val = simple_strtoul(str, NULL, 0); printk(KERN_INFO "l2cr set to %lx\n", val); _set_L2CR(0); - _set_L2CR(val); + if (val) + _set_L2CR(val); } } @@ -578,9 +581,6 @@ extern unsigned long find_available_memory(void); extern unsigned long *end_of_DRAM; -#ifdef CONFIG_BOOTX_TEXT - map_bootx_text(); -#endif #ifdef CONFIG_XMON { @@ -610,8 +610,16 @@ *memory_end_p = (unsigned long) end_of_DRAM; ppc_md.setup_arch(memory_start_p, memory_end_p); + + sort_exception_table(); } +#ifndef CONFIG_POWERMAC +void note_bootable_part(kdev_t dev, int part, int goodness) +{ +} +#endif + void ppc_generic_ide_fix_driveid(struct hd_driveid *id) { int i; @@ -713,7 +721,7 @@ id->word123 = __le16_to_cpu(id->word123); id->word124 = __le16_to_cpu(id->word124); id->word125 = __le16_to_cpu(id->word125); - id->word126 = __le16_to_cpu(id->word126); + id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); id->security = __le16_to_cpu(id->security); for (i=0; i<127; i++) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.2.17/arch/ppc/kernel/signal.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/signal.c Wed Nov 8 23:00:34 2000 @@ -14,6 +14,16 @@ * 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. + * + * + * 2000-04-7. + * Define a real-time signal frame with siginfo and ucontext + * structures (setup_rt_frame()). + * Stuck up a real-time signal frame when setting the signal + * frame with SA_SIGINFO flags. + * Add sys_rt_sigreturn() to undo the signal stack. + * + * Giovanna Ambrosini (ambrosini@lightning.ch) */ #include @@ -121,13 +131,6 @@ } -asmlinkage int sys_rt_sigreturn(unsigned long __unused) -{ - printk("sys_rt_sigreturn(): %s/%d not yet implemented.\n", - current->comm,current->pid); - do_exit(SIGSEGV); -} - asmlinkage int sys_sigaltstack(const stack_t *uss, stack_t *uoss) { @@ -171,13 +174,11 @@ * When we have signals to deliver, we set up on the * user stack, going down from the original stack pointer: * a sigregs struct - * one or more sigcontext structs + * one or more sigcontext structs with * a gap of __SIGNAL_FRAMESIZE bytes * * Each of these things must be a multiple of 16 bytes in size. * - * XXX ultimately we will have to stack up a siginfo and ucontext - * for each rt signal. */ struct sigregs { elf_gregset_t gp_regs; @@ -188,6 +189,15 @@ int abigap[56]; }; +struct rt_sigframe +{ + unsigned long _unused[2]; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; +}; + /* * Do a signal return; undo the signal stack. */ @@ -259,6 +269,91 @@ do_exit(SIGSEGV); } + +/* + * When we have rt signals to deliver, we set up on the + * user stack, going down from the original stack pointer: + * a sigregs struct + * one rt_sigframe struct (siginfo + ucontext) + * a gap of __SIGNAL_FRAMESIZE bytes + * + * Each of these things must be a multiple of 16 bytes in size. + * + */ +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe *rt_sf; + struct sigcontext_struct sigctx; + struct sigregs *sr; + int ret; + elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ + sigset_t set; + stack_t st; + unsigned long prevsp; + + rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)) + || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set)) + || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) + goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + rt_sf++; /* Look at next rt_sigframe */ + if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) { + /* Last stacked signal - restore registers - + * sigctx is initialized to point to the + * preamble frame (where registers are stored) + * see handle_signal() + */ + sr = (struct sigregs *) sigctx.regs; + if (regs->msr & MSR_FP ) + giveup_fpu(current); + if (copy_from_user(saved_regs, &sr->gp_regs, + sizeof(sr->gp_regs))) + goto badframe; + saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) + | (saved_regs[PT_MSR] & MSR_USERCHANGE); + memcpy(regs, saved_regs, GP_REGS_SIZE); + if (copy_from_user(current->tss.fpr, &sr->fp_regs, + sizeof(sr->fp_regs))) + goto badframe; + /* This function sets back the stack flags into + the current task structure. */ + sys_sigaltstack(&st, NULL); + + ret = regs->result; + } else { + /* More signals to go */ + /* Set up registers for next signal handler */ + regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE; + if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))) + goto badframe; + sr = (struct sigregs *) sigctx.regs; + regs->gpr[3] = ret = sigctx.signal; + /* Get the siginfo */ + get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo); + /* Get the ucontext */ + get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc); + regs->gpr[6] = (unsigned long) rt_sf; + + regs->link = (unsigned long) &sr->tramp; + regs->nip = sigctx.handler; + if (get_user(prevsp, &sr->gp_regs[PT_R1]) + || put_user(prevsp, (unsigned long *) regs->gpr[1])) + goto badframe; + } + return ret; + +badframe: + lock_kernel(); + do_exit(SIGSEGV); +} + + /* * Set up a signal frame. */ @@ -305,6 +400,57 @@ do_exit(SIGSEGV); } + +static void +setup_rt_frame(struct pt_regs *regs, struct sigregs *frame, + signed long newsp) +{ + struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp; + + /* Set up preamble frame */ + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto badframe; + if (regs->msr & MSR_FP) + giveup_fpu(current); + if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) + || __copy_to_user(&frame->fp_regs, current->tss.fpr, + ELF_NFPREG * sizeof(double)) + /* Set up to return from user space. + It calls the sc exception at offset 0x9999 + for sys_rt_sigreturn(). + */ + || __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */ + || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ + goto badframe; + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + + /* Retrieve rt_sigframe from stack and + set up registers for signal handler + */ + newsp -= __SIGNAL_FRAMESIZE; + if (put_user(regs->gpr[1], (unsigned long *)newsp) + || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler) + || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) + || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo) + || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc)) + goto badframe; + + regs->gpr[1] = newsp; + regs->gpr[6] = (unsigned long) rt_sf; + regs->link = (unsigned long) frame->tramp; + + return; + +badframe: +#if DEBUG_SIG + printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); +#endif + lock_kernel(); + do_exit(SIGSEGV); +} + /* * OK, we're invoking a handler */ @@ -314,6 +460,7 @@ unsigned long *newspp, unsigned long frame) { struct sigcontext_struct *sc; + struct rt_sigframe *rt_sf; if (regs->trap == 0x0C00 /* System Call! */ && ((int)regs->result == -ERESTARTNOHAND || @@ -321,20 +468,47 @@ !(ka->sa.sa_flags & SA_RESTART)))) regs->result = -EINTR; - /* Put another sigcontext on the stack */ - *newspp -= sizeof(*sc); - sc = (struct sigcontext_struct *) *newspp; - if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) - goto badframe; + /* Set up Signal Frame */ + if (ka->sa.sa_flags & SA_SIGINFO) { + /* Put a Real Time Context onto stack */ + *newspp -= sizeof(*rt_sf); + rt_sf = (struct rt_sigframe *) *newspp; + if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf))) + goto badframe; + + if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler) + || __put_user(&rt_sf->info, &rt_sf->pinfo) + || __put_user(&rt_sf->uc, &rt_sf->puc) + /* Put the siginfo */ + || __copy_to_user(&rt_sf->info, info, sizeof(*info)) + /* Create the ucontext */ + || __put_user(0, &rt_sf->uc.uc_flags) + || __put_user(0, &rt_sf->uc.uc_link) + || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) + || __put_user(sas_ss_flags(regs->gpr[1]), + &rt_sf->uc.uc_stack.ss_flags) + || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) + || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset)) + /* mcontext.regs points to preamble register frame */ + || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs) + || __put_user(sig, &rt_sf->uc.uc_mcontext.signal)) + goto badframe; + } else { + /* Put another sigcontext on the stack */ + *newspp -= sizeof(*sc); + sc = (struct sigcontext_struct *) *newspp; + if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) + goto badframe; - if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) - || __put_user(oldset->sig[0], &sc->oldmask) + if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) + || __put_user(oldset->sig[0], &sc->oldmask) #if _NSIG_WORDS > 1 - || __put_user(oldset->sig[1], &sc->_unused[3]) + || __put_user(oldset->sig[1], &sc->_unused[3]) #endif - || __put_user((struct pt_regs *)frame, &sc->regs) - || __put_user(sig, &sc->signal)) - goto badframe; + || __put_user((struct pt_regs *)frame, &sc->regs) + || __put_user(sig, &sc->signal)) + goto badframe; + } if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; @@ -494,7 +668,10 @@ if (newsp == frame) return 0; /* no signals delivered */ - setup_frame(regs, (struct sigregs *) frame, newsp); + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(regs, (struct sigregs *) frame, newsp); + else + setup_frame(regs, (struct sigregs *) frame, newsp); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/sleep.S linux/arch/ppc/kernel/sleep.S --- v2.2.17/arch/ppc/kernel/sleep.S Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/kernel/sleep.S Wed Nov 8 23:00:34 2000 @@ -113,8 +113,8 @@ stw r4,SL_HID0(r1) /* Set up stuff at address 0 */ - lis r5,wake_up@ha - addi r5,r5,wake_up@l + lis r5,grackle_wake_up@ha + addi r5,r5,grackle_wake_up@l tophys(r5,r5) stw r5,SL_PC(r1) lis r4,KERNELBASE@h @@ -124,22 +124,28 @@ addi r6,r6,MAGIC@l stw r5,0(r4) stw r6,4(r4) + /* Setup stuffs at 0x80-0x84 for Core99 */ + lis r3,core99_wake_up@ha + addi r3,r3,core99_wake_up@l + tophys(r3,r3) + stw r3,0x80(r4) + stw r5,0x84(r4) /* - * Flush the L1 data cache by reading the first 64kB of RAM + * Flush the L1 data cache by reading the first 128kB of RAM * and then flushing the same area with the dcbf instruction. * The L2 cache has already been disabled. */ - li r4,0x0800 /* 64kB / 32B */ + li r4,0x1000 /* 128kB / 32B */ mtctr r4 lis r4,KERNELBASE@h 1: lwz r0,0(r4) - addi r4,r4,0x0020 /* Go to start of next cache line */ + addi r4,r4,0x0020 /* Go to start of next cache line */ bdnz 1b sync - li r4,0x0800 /* 64k */ + li r4,0x1000 /* 128kB / 32B */ mtctr r4 lis r4,KERNELBASE@h 1: @@ -148,6 +154,14 @@ bdnz 1b sync +/* Turn off L1 (necessary ?) */ + mfspr r3,HID0 + ori r3,r3, HID0_ICE|HID0_DCE + xori r3,r3, HID0_ICE|HID0_DCE + mtspr HID0,r3 + sync + isync + /* * Set the HID0 and MSR for sleep. */ @@ -163,20 +177,50 @@ 1: sync mtmsr r2 isync - b 1b + b 1b + /* * Here is the resume code. + * Core99 machines resume here + * r4 has the physical address of SL_PC(sp). + */ + +core99_wake_up: + mr r1,r4 + mfspr r3,HID0 + /* use rlwinm ... */ + oris r3,r3,HID0_SLEEP@h + xoris r3,r3,HID0_SLEEP@h + mtspr HID0,r3 + sync + isync + + /* sanitize MSR */ + mfmsr r3 + ori r3,r3,MSR_EE|MSR_IP + xori r3,r3,MSR_EE|MSR_IP + mtmsr r3 + sync + isync + +/* + * Here is the resume code for older machines. * r1 has the physical address of SL_PC(sp). */ -wake_up: - /* Flash inval the instruction cache */ +grackle_wake_up: + /* Enable and then Flash inval the instruction cache */ mfspr r3,HID0 - ori r3,r3, HID0_ICFI - mtspr HID0,r3 + ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI + sync isync - /* Restore the HID0 register. This turns on the L1 caches. */ + mtspr HID0,r3 + xori r3,r3, HID0_ICFI|HID0_DCI + mtspr HID0,r3 + sync + + /* Restore the remaining bits of the HID0 register. */ subi r1,r1,SL_PC lwz r3,SL_HID0(r1) sync @@ -239,6 +283,13 @@ lwz r4,SL_IBAT3+4(r1) mtibatl 3,r4 + /* Flush all TLBs */ + lis r4, 0x1000 +1: addic. r4, r4, -0x1000 + tlbie r4 + blt 1b + sync + /* restore the MSR and turn on the MMU */ lwz r3,SL_MSR(r1) bl turn_on_mmu @@ -247,6 +298,8 @@ tovirt(r1,r1) /* Restore TB */ + lis r3,0 + mttbl r3 lwz r3,SL_TB(r1) lwz r4,SL_TB+4(r1) mttbu r3 @@ -267,3 +320,4 @@ mtsrr1 r3 sync rfi + sync diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.2.17/arch/ppc/kernel/smp.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/smp.c Wed Nov 8 23:00:34 2000 @@ -8,6 +8,8 @@ * * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes * (troy@blacklablinux.com, hozer@drgw.net) + * Support for PReP (Motorola MTX/MVME) and Macintosh G4 SMP + * by Troy Benjegerdes (hozer@drgw.net) */ #include @@ -37,6 +39,7 @@ #include #include #include +#include #include "open_pic.h" int first_cpu_booted = 0; @@ -46,7 +49,8 @@ struct cpuinfo_PPC cpu_data[NR_CPUS]; struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */ -volatile unsigned long ipi_count; +atomic_t ipi_recv; +atomic_t ipi_sent; spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; @@ -64,6 +68,9 @@ extern unsigned long *MotSave_SmpIar; extern unsigned char *MotSave_CpusState[2]; +/* l2 cache stuff for dual G4 macs */ +extern void core99_init_l2(void); + /* register for interrupting the secondary processor on the powersurge */ #define PSURGE_INTR ((volatile unsigned *)0xf80000c0) @@ -114,7 +121,7 @@ void smp_message_recv(int msg) { - ipi_count++; + atomic_inc(&ipi_recv); switch( msg ) { @@ -136,6 +143,7 @@ } } +#ifdef CONFIG_POWERMAC /* * 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 @@ -147,10 +155,10 @@ * rather than this. * -- Cort */ -int pmac_smp_message[NR_CPUS]; -void pmac_smp_message_recv(void) +int psurge_smp_message[NR_CPUS]; +void psurge_smp_message_recv(void) { - int msg = pmac_smp_message[smp_processor_id()]; + int msg = psurge_smp_message[smp_processor_id()]; /* clear interrupt */ out_be32(PSURGE_INTR, ~0); @@ -161,9 +169,9 @@ smp_message_recv(msg); /* reset message */ - pmac_smp_message[smp_processor_id()] = -1; + psurge_smp_message[smp_processor_id()] = -1; } - +#endif /* powermac */ /* * 750's don't broadcast tlb invalidates so @@ -195,49 +203,65 @@ smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0); } -void smp_message_pass(int target, int msg, unsigned long data, int wait) +#ifdef CONFIG_POWERMAC +static void psurge_message_pass(int target, int msg, unsigned long data, int wait) { int i; + /* + * 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++ ) + psurge_smp_message[i] = -1; + switch( target ) + { + case MSG_ALL: + psurge_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 () ) + psurge_smp_message[i] = msg; + break; + default: + psurge_smp_message[target] = msg; + break; + } + /* interrupt secondary processor */ + out_be32(PSURGE_INTR, ~0); + out_be32(PSURGE_INTR, 0); + /* + * Assume for now that the secondary doesn't send + * IPI's -- Cort + * Could be fixed with 2.4 code from Paulus -- BenH + */ + /* interrupt primary */ + /**(volatile unsigned long *)(0xf3019000);*/ +} +#endif /* powermac */ + +void smp_message_pass(int target, int msg, unsigned long data, int wait) +{ + atomic_inc(&ipi_sent); + if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) ) return; switch (_machine) { +#ifdef CONFIG_POWERMAC 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; + /* Hack, 2.4 does it cleanly */ + if (OpenPIC == NULL) { + psurge_message_pass(target, msg, data, wait); break; - } - /* interrupt secondary processor */ - out_be32(PSURGE_INTR, ~0); - out_be32(PSURGE_INTR, 0); - /* - * Assume for now that the secondary doesn't send - * IPI's -- Cort - */ - /* interrupt primary */ - /**(volatile unsigned long *)(0xf3019000);*/ - break; + } + /* else fall through and do something sane --Troy */ +#endif case _MACH_chrp: case _MACH_prep: case _MACH_gemini: @@ -261,6 +285,52 @@ } } +#ifdef CONFIG_POWERMAC +static void pmac_core99_kick_cpu(int nr) +{ + extern void __secondary_start_psurge(void); + + unsigned long save_int; + unsigned long flags; + volatile unsigned long *vector + = ((volatile unsigned long *)(KERNELBASE+0x500)); + + if (nr != 1) + return; + + __save_flags(flags); + __cli(); + + /* Save EE vector */ + save_int = *vector; + + /* Setup fake EE vector that does + * b __secondary_start_psurge - KERNELBASE + */ + *vector = 0x48000002 + + ((unsigned long)__secondary_start_psurge - KERNELBASE); + + /* flush data cache and inval instruction cache */ + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + /* Put some life in our friend */ + feature_core99_kick_cpu1(); + + /* FIXME: We wait a bit for the CPU to take the exception, I should + * instead wait for the entry code to set something for me. Well, + * ideally, all that crap will be done in prom.c and the CPU left + * in a RAM-based wait loop like CHRP. + */ + mdelay(1); + + /* Restore our exception vector */ + *vector = save_int; + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + __restore_flags(flags); +} +#endif /* powermac */ + void __init smp_boot_cpus(void) { extern struct task_struct *current_set[NR_CPUS]; @@ -297,15 +367,21 @@ switch ( _machine ) { +#ifdef CONFIG_POWERMAC case _MACH_Pmac: - /* assume powersurge board - 2 processors -- Cort */ + /* assum e powersurge board - 2 processors -- Cort */ + /* or a dual G4 -- Troy */ cpu_nr = 2; break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP) case _MACH_chrp: cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0) & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1; break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP) case _MACH_prep: /* assume 2 for now == fix later -- Johnnie */ if ( mot_multi ) @@ -313,10 +389,13 @@ cpu_nr = 2; break; } +#endif +#ifdef CONFIG_GEMINI case _MACH_gemini: cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2; cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr; break; +#endif default: printk("SMP not supported on this machine.\n"); return; @@ -347,30 +426,41 @@ /* wake up cpus */ switch ( _machine ) { +#ifdef CONFIG_POWERMAC case _MACH_Pmac: - /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) = - (unsigned long)__secondary_start_psurge-KERNELBASE; - eieio(); - /* interrupt secondary to begin executing code */ - out_be32(PSURGE_INTR, ~0); - out_be32(PSURGE_INTR, 0); + if (OpenPIC == NULL) { + /* setup entry point of secondary processor */ + *(volatile unsigned long *)(0xf2800000) = + (unsigned long)__secondary_start_psurge-KERNELBASE; + eieio(); + /* interrupt secondary to begin executing code */ + out_be32(PSURGE_INTR, ~0); + out_be32(PSURGE_INTR, 0); + } else + pmac_core99_kick_cpu(i); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP) case _MACH_chrp: *(unsigned long *)KERNELBASE = i; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP) case _MACH_prep: *MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE; *MotSave_CpusState[1] = CPU_GOOD; printk("CPU1 reset, waiting\n"); break; +#endif +#ifdef CONFIG_GEMINI case _MACH_gemini: openpic_init_processor( 1<loops_per_sec = loops_per_sec; + c->loops_per_jiffy = loops_per_jiffy; c->pvr = _get_PVR(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.2.17/arch/ppc/kernel/syscalls.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/syscalls.c Wed Nov 8 23:00:34 2000 @@ -283,3 +283,14 @@ return error; } + +#ifndef CONFIG_PCI +/* + * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is + * not defined, this file is not linked at all, so here are the "empty" versions + */ +asmlinkage int sys_pciconfig_read() { return -ENOSYS; } +asmlinkage int sys_pciconfig_write() { return -ENOSYS; } +asmlinkage long sys_pciconfig_iobase() { return -ENOSYS; } +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.2.17/arch/ppc/kernel/time.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/time.c Wed Nov 8 23:00:34 2000 @@ -71,7 +71,7 @@ { int dval, d; unsigned long cpu = smp_processor_id(); - + hardirq_enter(cpu); #ifdef __SMP__ { @@ -192,10 +192,10 @@ __initfunc(void time_init(void)) { + long time_offset = 0; + if (ppc_md.time_init != NULL) - { - ppc_md.time_init(); - } + time_offset = ppc_md.time_init(); if ((_get_PVR() >> 16) == 1) { /* 601 processor: dec counts down by 128 every 128ns */ @@ -208,6 +208,12 @@ xtime.tv_sec = ppc_md.get_rtc_time(); xtime.tv_usec = 0; + if (time_offset) { + struct timezone tz; + tz.tz_minuteswest = time_offset/60; + tz.tz_dsttime = 0; /* Not handled correctly by the kernel anyway */ + do_sys_settimeofday(NULL, &tz); + } set_dec(decrementer_count); /* allow updates right away */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.2.17/arch/ppc/kernel/traps.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/kernel/traps.c Wed Nov 8 23:00:34 2000 @@ -156,9 +156,52 @@ _exception(SIGTRAP, regs); } +/* Illegal instruction emulation support. Originally written to + * provide the PVR to user applications using the mfspr rd, PVR. + * Return non-zero if we can't emulate, or EFAULT if the associated + * memory access caused an access fault. Return zero on success. + * + * There are a couple of ways to do this, either "decode" the instruction + * or directly match lots of bits. In this case, matching lots of + * bits is faster and easier. + * + */ +#define INST_MFSPR_PVR 0x7c1f42a6 +#define INST_MFSPR_PVR_MASK 0xfc1fffff + +static int +emulate_instruction(struct pt_regs *regs) +{ + uint instword; + uint rd; + int retval; + + retval = EINVAL; + if (!user_mode(regs)) + return retval; + + retval = EFAULT; + if (get_user(instword, (uint *)(regs->nip))) + return retval; + + /* Emulate the mfspr rD, PVR. + */ + retval = EINVAL; + if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = _get_PVR(); + retval = 0; + } + if (retval == 0) + regs->nip += 4; + return(retval); +} + void ProgramCheckException(struct pt_regs *regs) { + int errcode; + if (regs->msr & 0x100000) { /* IEEE FP exception */ _exception(SIGFPE, regs); @@ -170,7 +213,13 @@ #endif _exception(SIGTRAP, regs); } else { - _exception(SIGILL, regs); + /* Try to emulate it if we should. */ + if ((errcode = emulate_instruction(regs))) { + if (errcode == EFAULT) + _exception(SIGBUS, regs); + else + _exception(SIGILL, regs); + } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/mm/extable.c linux/arch/ppc/mm/extable.c --- v2.2.17/arch/ppc/mm/extable.c Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/mm/extable.c Wed Nov 8 23:00:34 2000 @@ -7,8 +7,43 @@ #include #include -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of segments + * such as the prep, pmac, chrp, etc. segments as well as the init + * segment and the main kernel text segment. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void +sort_exception_table(void) +{ + sort_ex_table(__start___ex_table, __stop___ex_table); +} static inline unsigned long search_one_table(const struct exception_table_entry *first, @@ -36,7 +71,7 @@ { unsigned long ret; -#if 1 /*ndef CONFIG_MODULES*/ +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); if (ret) return ret; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.2.17/arch/ppc/mm/init.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/mm/init.c Wed Nov 8 23:00:34 2000 @@ -1044,6 +1044,9 @@ * still be merged. * -- Cort */ +#ifdef CONFIG_BOOTX_TEXT +extern boot_infos_t *disp_bi; +#endif __initfunc(void MMU_init(void)) { #ifdef __SMP__ @@ -1092,7 +1095,13 @@ struct device_node *macio = find_devices("mac-io"); if (macio && macio->n_addrs) base = macio->addrs[0].address; - setbat(0, base, base, 0x100000, IO_PAGE); + /* Hrm... we have it at 0x80000000 on some machines + * and this is covered by the userland segment + * registers. Isn't that bad ? Well, the BAT takes + * precedence, but I don't like it. --BenH + */ + if (base >= 0xf0000000) + setbat(0, base, base, 0x100000, IO_PAGE); ioremap_base = 0xf0000000; } break; @@ -1131,6 +1140,10 @@ ioremap(0x80000000, 0x4000); ioremap(0x81000000, 0x4000); #endif /* CONFIG_8xx */ +#ifdef CONFIG_BOOTX_TEXT + if (_machine == _MACH_Pmac) + map_bootx_text(); +#endif } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds --- v2.2.17/arch/ppc/vmlinux.lds Fri Apr 21 12:45:47 2000 +++ linux/arch/ppc/vmlinux.lds Tue Sep 5 22:20:06 2000 @@ -71,8 +71,16 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; + . = ALIGN(4096); __pmac_begin = .; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.2.17/arch/ppc/xmon/start.c Sat Sep 9 18:42:33 2000 +++ linux/arch/ppc/xmon/start.c Wed Nov 8 23:00:34 2000 @@ -467,3 +467,15 @@ *p = 0; return str; } + +void +xmon_enter(void) +{ + pmu_suspend(); +} + +void +xmon_leave(void) +{ + pmu_resume(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.2.17/arch/ppc/xmon/xmon.c Fri Apr 21 12:45:48 2000 +++ linux/arch/ppc/xmon/xmon.c Wed Nov 8 23:00:34 2000 @@ -86,6 +86,9 @@ extern int setjmp(u_int *); extern void longjmp(u_int *, int); +extern void xmon_enter(void); +extern void xmon_leave(void); + #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) static char *help_string = "\ @@ -139,6 +142,7 @@ msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ remove_bpts(); + xmon_enter(); excprint(excp); cmd = cmds(excp); if (cmd == 's') { @@ -151,6 +155,7 @@ xmon_trace = 0; insert_bpts(); } + xmon_leave(); set_msr(msr); /* restore interrupt enable */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/boot/ipleckd.S linux/arch/s390/boot/ipleckd.S --- v2.2.17/arch/s390/boot/ipleckd.S Sun Jun 11 21:44:09 2000 +++ linux/arch/s390/boot/ipleckd.S Wed Nov 8 23:09:58 2000 @@ -11,6 +11,8 @@ # FIXME: should insert zeroes into memory when filling holes # FIXME: calculate blkpertrack from rdc data and blksize +# change 09/20/00 removed obsolete store of ipldevice to textesegment + # Usage of registers # r1: ipl subchannel ( general use, dont overload without save/restore !) # r10: @@ -47,7 +49,7 @@ msch .Lrdcdata xi .Lprgn,6 # restore Wait and d/a bit in PCnew PSW l %r2,.Lparm - mvc 0x0(8,%r2),.Lnull # set parmarea to null + mvc 0x0(8,%r2),.Lnull # set parmarea to null lctl %c6,%c6,.Lc6 # enable all interrupts .Lrdc: # read device characteristics la %r6,.Lrdcccw @@ -94,7 +96,7 @@ .Lzeroes: lr %r2,%r3 .L001: slr %r3,%r3 - icm %r3,3,.Lcountarea+6 # get blocksize + icm %r3,3,.Lcountarea+6 # get blocksize slr %r5,%r5 # no bytes to move .L008: mvcle %r2,%r4,0 # fill zeroes to storage jo .L008 # until block is filled @@ -111,10 +113,10 @@ mvc 0x600(256,%r3),0x180(%r4) mvc 0x700(256,%r3),0x280(%r4) .Lrunkern: - lhi %r2,17 - sll %r2,12 - st %r1,0xc6c(%r2) # store iplsubchannel to lowcore - st %r1,0xc6c # store iplsubchannel to lowcore +# lhi %r2,17 +# sll %r2,12 +# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore +# st %r1,0xc6c # store iplsubchannel to lowcore br %r3 # This function does the start IO # r2: number of first block to read ( input by caller ) @@ -140,16 +142,16 @@ lr %r15,%r4 # save number or blocks slr %r7,%r7 icm %r7,3,.Lrdcdata+14 # load heads to r7 - lhi %r6,9 - clc .Lrdcdata+3(2),.L9343 + lhi %r6,9 + clc .Lrdcdata+3(2),.L9345 je .L011 - lhi %r6,10 + lhi %r6,10 clc .Lrdcdata+3(2),.L3380 je .L011 lhi %r6,12 clc .Lrdcdata+3(2),.L3390 je .L011 - bras %r14,.Ldisab + bras %r14,.Ldisab .L011: # loop for nbl times .Lrdloop: @@ -244,8 +246,8 @@ .long 0x00008000 # they are loaded with a LM .L3390: .word 0x3390 -.L9343: - .word 0x934a +.L9345: + .word 0x9345 .L3380: .word 0x3380 .Lnull: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/config.in linux/arch/s390/config.in --- v2.2.17/arch/s390/config.in Sun Jun 11 21:44:09 2000 +++ linux/arch/s390/config.in Wed Nov 8 23:09:58 2000 @@ -8,6 +8,7 @@ mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG endmenu mainmenu_option next_comment diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/defconfig linux/arch/s390/defconfig --- v2.2.17/arch/s390/defconfig Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/defconfig Wed Nov 8 23:09:58 2000 @@ -7,6 +7,7 @@ # Code maturity level options # CONFIG_EXPERIMENTAL=y +CONFIG_PROCESS_DEBUG=n # # Processor type and features @@ -81,7 +82,7 @@ # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set # CONFIG_IP_ROUTER is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/cpcmd.c linux/arch/s390/kernel/cpcmd.c --- v2.2.17/arch/s390/kernel/cpcmd.c Sun Jun 11 21:44:09 2000 +++ linux/arch/s390/kernel/cpcmd.c Wed Nov 8 23:09:58 2000 @@ -8,7 +8,7 @@ #include #include -#include +#include #include void cpcmd(char *cmd, char *response, int rlen) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c --- v2.2.17/arch/s390/kernel/debug.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/debug.c Wed Nov 8 23:04:58 2000 @@ -1,285 +1,1120 @@ +/* + * arch/s390/kernel/debug.c + * S/390 debug facility + * + * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, + * IBM Corporation + * Author(s): Michael Holzheu (holzheu@de.ibm.com), + * Holger Smolinski (Holger.Smolinski@de.ibm.com) + * + * Bugreports to: + */ + #include #include #include #include +#include +#include +#include #include -#include +#include +#include #ifdef MODULE #include #endif -#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#if defined(CONFIG_ARCH_S390) +#define DEBUG_PROC_HEADER_SIZE 38 +#endif + +#define ADD_BUFFER 1000 + +/* typedefs */ + +typedef struct file_private_info { + loff_t len; /* length of output in byte */ + int size; /* size of buffer for output */ + char *data; /* buffer for output */ + debug_info_t *debug_info; /* the debug information struct */ + struct debug_view *view; /* used view of debug info */ +} file_private_info_t; + +extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); + +/* internal function prototyes */ + +static int debug_init(void); +static int debug_format_output(debug_info_t * debug_area, char *buf, + int size, struct debug_view *view); +static ssize_t debug_output(struct file *file, char *user_buf, + size_t user_len, loff_t * offset); +static ssize_t debug_input(struct file *file, const char *user_buf, + size_t user_len, loff_t * offset); +static int debug_open(struct inode *inode, struct file *file); +static int debug_close(struct inode *inode, struct file *file); +static struct proc_dir_entry +*debug_create_proc_dir_entry(struct proc_dir_entry *root, + const char *name, mode_t mode, + struct inode_operations *iops, + struct file_operations *fops); +static void debug_delete_proc_dir_entry(struct proc_dir_entry *root, + struct proc_dir_entry *entry); +static void debug_info_get(debug_info_t *); +static void debug_info_put(debug_info_t *); +static int debug_prolog_level_fn(debug_info_t * id, + struct debug_view *view, char *out_buf); +static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char *user_buf, + size_t user_buf_size, loff_t * offset); +static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf); +static int debug_ascii_format_fn(debug_info_t * id, + struct debug_view *view, char *out_buf, + const char *in_buf); +static int debug_ebcdic_format_fn(debug_info_t * id, + struct debug_view *view, char *out_buf, + const char *in_buf); + +/* globals */ + +struct debug_view debug_ascii_view = { + "ascii", + NULL, + &debug_dflt_header_fn, + &debug_ascii_format_fn, + NULL +}; + +struct debug_view debug_ebcdic_view = { + "ebcdic", + NULL, + &debug_dflt_header_fn, + &debug_ebcdic_format_fn, + NULL +}; + +struct debug_view debug_hex_view = { + "hex", + NULL, + &debug_dflt_header_fn, + &debug_hex_format_fn, + NULL +}; + +struct debug_view debug_level_view = { + "level", + &debug_prolog_level_fn, + NULL, + NULL, + &debug_input_level_fn +}; + +/* static globals */ + +static debug_info_t debug_areas[DEBUG_MAX_AREAS]; +static debug_info_t *free_area = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) +static struct semaphore debug_lock = MUTEX; +#else +DECLARE_MUTEX(debug_lock); +#endif -debug_info_t debug_areas[MAX_DEBUG_AREAS] = { {NULL, },}; -debug_info_t *free_area = 0; static int initialized = 0; -static spinlock_t debug_lock = SPIN_LOCK_UNLOCKED; +static struct file_operations debug_file_ops = { + read: debug_output, + write: debug_input, + open: debug_open, + release: debug_close, +}; + +static struct inode_operations debug_inode_ops = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + default_file_ops: &debug_file_ops, /* file ops */ +#endif +}; + + +static struct proc_dir_entry *debug_proc_root_entry; + + +/* functions */ + +/* + * debug_info_get + * - increments reference count for debug-info + */ + +static void debug_info_get(debug_info_t * db_info) +{ + if (db_info) + atomic_inc(&db_info->ref_count); +} + +/* + * debug_info_put: + * - decreases reference count for debug-info and frees it if necessary + */ + +static void debug_info_put(debug_info_t *db_info) +{ + int i; + + if (!db_info) + return; + if (atomic_dec_and_test(&db_info->ref_count)) { + printk(KERN_INFO "debug: freeing debug area %p (%s)\n", + db_info, db_info->name); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (db_info->views[i] != NULL) + debug_delete_proc_dir_entry + (db_info->proc_root_entry, + db_info->proc_entries[i]); + } + debug_delete_proc_dir_entry(debug_proc_root_entry, + db_info->proc_root_entry); + for (i = 0; i < db_info->nr_areas; i++) { + free_pages((unsigned long) db_info->areas[i], + db_info->page_order); + } + kfree(db_info->areas); + db_info->areas = NULL; + *((debug_info_t **) db_info) = free_area; + free_area = db_info; + } +} + -debug_info_t * -debug_register (char *name, int page_order, int nr_areas) +/* + * debug_output: + * - called for user read() + * - copies formated output form private_data of the file + * handle to the user buffer + */ + +static ssize_t debug_output(struct file *file, /* file descriptor */ + char *user_buf, /* user buffer */ + size_t user_len, /* length of buffer */ + loff_t *offset /* offset in the file */ ) { - debug_info_t *rc = 0; - int i; - long flags; - - if ( ! initialized ){ - debug_init(); - initialized = 1; - } - if (!free_area) - { - printk (KERN_WARNING "No free debug area\n"); - return NULL; - } - spin_lock_irqsave (&debug_lock, flags); - rc = free_area; - free_area = *((debug_info_t **) rc); - - memset(rc, 0, nr_areas * sizeof(debug_info_t)); - rc->areas = (debug_entry_t **) kmalloc (nr_areas * - sizeof (debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) - { - goto noareas; - } - - for (i = 0; i < nr_areas; i++) - { - rc->areas[i] = (debug_entry_t *) __get_free_pages (GFP_ATOMIC, - page_order); - if (!rc->areas[i]) + loff_t len; + int rc; + file_private_info_t *p_info; + + p_info = ((file_private_info_t *) file->private_data); + if (*offset >= p_info->len) { + return 0; /* EOF */ + } else { + len = MIN(user_len, (p_info->len - *offset)); + if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len))) + return rc;; + (*offset) += len; + return len; /* number of bytes "read" */ + } +} + +/* + * debug_input: + * - called for user write() + * - calls input function of view + */ + +static ssize_t debug_input(struct file *file, + const char *user_buf, size_t length, + loff_t *offset) +{ + int rc = 0; + file_private_info_t *p_info; + + down(&debug_lock); + p_info = ((file_private_info_t *) file->private_data); + if (p_info->view->input_proc) + rc = p_info->view->input_proc(p_info->debug_info, + p_info->view, file, user_buf, + length, offset); + up(&debug_lock); + return rc; /* number of input characters */ +} + +/* + * debug_format_output: + * - calls prolog, header and format functions of view to format output + */ + +static int debug_format_output(debug_info_t * debug_area, char *buf, + int size, struct debug_view *view) +{ + int len = 0; + int i, j; + int nr_of_entries; + debug_entry_t *act_entry; + + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(debug_area, view, buf); + /* print debug records */ + if (!(view->format_proc) && !(view->header_proc)) + goto out; + nr_of_entries = PAGE_SIZE / debug_area->entry_size + << debug_area->page_order; + for (i = 0; i < debug_area->nr_areas; i++) { + act_entry = debug_area->areas[i]; + for (j = 0; j < nr_of_entries; j++) { + if (act_entry->id.fields.used == 0) + break; /* empty entry */ + if (view->header_proc) + len += view->header_proc(debug_area, view, i, + act_entry, buf + len); + if (view->format_proc) + len += view->format_proc(debug_area, view, + buf + len, + act_entry->data); + len += sprintf(buf + len, "\n"); + if (len > size) { + printk(KERN_ERR + "debug: error -- memory exceeded for (%s/%s)\n", + debug_area->name, view->name); + printk(KERN_ERR "debug: fix view %s!!\n", + view->name); + printk(KERN_ERR + "debug: area: %i (0 - %i) entry: %i (0 - %i)\n", + i, debug_area->nr_areas - 1, j, + nr_of_entries - 1); + goto out; + } + act_entry = (debug_entry_t *) (((char *) act_entry) + + debug_area->entry_size); + } + } + out: + return len; +} + + +/* + * debug_open: + * - called for user open() + * - copies formated output to private_data area of the file + * handle + */ + +static int debug_open(struct inode *inode, struct file *file) +{ + int i, j = 0, size = 0, rc = 0, f_entry_size = 0; + file_private_info_t *p_info; + +#ifdef DEBUG + printk("debug_open\n"); +#endif + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + down(&debug_lock); + + /* find debug log and view */ + + for (i = 0; i < DEBUG_MAX_AREAS; i++) { + if (debug_areas[i].areas == NULL) + continue; /* not in use */ + for (j = 0; j < DEBUG_MAX_VIEWS; j++) { + if (debug_areas[i].views[j] == NULL) + continue; + else if (debug_areas[i].proc_entries[j]->low_ino == + file->f_dentry->d_inode->i_ino) { + goto found; /* found view ! */ + } + } + } + /* no entry found */ + rc = -EINVAL; + goto out; + found: + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + rc = -ENOMEM; + goto out; + } + p_info = (file_private_info_t *) file->private_data; + + /* + * the size for the formated output is calculated + * with the following formula: + * + * prolog-size + * + + * (record header size + record data field size) + * * number of entries per page + * * number of pages per area + * * number of areas + */ + + if (debug_areas[i].views[j]->prolog_proc) + size += + debug_areas[i].views[j]->prolog_proc(&debug_areas[i], + debug_areas[i]. + views[j], NULL); + + if (debug_areas[i].views[j]->header_proc) + f_entry_size = + debug_areas[i].views[j]->header_proc(&debug_areas[i], + debug_areas[i]. + views[j], 0, NULL, + NULL); + if (debug_areas[i].views[j]->format_proc) + f_entry_size += + debug_areas[i].views[j]->format_proc(&debug_areas[i], + debug_areas[i]. + views[j], NULL, + NULL); + if (f_entry_size) + f_entry_size += 1; /* \n in each line */ + + + size += f_entry_size + * (PAGE_SIZE / debug_areas[i].entry_size + << debug_areas[i].page_order) + * debug_areas[i].nr_areas + 1; /* terminating \0 */ +#ifdef DEBUG + printk("debug_open: size: %i\n", size); +#endif + + /* alloc some bytes more to be safe against bad views */ + if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) { + printk(KERN_ERR "debug_open: vmalloc failed\n"); + vfree(file->private_data); + rc = -ENOMEM; + goto out; + } + + p_info->size = size; + p_info->debug_info = &debug_areas[i]; + p_info->view = debug_areas[i].views[j]; + + spin_lock_irq(&debug_areas[i].lock); + + p_info->len = + debug_format_output(&debug_areas[i], p_info->data, size, + debug_areas[i].views[j]); +#ifdef DEBUG { - for (i--; i >= 0; i--) - { - free_pages ((unsigned long) rc->areas[i], page_order); - } - goto nopages; - } - } - rc->page_order = page_order; - rc->nr_areas = nr_areas; - rc->name = kmalloc (strlen (name) + 1, GFP_ATOMIC); - strncpy (rc->name, name, strlen (name)); - ASCEBC(rc->name, strlen (name)); - rc->name[strlen (name)] = 0; - - rc->active_entry = kmalloc (nr_areas, GFP_ATOMIC); - memset(rc->active_entry, 0, nr_areas * sizeof(int)); - rc->level=3; - printk (KERN_INFO "reserved %d areas of %d pages for debugging %s\n", - nr_areas, 1 << page_order, name); - goto exit; - -nopages: -noareas: - free_area = rc; -exit: - spin_unlock_irqrestore (&debug_lock, flags); - return rc; -} - -void -debug_unregister (debug_info_t * id, char *name) -{ - int i = id->nr_areas; - long flags; - spin_lock_irqsave (&debug_lock, flags); - printk (KERN_INFO "freeing debug area %p named '%s'\n", id, name); - if (strncmp (name, id->name, strlen (name))) - { - printk (KERN_ERR "name '%s' does not match against '%s'\n", - name, id->name); - } - for (i--; i >= 0; i--) - { - free_pages ((unsigned long) id->areas[i], id->page_order); - } - kfree (id->areas); - kfree (id->name); - *((debug_info_t **) id) = free_area; - free_area = id; - spin_unlock_irqrestore (&debug_lock, flags); - return; -} - -static inline void -proceed_active_entry (debug_info_t * id) -{ - id->active_entry[id->active_area] = - (id->active_entry[id->active_area]++) % - ((PAGE_SIZE / sizeof (debug_entry_t)) << (id->page_order)); -} - -static inline void -proceed_active_area (debug_info_t * id) -{ - id->active_area = (id->active_area++) % id->nr_areas; -} - -static inline debug_entry_t * -get_active_entry (debug_info_t * id) -{ - return &id->areas[id->active_area][id->active_entry[id->active_area]]; -} - -static inline debug_entry_t * -debug_common ( debug_info_t * id ) -{ - debug_entry_t * active; - proceed_active_entry (id); - active = get_active_entry (id); - STCK (active->id.stck); - active->id.stck = active->id.stck >> 4; - active->id.fields.cpuid = smp_processor_id (); - active->caller = __builtin_return_address (0); - return active; -} - -void -debug_event (debug_info_t * id, int level, unsigned int tag) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - active->tag.tag = tag; - spin_unlock_irqrestore (&id->lock, flags); - return; -} - -void -debug_text_event (debug_info_t * id, int level, char tag[4]) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - strncpy ( active->tag.text, tag, 4); - ASCEBC (active->tag.text, 4 ); - spin_unlock_irqrestore (&id->lock, flags); - return; -} - -void -debug_exception (debug_info_t * id, int level, unsigned int tag) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - active->tag.tag = tag; - proceed_active_area (id); - spin_unlock_irqrestore (&id->lock, flags); - - return; -} - -void -debug_text_exception (debug_info_t * id, int level, char tag[4]) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - strncpy ( active->tag.text, tag, 4); - ASCEBC (active->tag.text, 4 ); - proceed_active_area (id); - spin_unlock_irqrestore (&id->lock, flags); - return; -} - -int -debug_init (void) -{ - int rc = 0; - int i; - for (i = 0; i < MAX_DEBUG_AREAS - 1; i++) - { - *(debug_info_t **) (&debug_areas[i]) = - (debug_info_t *) (&debug_areas[i + 1]); - } - *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL; - free_area = &(debug_areas[0]); - printk (KERN_INFO "%d areas reserved for debugging information\n", - MAX_DEBUG_AREAS); - return rc; + int ilen = p_info->len; + printk("debug_open: len: %i\n", ilen); + } +#endif + + spin_unlock_irq(&debug_areas[i].lock); + debug_info_get(&debug_areas[i]); + + out: + up(&debug_lock); +#ifdef MODULE + if (rc != 0) + MOD_DEC_USE_COUNT; +#endif + return rc; +} + +/* + * debug_close: + * - called for user close() + * - deletes private_data area of the file handle + */ + +static int debug_close(struct inode *inode, struct file *file) +{ + file_private_info_t *p_info; +#ifdef DEBUG + printk("debug_close\n"); +#endif + down(&debug_lock); + p_info = (file_private_info_t *) file->private_data; + debug_info_put(p_info->debug_info); + if (p_info->data) { + vfree(p_info->data); + kfree(file->private_data); + } + up(&debug_lock); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; /* success */ +} + +/* + * debug_create_proc_dir_entry: + * - initializes proc-dir-entry and registers it + */ + +static struct proc_dir_entry *debug_create_proc_dir_entry + (struct proc_dir_entry *root, const char *name, mode_t mode, + struct inode_operations *iops, struct file_operations *fops) +{ + struct proc_dir_entry *rc = NULL; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + const char *fn = name; + int len; + len = strlen(fn); + + rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry) + + len + 1, GFP_ATOMIC); + if (!rc) + goto out; + + memset(rc, 0, sizeof(struct proc_dir_entry)); + memcpy(((char *) rc) + sizeof(*rc), fn, len + 1); + rc->name = ((char *) rc) + sizeof(*rc); + rc->namelen = len; + rc->low_ino = 0, rc->mode = mode; + rc->nlink = 1; + rc->uid = 0; + rc->gid = 0; + rc->size = 0; + rc->get_info = NULL; + rc->ops = iops; + + proc_register(root, rc); +#else + rc = create_proc_entry(name, mode, root); + if (!rc) + goto out; + if (fops) + rc->proc_fops = fops; +#endif + + out: + return rc; +} + + +/* + * delete_proc_dir_entry: + */ + +static void debug_delete_proc_dir_entry + (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) +{ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + proc_unregister(root, proc_entry->low_ino); + kfree(proc_entry); +#else + remove_proc_entry(proc_entry->name, root); +#endif } +/* + * debug_register: + * - creates and initializes debug area for the caller + * - returns handle for debug area + */ + +debug_info_t *debug_register + (char *name, int page_order, int nr_areas, int buf_size) +{ + debug_info_t *rc = NULL; + int i; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + if (!initialized) + debug_init(); + down(&debug_lock); + if (!free_area) { + printk(KERN_WARNING "debug: no free debug area for %s\n", + name); + goto out; + } + rc = free_area; + free_area = *((debug_info_t **) rc); + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) { + free_area = rc; + rc = NULL; + goto out; + } + for (i = 0; i < nr_areas; i++) { + rc->areas[i] = + (debug_entry_t *) __get_free_pages(GFP_ATOMIC, + page_order); + if (!rc->areas[i]) { + for (i--; i >= 0; i--) { + free_pages((unsigned long) rc->areas[i], + page_order); + } + free_area = rc; + rc = NULL; + goto out; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + rc->page_order = page_order; + rc->nr_areas = nr_areas; + rc->active_area = 0; + rc->level = DEBUG_DEFAULT_LEVEL; + rc->buf_size = buf_size; + rc->entry_size = sizeof(debug_entry_t) + + buf_size - 4; /* must subtract data[4] */ + strncpy(rc->name, name, + MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); + rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; + memset(rc->active_entry, 0, nr_areas * sizeof(int)); + memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + atomic_set(&(rc->ref_count), 0); + rc->proc_root_entry = + debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, + S_IFDIR | S_IRUGO | S_IXUGO | + S_IWUSR | S_IWGRP, NULL, NULL); + debug_register_view(rc, &debug_level_view); + debug_info_get(rc); + printk(KERN_INFO + "debug: reserved %d areas of %d pages for debugging %s\n", + nr_areas, 1 << page_order, rc->name); + out: + if (rc == NULL){ + printk(KERN_ERR "debug: debug_register failed for %s\n",name); #ifdef MODULE -int -init_module (void) + MOD_DEC_USE_COUNT; +#endif + } + up(&debug_lock); + return rc; +} + +/* + * debug_unregister: + * - give back debug area + */ + +void debug_unregister(debug_info_t * id) +{ + if (!id) + goto out; + down(&debug_lock); + printk(KERN_INFO "debug: unregistering %s\n", id->name); + debug_info_put(id); + up(&debug_lock); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + out: + return; +} + + +/* + * proceed_active_entry: + * - set active entry to next in the ring buffer + */ + +static inline void proceed_active_entry(debug_info_t * id) +{ + if ((id->active_entry[id->active_area] += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) - id->entry_size)) + id->active_entry[id->active_area] = 0; +} + +/* + * proceed_active_area: + * - set active area to next in the ring buffer + */ + +static inline void proceed_active_area(debug_info_t * id) +{ + id->active_area++; + id->active_area = id->active_area % id->nr_areas; +} + +/* + * get_active_entry: + */ + +static inline debug_entry_t *get_active_entry(debug_info_t * id) +{ + return (debug_entry_t *) ((char *) id->areas[id->active_area] + + id->active_entry[id->active_area]); +} + +/* + * debug_common: + * - set timestamp, caller address, cpu number etc. + */ + +static inline debug_entry_t *debug_common(debug_info_t * id) +{ + debug_entry_t *active; + + active = get_active_entry(id); + STCK(active->id.stck); + active->id.fields.cpuid = smp_processor_id(); + active->id.fields.used = 1; + active->caller = __builtin_return_address(0); + return active; +} + +/* + * debug_event: + */ + +debug_entry_t *debug_event(debug_info_t * id, int level, void *buf, + int len) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level < id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 0; + memset(active->data, 0, id->buf_size); + memcpy(active->data, buf, MIN(len, id->buf_size)); + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_int_event: + */ + +debug_entry_t *debug_int_event(debug_info_t * id, int level, + unsigned int tag) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level < id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 0; + memset(active->data, 0, id->buf_size); + memcpy(active->data, &tag, MIN(sizeof(unsigned int), id->buf_size)); + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_text_event: + */ + +debug_entry_t *debug_text_event(debug_info_t * id, int level, + const char *txt) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level < id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + memset(active->data, 0, id->buf_size); + strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); + ASCEBC(active->data, MIN(strlen(txt), id->buf_size)); + active->id.fields.exception = 0; + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; + +} + +/* + * debug_exception: + */ + +debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, + int len) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level < id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 1; + memset(active->data, 0, id->buf_size); + memcpy(active->data, buf, MIN(len, id->buf_size)); + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_int_exception: + */ + +debug_entry_t *debug_int_exception(debug_info_t * id, int level, + unsigned int tag) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level < id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 1; + memset(active->data, 0, id->buf_size); + memcpy(active->data, &tag, + MIN(sizeof(unsigned int), id->buf_size)); + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_text_exception: + */ + +debug_entry_t *debug_text_exception(debug_info_t * id, int level, + const char *txt) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level < id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + memset(active->data, 0, id->buf_size); + strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); + ASCEBC(active->data, MIN(strlen(txt), id->buf_size)); + active->id.fields.exception = 1; + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; + +} + +/* + * debug_init: + * - is called exactly once to initialize the debug feature + */ + +int debug_init(void) +{ + int rc = 0; + int i; + + down(&debug_lock); + if (!initialized) { + debug_proc_root_entry = + debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT, + S_IFDIR | S_IRUGO | S_IXUGO + | S_IWUSR | S_IWGRP, NULL, + NULL); + for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) { + *(debug_info_t **) (&debug_areas[i]) = + (debug_info_t *) (&debug_areas[i + 1]); + } + *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL; + free_area = &(debug_areas[0]); + printk(KERN_INFO + "debug: %d areas reserved for debugging information\n", + DEBUG_MAX_AREAS); + initialized = 1; + } + up(&debug_lock); + + return rc; +} + +/* + * debug_register_view: + */ + +int debug_register_view(debug_info_t * id, struct debug_view *view) +{ + int rc = 0; + int i; + long flags; + mode_t mode = S_IFREG; + + if (!id) + goto out; + spin_lock_irqsave(&id->lock, flags); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (id->views[i] == NULL) + break; + } + if (i == DEBUG_MAX_VIEWS) { + printk(KERN_WARNING "debug: cannot register view %s/%s\n", + id->name,view->name); + printk(KERN_WARNING + "debug: maximum number of views reached (%i)!\n", i); + rc = -1; + } + else { + id->views[i] = view; + if (view->prolog_proc || view->format_proc || view->header_proc) + mode |= S_IRUSR; + if (view->input_proc) + mode |= S_IWUSR; + id->proc_entries[i] = + debug_create_proc_dir_entry(id->proc_root_entry, + view->name, mode, + &debug_inode_ops, + &debug_file_ops); + rc = 0; + } + spin_unlock_irqrestore(&id->lock, flags); + out: + return rc; +} + +/* + * debug_unregister_view: + */ + +int debug_unregister_view(debug_info_t * id, struct debug_view *view) +{ + int rc = 0; + int i; + long flags; + + if (!id) + goto out; + spin_lock_irqsave(&id->lock, flags); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (id->views[i] == view) + break; + } + if (i == DEBUG_MAX_VIEWS) + rc = -1; + else { + debug_delete_proc_dir_entry(id->proc_root_entry, + id->proc_entries[i]); + id->views[i] = NULL; + rc = 0; + } + spin_unlock_irqrestore(&id->lock, flags); + out: + return rc; +} + +/* + * functions for debug-views + *********************************** +*/ + +/* + * prints out actual debug level + */ + +static int debug_prolog_level_fn(debug_info_t * id, + struct debug_view *view, char *out_buf) +{ + int rc = 0; + + if (out_buf == NULL) { + rc = 2; + goto out; + } + rc = sprintf(out_buf, "%i\n", id->level); + out: + return rc; +} + +/* + * reads new debug level + */ + +static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char *user_buf, + size_t in_buf_size, loff_t * offset) +{ + char input_buf[1]; + int rc = in_buf_size; + + if (*offset != 0) + goto out; + if ((rc = copy_from_user(input_buf, user_buf, 1))) + goto out; + if (isdigit(input_buf[0])) { + int new_level = ((int) input_buf[0] - (int) '0'); + if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { + printk(KERN_INFO + "debug: level %i is out of range (%i - %i)\n", + new_level, 0, DEBUG_MAX_LEVEL); + } else { + id->level = new_level; + printk(KERN_INFO + "debug: set new level %i for %s\n", + id->level, id->name); + } + } else { + printk(KERN_INFO "debug: level `%c` is not valid\n", + input_buf[0]); + } + out: + *offset += in_buf_size; + return rc; /* number of input characters */ +} + +/* + * prints debug data in hex format + */ + +static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + int i, rc = 0; + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size * 3; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + out: + return rc; +} + +/* + * prints debug data in ascii format + */ + +static int debug_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) { - int rc = 0; - rc = debug_init (); - if (rc) - { - printk (KERN_INFO "An error occurred with debug_init\n"); - } - - { /* test section */ - debug_info_t *a[4]; - printk (KERN_INFO "registering 1, %p\n", a[0] = - debug_register ("debug1", 1, 1)); - printk (KERN_INFO "registering 2, %p\n", a[1] = - debug_register ("debug2", 1, 2)); - printk (KERN_INFO "registering 3, %p\n", a[2] = - debug_register ("debug3", 2, 1)); - printk (KERN_INFO "registering 4, %p\n", a[3] = - debug_register ("debug4", 2, 2)); - debug_unregister (a[0], "debug1"); - debug_unregister (a[1], "debug3"); - printk (KERN_INFO "registering 1, %p\n", a[0] = - debug_register ("debug5", 1, 1)); - printk (KERN_INFO "registering 2, %p\n", a[1] = - debug_register ("debug6", 1, 2)); - debug_unregister (a[2], "debug2"); - debug_unregister (a[3], "debug4"); - debug_unregister (a[0], "debug5"); - debug_unregister (a[1], "debug6"); - } - return rc; + int i, rc = 0; + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + unsigned char c = in_buf[i]; + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + out: + return rc; } -void -cleanup_module (void) +/* + * prints debug data in ebcdic format + */ + +static int debug_ebcdic_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) { + int i, rc = 0; - return; + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + unsigned char c = in_buf[i]; + EBCASC(&c, 1); + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + out: + return rc; +} + +/* + * prints header for debug entry + */ + +int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) +{ + struct timeval time_val; + unsigned long long time; + char *except_str; + unsigned long caller; + int rc = 0; + + if (out_buf == NULL) { + rc = DEBUG_PROC_HEADER_SIZE; + goto out; + } + + time = entry->id.stck; + /* adjust todclock to 1970 */ + time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); + tod_to_timeval(time, &time_val); + + if (entry->id.fields.exception) + except_str = "*"; + else + except_str = "-"; + caller = (unsigned long) entry->caller; +#if defined(CONFIG_ARCH_S390) + caller &= 0x7fffffff; + rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ", + area, time_val.tv_sec, + time_val.tv_usec, except_str, + entry->id.fields.cpuid, caller); +#endif + out: + return rc; +} + +/* + * init_module: + */ + +#ifdef MODULE +int init_module(void) +{ + int rc = 0; +#ifdef DEBUG + printk("debug_module_init: \n"); +#endif + rc = debug_init(); + if (rc) + printk(KERN_INFO "debug: an error occurred with debug_init\n"); + return rc; +} + +/* + * cleanup_module: + */ + +void cleanup_module(void) +{ +#ifdef DEBUG + printk("debug_cleanup_module: \n"); +#endif + debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry); + return; } -#endif /* MODULE */ +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.2.17/arch/s390/kernel/entry.S Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/entry.S Wed Nov 8 23:09:58 2000 @@ -21,11 +21,11 @@ /* * stack layout for the system_call stack entry - * Martin please don't modify these back to hard coded values - * You know how bad I'm at mental arithmetic DJB & it gives + * Martin please don't modify these back to hard coded values + * You know how bad I'm at mental arithmetic DJB & it gives * me grief when I modify the pt_regs */ -SP_PTREGS = STACK_FRAME_OVERHEAD +SP_PTREGS = STACK_FRAME_OVERHEAD SP_PSW = SP_PTREGS SP_R0 = (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE) SP_R1 = (SP_R0+GPR_SIZE) @@ -51,13 +51,13 @@ /* fpu registers are saved & restored by the gdb stub itself */ SP_FPC = (SP_CRREGS+(NUM_CRS*CR_SIZE)) SP_FPRS = (SP_FPC+FPC_SIZE+FPC_PAD_SIZE) -/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not +/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not defined in ptrace.h but space is needed for this too */ SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE)) #else SP_PGM_OLD_ILC= (SP_TRAP+4) #endif -SP_SVC_STEP = (SP_PGM_OLD_ILC+4) +SP_SVC_STEP = (SP_PGM_OLD_ILC+4) SP_SIZE = (SP_SVC_STEP+4) /* * these defines are offsets into the thread_struct @@ -140,7 +140,7 @@ stm %r0,%r12,SP_R0(%r15) ; /* store gprs 0-12 to kernel stack */ \ st %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \ mvc SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \ - stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \ + stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */\ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \ mvc SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \ la %r0,psworg ; /* store trap indication */ \ @@ -150,10 +150,10 @@ #define RESTORE_ALL \ mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ + lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \ lpsw __LC_RETURN_PSW /* back to caller */ - + #define GET_CURRENT /* load pointer to task_struct to R9 */ \ lr %r9,%r15 ; \ n %r9,BASED(.Lc0xffffe000) @@ -170,12 +170,12 @@ basr %r1,0 # setup base pointer resume_base: l %r4,_TSS_PTREGS(%r3) - tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? + tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? bz resume_noper-resume_base(%r1) # if not we're fine - stctl %r9,%r11,24(%r15) # We are using per stuff + stctl %r9,%r11,24(%r15) # We are using per stuff clc _TSS_PER(12,%r3),24(%r15) be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's - lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't + lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't resume_noper: stm %r6,%r15,24(%r15) # store resume registers of prev task st %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp @@ -248,7 +248,7 @@ # # call do_signal before return # -sysc_signal_return: +sysc_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset l %r1,BASED(.Ldo_signal) @@ -276,7 +276,7 @@ # call do_bottom_half and return from syscall, if interrupt-level # is zero # -sysc_handle_bottom_half: +sysc_handle_bottom_half: l %r1,BASED(.Ldo_bottom_half) la %r14,BASED(sysc_return_bh) br %r1 # call do_bottom_half @@ -284,7 +284,7 @@ # # call schedule with sysc_return as return-address # -sysc_reschedule: +sysc_reschedule: l %r1,BASED(.Lschedule) la %r14,BASED(sysc_return) br %r1 # call scheduler, return to sysc_return @@ -293,7 +293,7 @@ # a new process exits the kernel with ret_from_fork # .globl ret_from_fork -ret_from_fork: +ret_from_fork: basr %r13,0 l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base GET_CURRENT # load pointer to task_struct to R9 @@ -314,23 +314,23 @@ # but are called with different parameter. # return-address is set up above # -sys_clone_glue: +sys_clone_glue: la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lclone) br %r1 # branch to sys_clone -sys_fork_glue: +sys_fork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lfork) br %r1 # branch to sys_fork -sys_vfork_glue: +sys_vfork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lvfork) br %r1 # branch to sys_vfork -sys_execve_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs +sys_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lexecve) lr %r12,%r14 # save return address basr %r14,%r1 # call sys_execve @@ -339,12 +339,12 @@ b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8 # in system_call/sysc_tracesys -sys_sigreturn_glue: +sys_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter l %r1,BASED(.Lsigreturn) br %r1 # branch to sys_sigreturn -sys_rt_sigreturn_glue: +sys_rt_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter l %r1,BASED(.Lrt_sigreturn) br %r1 # branch to sys_sigreturn @@ -352,11 +352,11 @@ # # sigsuspend and rt_sigsuspend need pt_regs as an additional # parameter and they have to skip the store of %r2 into the -# user register %r2 because the return value was set in +# user register %r2 because the return value was set in # sigsuspend and rt_sigsuspend already and must not be overwritten! # -sys_sigsuspend_glue: +sys_sigsuspend_glue: lr %r5,%r4 # move mask back lr %r4,%r3 # move history1 parameter lr %r3,%r2 # move history0 parameter @@ -365,7 +365,7 @@ la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_sigsuspend -sys_rt_sigsuspend_glue: +sys_rt_sigsuspend_glue: lr %r4,%r3 # move sigsetsize parameter lr %r3,%r2 # move unewset parameter la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter @@ -373,6 +373,12 @@ la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_rt_sigsuspend +sys_sigaltstack_glue: + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter + l %r1,BASED(.Lsigaltstack) + br %r1 # branch to sys_sigreturn + + .globl sys_call_table sys_call_table: .long sys_ni_syscall /* 0 */ @@ -561,13 +567,13 @@ .long sys_getcwd .long sys_capget .long sys_capset /* 185 */ - .long sys_sigaltstack + .long sys_sigaltstack_glue .long sys_sendfile .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ .long sys_vfork_glue /* 190 */ .rept 255-190 - .long sys_ni_syscall + .long sys_ni_syscall .endr /* @@ -603,7 +609,7 @@ be BASED(pgm_svcper) # no interesting special case, ignore PER event lm %r13,%r15,__LC_SAVE_AREA - lpsw 0x28 + lpsw 0x28 # it was a single stepped SVC that is causing all the trouble pgm_svcper: tm 0x21,0x01 # test problem state bit @@ -622,7 +628,7 @@ la %r0,0x20 # store trap indication st %r0,SP_TRAP(%r15) xc 0(4,%r15),0(%r15) # clear back chain - mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero + mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information b BASED(pgm_system_call) # now do the svc pgm_svcret: @@ -723,7 +729,7 @@ # call do_bottom_half and return from syscall, if interrupt-level # is zero # -io_handle_bottom_half: +io_handle_bottom_half: l %r1,BASED(.Ldo_bottom_half) la %r14,BASED(io_return_bh) br %r1 # call do_bottom_half @@ -731,7 +737,7 @@ # # call schedule with io_return as return-address # -io_reschedule: +io_reschedule: l %r1,BASED(.Lschedule) la %r14,BASED(io_return) br %r1 # call scheduler, return to io_return @@ -739,7 +745,7 @@ # # call do_signal before return # -io_signal_return: +io_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset l %r1,BASED(.Ldo_signal) @@ -755,9 +761,7 @@ SAVE_ALL(0x18) la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # error code - lr %r1,%r3 # calculate index - srl %r1,8 # = (code + (code >> 8)) & 0xff - alr %r1,%r3 + lr %r1,%r3 # calculate index = code & 0xff n %r1,BASED(.Lc0xff) sll %r1,2 l %r9,BASED(.Lext_hash) @@ -773,7 +777,7 @@ ext_int_found: l %r9,4(%r9) # get handler address la %r14,BASED(io_return) - br %r9 # branch to ext call handler + br %r9 # branch to ext call handler /* * Machine check handler routines @@ -857,6 +861,7 @@ .Lrt_sigreturn:.long sys_rt_sigreturn .Lrt_sigsuspend: .long sys_rt_sigsuspend +.Lsigaltstack: .long sys_sigaltstack .Lsigreturn: .long sys_sigreturn .Lsigsuspend: .long sys_sigsuspend .Ltrace: .long syscall_trace diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S --- v2.2.17/arch/s390/kernel/head.S Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/head.S Wed Nov 8 23:09:58 2000 @@ -528,21 +528,21 @@ lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 8 -.Lentry:.long 0x04080000,0x80000000 + _stext +.Lentry:.long 0x00080000,0x80000000 + _stext .Lctl: .long 0x04b50002 # cr0: various things - .long .Lpgd+0x7f # cr1: primary space segment table + .long 0 # cr1: primary space segment table .long 0 # cr2: access register translation .long 0 # cr3: instruction authorization .long 0 # cr4: instruction authorization .long 0 # cr5: various things .long 0 # cr6: I/O interrupts - .long .Lpgd+0x7f # cr7: secondary space segment table + .long 0 # cr7: secondary space segment table .long 0 # cr8: access registers translation .long 0 # cr9: tracing off .long 0 # cr10: tracing off .long 0 # cr11: tracing off .long 0 # cr12: tracing off - .long .Lpgd+0x7f # cr13: home space segment table + .long 0 # cr13: home space segment table .long 0xc0000000 # cr14: machine check handling off .long 0 # cr15: linkage stack operations .Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem @@ -630,43 +630,4 @@ .align 8 .Ldw: .long 0x000a0000,0x00000000 -# -# tempory segment-table at 0x11000 -# - .org 0x11000 -.Lpgd: .long .Lpt0+0x1f # 00000000-000fffff - .long .Lpt1+0x1f # 00100000-001fffff - .long .Lpt2+0x1f # 00200000-002fffff - .long .Lpt3+0x1f # 00300000-003fffff - .fill 2044,4,0x20 # 00400000-7fffffff - -# -# tempory page-tables at 0x12000-0x15fff -# - .macro mktable from,to - .long \from*0x10000 - .long \from*0x10000+0x1000 - .long \from*0x10000+0x2000 - .long \from*0x10000+0x3000 - .long \from*0x10000+0x4000 - .long \from*0x10000+0x5000 - .long \from*0x10000+0x6000 - .long \from*0x10000+0x7000 - .long \from*0x10000+0x8000 - .long \from*0x10000+0x9000 - .long \from*0x10000+0xa000 - .long \from*0x10000+0xb000 - .long \from*0x10000+0xc000 - .long \from*0x10000+0xd000 - .long \from*0x10000+0xe000 - .long \from*0x10000+0xf000 - .if \to-\from - mktable "(\from+1)",\to - .endif - .endm - -.Lpt0: mktable 0,15 -.Lpt1: mktable 16,31 -.Lpt2: mktable 32,47 -.Lpt3: mktable 48,63 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c --- v2.2.17/arch/s390/kernel/irq.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/irq.c Wed Nov 8 23:04:59 2000 @@ -36,13 +36,13 @@ #include #include -unsigned long s390_init_IRQ(unsigned long); -void s390_free_irq(unsigned int irq, void *dev_id); -int s390_request_irq( unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char *devname, - void *dev_id); +unsigned long s390_init_IRQ ( unsigned long); +void s390_free_irq ( unsigned int irq, void *dev_id); +int s390_request_irq( unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id); atomic_t nmi_counter; @@ -82,7 +82,7 @@ action = ioinfo[i]->irq_desc.action; - if (!action) + if (!action) continue; p += sprintf(p, "%3d: ",i); @@ -90,8 +90,8 @@ p += sprintf(p, "%10u ", kstat_irqs(i)); #else for (j=0; jirq_desc.handler->typename); p += sprintf(p, " %s", action->name); @@ -403,13 +403,16 @@ __initfunc(unsigned long init_IRQ( unsigned long memory)) { - return s390_init_IRQ( memory); + int result; + + result=s390_init_IRQ(memory); + return result; } void free_irq(unsigned int irq, void *dev_id) { - s390_free_irq( irq, dev_id); + s390_free_irq( irq, dev_id); } @@ -419,7 +422,7 @@ const char *devname, void *dev_id) { - return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) ); + return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) ); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/mathemu.c linux/arch/s390/kernel/mathemu.c --- v2.2.17/arch/s390/kernel/mathemu.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/mathemu.c Wed Nov 8 23:09:58 2000 @@ -16,20 +16,61 @@ #include #include +#include + +#ifdef CONFIG_SYSCTL +int sysctl_ieee_emulation_warnings=1; +#endif + +#define mathemu_put_user(x, ptr) \ +{ \ + if(put_user((x),(ptr))) \ + return 1; \ +} + +#define mathemu_get_user(x, ptr) \ +{ \ + if(get_user((x),(ptr))) \ + return 1; \ +} + + +#define mathemu_copy_from_user(to,from,n) \ +{ \ + if(copy_from_user((to),(from),(n))==-EFAULT) \ + return 1; \ +} + + +#define mathemu_copy_to_user(to, from, n) \ +{ \ + if(copy_to_user((to),(from),(n))==-EFAULT) \ + return 1; \ +} + + static void display_emulation_not_implemented(char *instr) { - struct pt_regs *regs=current->tss.regs; - printk("%s not implemented\n",instr); - printk("Process with %s instruction %s (pid: %d, stackpage=%08X)\n", - instr, - current->comm, current->pid, 4096+(addr_t)current); - printk("%s's PSW: %08lx %08lx\n",instr, - (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr); + struct pt_regs *regs; + __u16 *location; + +#if CONFIG_SYSCTL + if(sysctl_ieee_emulation_warnings) +#endif + { + regs=current->tss.regs; + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n", + instr, + current->comm, current->pid); + printk("%s's PSW: %08lx %08lx\n",instr, + (unsigned long) regs->psw.mask, + (unsigned long) location); + } } -static void set_CC_df(__u64 val1,__u64 val2) { +static int set_CC_df(__u64 val1,__u64 val2) { int rc; rc = __cmpdf2(val1,val2); current->tss.regs->psw.mask &= 0xFFFFCFFF; @@ -41,9 +82,10 @@ current->tss.regs->psw.mask |= 0x00002000; break; } + return 0; } -static void set_CC_sf(__u32 val1,__u32 val2) { +static int set_CC_sf(__u32 val1,__u32 val2) { int rc; rc = __cmpsf2(val1,val2); current->tss.regs->psw.mask &= 0xFFFFCFFF; @@ -55,384 +97,473 @@ current->tss.regs->psw.mask |= 0x00002000; break; } + return 0; } -static void emu_adb (int rx, __u64 val) { +static int emu_adb (int rx, __u64 val) { current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,val); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_adbr (int rx, int ry) { +static int emu_adbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_aeb (int rx, __u32 val) { +static int emu_aeb (int rx, __u32 val) { current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,val); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_aebr (int rx, int ry) { +static int emu_aebr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_axbr (int rx, int ry) { +static int emu_axbr (int rx, int ry) { display_emulation_not_implemented("axbr"); + return 0; } -static void emu_cdb (int rx, __u64 val) { +static int emu_cdb (int rx, __u64 val) { set_CC_df(current->tss.fp_regs.fprs[rx].d,val); + return 0; } -static void emu_cdbr (int rx, int ry) { +static int emu_cdbr (int rx, int ry) { set_CC_df(current->tss.fp_regs.fprs[rx].d,current->tss.fp_regs.fprs[ry].d); + return 0; } -static void emu_cdfbr (int rx, int ry) { +static int emu_cdfbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __floatsidf(current->tss.regs->gprs[ry]); + return 0; } -static void emu_ceb (int rx, __u32 val) { +static int emu_ceb (int rx, __u32 val) { set_CC_sf(current->tss.fp_regs.fprs[rx].f,val); + return 0; } -static void emu_cebr (int rx, int ry) { +static int emu_cebr (int rx, int ry) { set_CC_sf(current->tss.fp_regs.fprs[rx].f,current->tss.fp_regs.fprs[ry].f); + return 0; } -static void emu_cefbr (int rx, int ry) { +static int emu_cefbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __floatsisf(current->tss.regs->gprs[ry]); + return 0; } -static void emu_cfdbr (int rx, int ry, int mask) { +static int emu_cfdbr (int rx, int ry, int mask) { current->tss.regs->gprs[rx] = __fixdfsi(current->tss.fp_regs.fprs[ry].d); + return 0; } -static void emu_cfebr (int rx, int ry, int mask) { +static int emu_cfebr (int rx, int ry, int mask) { current->tss.regs->gprs[rx] = __fixsfsi(current->tss.fp_regs.fprs[ry].f); + return 0; } -static void emu_cfxbr (int rx, int ry, int mask) { +static int emu_cfxbr (int rx, int ry, int mask) { display_emulation_not_implemented("cfxbr"); + return 0; } -static void emu_cxbr (int rx, int ry) { +static int emu_cxbr (int rx, int ry) { display_emulation_not_implemented("cxbr"); + return 0; } -static void emu_cxfbr (int rx, int ry) { +static int emu_cxfbr (int rx, int ry) { display_emulation_not_implemented("cxfbr"); + return 0; } -static void emu_ddb (int rx, __u64 val) { +static int emu_ddb (int rx, __u64 val) { current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,val); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_ddbr (int rx, int ry) { +static int emu_ddbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_deb (int rx, __u32 val) { +static int emu_deb (int rx, __u32 val) { current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,val); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_debr (int rx, int ry) { +static int emu_debr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_didbr (int rx, int ry, int mask) { +static int emu_didbr (int rx, int ry, int mask) { display_emulation_not_implemented("didbr"); + return 0; } -static void emu_diebr (int rx, int ry, int mask) { +static int emu_diebr (int rx, int ry, int mask) { display_emulation_not_implemented("diebr"); + return 0; } -static void emu_dxbr (int rx, int ry) { +static int emu_dxbr (int rx, int ry) { display_emulation_not_implemented("dxbr"); + return 0; } -static void emu_efpc (int rx, int ry) { - display_emulation_not_implemented("efpc"); +static int emu_efpc (int rx, int ry) { + current->tss.regs->gprs[rx]=current->tss.fp_regs.fpc; + return 0; } -static void emu_fidbr (int rx, int ry, int mask) { +static int emu_fidbr (int rx, int ry, int mask) { display_emulation_not_implemented("fidbr"); + return 0; } -static void emu_fiebr (int rx, int ry, int mask) { +static int emu_fiebr (int rx, int ry, int mask) { display_emulation_not_implemented("fiebr"); + return 0; } -static void emu_fixbr (int rx, int ry, int mask) { +static int emu_fixbr (int rx, int ry, int mask) { display_emulation_not_implemented("fixbr"); + return 0; } -static void emu_kdb (int rx, __u64 val) { +static int emu_kdb (int rx, __u64 val) { display_emulation_not_implemented("kdb"); + return 0; } -static void emu_kdbr (int rx, int ry) { +static int emu_kdbr (int rx, int ry) { display_emulation_not_implemented("kdbr"); + return 0; } -static void emu_keb (int rx, __u32 val) { +static int emu_keb (int rx, __u32 val) { display_emulation_not_implemented("keb"); + return 0; } -static void emu_kebr (int rx, int ry) { +static int emu_kebr (int rx, int ry) { display_emulation_not_implemented("kebr"); + return 0; } -static void emu_kxbr (int rx, int ry) { +static int emu_kxbr (int rx, int ry) { display_emulation_not_implemented("kxbr"); + return 0; } -static void emu_lcdbr (int rx, int ry) { +static int emu_lcdbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __negdf2(current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_lcebr (int rx, int ry) { +static int emu_lcebr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __negsf2(current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lcxbr (int rx, int ry) { +static int emu_lcxbr (int rx, int ry) { display_emulation_not_implemented("lcxbr"); + return 0; } -static void emu_ldeb (int rx, __u32 val) { +static int emu_ldeb (int rx, __u32 val) { current->tss.fp_regs.fprs[rx].d = __extendsfdf2(val); + return 0; } -static void emu_ldebr (int rx, int ry) { +static int emu_ldebr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __extendsfdf2(current->tss.fp_regs.fprs[ry].f); + return 0; } -static void emu_ldxbr (int rx, int ry) { +static int emu_ldxbr (int rx, int ry) { display_emulation_not_implemented("ldxbr"); + return 0; } -static void emu_ledbr (int rx, int ry) { +static int emu_ledbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __truncdfsf2(current->tss.fp_regs.fprs[ry].d); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lexbr (int rx, int ry) { +static int emu_lexbr (int rx, int ry) { display_emulation_not_implemented("lexbr"); + return 0; } -static void emu_lndbr (int rx, int ry) { +static int emu_lndbr (int rx, int ry) { display_emulation_not_implemented("lndbr"); + return 0; } -static void emu_lnebr (int rx, int ry) { +static int emu_lnebr (int rx, int ry) { display_emulation_not_implemented("lnebr"); + return 0; } -static void emu_lnxbr (int rx, int ry) { +static int emu_lnxbr (int rx, int ry) { display_emulation_not_implemented("lnxbr"); + return 0; } -static void emu_lpdbr (int rx, int ry) { +static int emu_lpdbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __absdf2(current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.fp_regs.fprs[rx].d,0); + return 0; } -static void emu_lpebr (int rx, int ry) { +static int emu_lpebr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __abssf2(current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lpxbr (int rx, int ry) { +static int emu_lpxbr (int rx, int ry) { display_emulation_not_implemented("lpxbr"); + return 0; } -static void emu_ltdbr (int rx, int ry) { +static int emu_ltdbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = current->tss.fp_regs.fprs[ry].d; set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_ltebr (int rx, int ry) { +static int emu_ltebr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = current->tss.fp_regs.fprs[ry].f; set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_ltxbr (int rx, int ry) { +static int emu_ltxbr (int rx, int ry) { display_emulation_not_implemented("ltxbr"); + return 0; } -static void emu_lxdb (int rx, __u64 val) { +static int emu_lxdb (int rx, __u64 val) { display_emulation_not_implemented("lxdb"); + return 0; } -static void emu_lxdbr (int rx, int ry) { +static int emu_lxdbr (int rx, int ry) { display_emulation_not_implemented("lxdbr"); + return 0; } -static void emu_lxeb (int rx, __u32 val) { +static int emu_lxeb (int rx, __u32 val) { display_emulation_not_implemented("lxeb"); + return 0; } -static void emu_lxebr (int rx, int ry) { +static int emu_lxebr (int rx, int ry) { display_emulation_not_implemented("lxebr"); + return 0; } -static void emu_madb (int rx, __u64 val, int mask) { +static int emu_madb (int rx, __u64 val, int mask) { display_emulation_not_implemented("madb"); + return 0; } -static void emu_madbr (int rx, int ry, int mask) { +static int emu_madbr (int rx, int ry, int mask) { display_emulation_not_implemented("madbr"); + return 0; } -static void emu_maeb (int rx, __u32 val, int mask) { +static int emu_maeb (int rx, __u32 val, int mask) { display_emulation_not_implemented("maeb"); + return 0; } -static void emu_maebr (int rx, int ry, int mask) { +static int emu_maebr (int rx, int ry, int mask) { display_emulation_not_implemented("maebr"); + return 0; } -static void emu_mdb (int rx, __u64 val) { +static int emu_mdb (int rx, __u64 val) { current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,val); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_mdbr (int rx, int ry) { +static int emu_mdbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_mdeb (int rx, __u32 val) { +static int emu_mdeb (int rx, __u32 val) { display_emulation_not_implemented("mdeb"); + return 0; } -static void emu_mdebr (int rx, int ry) { +static int emu_mdebr (int rx, int ry) { display_emulation_not_implemented("mdebr"); + return 0; } -static void emu_meeb (int rx, __u32 val) { +static int emu_meeb (int rx, __u32 val) { current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f, val); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_meebr (int rx, int ry) { +static int emu_meebr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_msdb (int rx, __u64 val, int mask) { +static int emu_msdb (int rx, __u64 val, int mask) { display_emulation_not_implemented("msdb"); + return 0; } -static void emu_msdbr (int rx, int ry, int mask) { +static int emu_msdbr (int rx, int ry, int mask) { display_emulation_not_implemented("msdbr"); + return 0; } -static void emu_mseb (int rx, __u32 val, int mask) { +static int emu_mseb (int rx, __u32 val, int mask) { display_emulation_not_implemented("mseb"); + return 0; } -static void emu_msebr (int rx, int ry, int mask) { +static int emu_msebr (int rx, int ry, int mask) { display_emulation_not_implemented("msebr"); + return 0; } -static void emu_mxbr (int rx, int ry) { +static int emu_mxbr (int rx, int ry) { display_emulation_not_implemented("mxbr"); + return 0; } -static void emu_mxdb (int rx, __u64 val) { +static int emu_mxdb (int rx, __u64 val) { display_emulation_not_implemented("mxdb"); + return 0; } -static void emu_mxdbr (int rx, int ry) { +static int emu_mxdbr (int rx, int ry) { display_emulation_not_implemented("mxdbr"); + return 0; } -static void emu_sdb (int rx, __u64 val) { +static int emu_sdb (int rx, __u64 val) { current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d, val); set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_sdbr (int rx, int ry) { +static int emu_sdbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_seb (int rx, __u32 val) { +static int emu_seb (int rx, __u32 val) { current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f, val); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_sebr (int rx, int ry) { +static int emu_sebr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_sfpc (int rx, int ry) { - display_emulation_not_implemented("sfpc"); +static int emu_sfpc (int rx, int ry) { + __u32 val=current->tss.regs->gprs[rx]; + if(val==0) + current->tss.fp_regs.fpc=val; + else + display_emulation_not_implemented("sfpc"); + return 0; } -static void emu_sqdb (int rx, __u64 val) { +static int emu_sqdb (int rx, __u64 val) { display_emulation_not_implemented("sqdb"); + return 0; } -static void emu_sqdbr (int rx, int ry) { +static int emu_sqdbr (int rx, int ry) { display_emulation_not_implemented("sqdbr"); + return 0; } -static void emu_sqeb (int rx, __u32 val) { +static int emu_sqeb (int rx, __u32 val) { display_emulation_not_implemented("sqeb"); + return 0; } -static void emu_sqebr (int rx, int ry) { +static int emu_sqebr (int rx, int ry) { display_emulation_not_implemented("sqebr"); + return 0; } -static void emu_sqxbr (int rx, int ry) { +static int emu_sqxbr (int rx, int ry) { display_emulation_not_implemented("sqxbr"); + return 0; } -static void emu_sxbr (int rx, int ry) { +static int emu_sxbr (int rx, int ry) { display_emulation_not_implemented("sxbr"); + return 0; } -static void emu_tcdb (int rx, __u64 val) { +static int emu_tcdb (int rx, __u64 val) { display_emulation_not_implemented("tcdb"); + return 0; } -static void emu_tceb (int rx, __u32 val) { +static int emu_tceb (int rx, __u32 val) { display_emulation_not_implemented("tceb"); + return 0; } -static void emu_tcxb (int rx, __u64 val) { +static int emu_tcxb (int rx, __u64 val) { display_emulation_not_implemented("tcxb"); + return 0; } @@ -486,6 +617,7 @@ } int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { + int rc=0; static const __u8 format_table[] = { 2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3, @@ -551,84 +683,82 @@ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + emu_load_regd(opcode[3]&15); + return rc; case 2: /* RRE format, float operation */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + emu_load_rege(opcode[3]&15); + return rc; case 3: /* RRF format, double operation */ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + emu_load_regd(opcode[3]&15); + return rc; case 4: /* RRF format, float operation */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + emu_load_rege(opcode[3]&15); + return rc; case 5: /* RRE format, cefbr instruction */ emu_store_rege((opcode[3]>>4)&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + return rc; case 6: /* RRE format, cdfbr & cxfbr instruction */ emu_store_regd((opcode[3]>>4)&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return 0; - /* FIXME !! */ - return 0; - case 7: /* RRF format, cfebr instruction */ + emu_load_regd((opcode[3]>>4)&15); + return rc; + case 7: /* RRF format, cfebr instruction */ emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return 0; + return rc; case 8: /* RRF format, cfdbr & cfxbr instruction */ emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return 0; + return rc; case 9: /* RRE format, ldebr & mdebr instruction */ /* float store but double load */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + return rc; case 10: /* RRE format, ledbr instruction */ /* double store but float load */ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + return rc; default: return 1; } @@ -645,6 +775,8 @@ } int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { + int rc=0; + static const __u8 format_table[] = { 0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4, 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3, @@ -682,13 +814,12 @@ emu_store_regd((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(&temp, dxb, 8); + mathemu_copy_from_user(&temp, dxb, 8); /* call the emulation function */ - ((void (*)(int, __u64))jump_table[opcode[5]]) + rc=((int (*)(int, __u64))jump_table[opcode[5]]) (opcode[1]>>4,temp); - emu_load_regd((opcode[1]>>4)&15); - return 0; + emu_load_regd((opcode[1]>>4)&15); + return rc; } case 2: /* RXE format, __u32 constant */ { __u32 *dxb, temp; @@ -697,13 +828,12 @@ emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32))jump_table[opcode[5]]) + rc=((int (*)(int, __u32))jump_table[opcode[5]]) (opcode[1]>>4,temp); - emu_load_rege((opcode[1]>>4)&15); - return 0; + emu_load_rege((opcode[1]>>4)&15); + return rc; } case 3: /* RXF format, __u64 constant */ { __u32 *dxb, temp; @@ -712,13 +842,12 @@ emu_store_regd((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(&temp, dxb, 8); + mathemu_copy_from_user(&temp, dxb, 8); /* call the emulation function */ - ((void (*)(int, __u32, int))jump_table[opcode[5]]) + rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) (opcode[1]>>4,temp,opcode[4]>>4); - emu_load_regd((opcode[1]>>4)&15); - return 0; + emu_load_regd((opcode[1]>>4)&15); + return rc; } case 4: /* RXF format, __u32 constant */ { __u32 *dxb, temp; @@ -727,29 +856,27 @@ emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32, int))jump_table[opcode[5]]) + rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) (opcode[1]>>4,temp,opcode[4]>>4); emu_load_rege((opcode[1]>>4)&15); - return 0; + return rc; } case 5: /* RXE format, __u32 constant */ /* store_rege and load_regd */ - { + { __u32 *dxb, temp; __u32 opc; emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32))jump_table[opcode[5]]) + rc=((int (*)(int, __u32))jump_table[opcode[5]]) (opcode[1]>>4,temp); emu_load_regd((opcode[1]>>4)&15); - return 0; + return rc; } default: return 1; @@ -759,7 +886,7 @@ /* * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6} */ -void math_emu_ldr(__u8 *opcode) { +int math_emu_ldr(__u8 *opcode) { __u16 opc = *((__u16 *) opcode); if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ @@ -785,12 +912,13 @@ current->tss.fp_regs.fprs[(opc&0x00f0)>>4] = current->tss.fp_regs.fprs[opc&0x000f]; } + return 0; } /* * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6} */ -void math_emu_ler(__u8 *opcode) { +int math_emu_ler(__u8 *opcode) { __u16 opc = *((__u16 *) opcode); if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ @@ -816,61 +944,68 @@ current->tss.fp_regs.fprs[(opc&0x00f0)>>4] = current->tss.fp_regs.fprs[opc&0x000f]; } + return 0; } /* * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_ld(__u8 *opcode, struct pt_regs * regs) { +int math_emu_ld(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u64 *dxb; dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(¤t->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); + mathemu_copy_from_user(¤t->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); + return 0; } /* * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_le(__u8 *opcode, struct pt_regs * regs) { +int math_emu_le(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u32 *mem, *dxb; dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ mem = (__u32 *) (¤t->tss.fp_regs.fprs[(opc>>20)&15].f); - get_user(mem[0], dxb); + mathemu_get_user(mem[0], dxb); + return 0; } /* * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_std(__u8 *opcode, struct pt_regs * regs) { +int math_emu_std(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u64 *dxb; dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_to_user fails ? */ - copy_to_user(dxb, ¤t->tss.fp_regs.fprs[(opc>>20)&15].d, 8); + mathemu_copy_to_user(dxb, ¤t->tss.fp_regs.fprs[(opc>>20)&15].d, 8); + return 0; } /* * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_ste(__u8 *opcode, struct pt_regs * regs) { +int math_emu_ste(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u32 *mem, *dxb; dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if put_user fails ? */ + /* FIXME: how to react if mathemu_put_user fails ? */ mem = (__u32 *) (¤t->tss.fp_regs.fprs[(opc>>20)&15].f); - put_user(mem[0], dxb); + mathemu_put_user(mem[0], dxb); + return 0; } /* * Emulate LFPC D(B) */ int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { - /* FIXME: how to do that ?!? */ + __u32 *dxb,temp; + __u32 opc = *((__u32 *) opcode); + dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); + mathemu_get_user(temp, dxb); + if(temp!=0) + display_emulation_not_implemented("lfpc"); return 0; } @@ -878,7 +1013,10 @@ * Emulate STFPC D(B) */ int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { - /* FIXME: how to do that ?!? */ + __u32 *dxb; + __u32 opc = *((__u32 *) opcode); + dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); + mathemu_put_user(current->tss.fp_regs.fpc, dxb); return 0; } @@ -887,6 +1025,7 @@ */ int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) { /* FIXME: how to do that ?!? */ + display_emulation_not_implemented("srnm"); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c --- v2.2.17/arch/s390/kernel/process.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/process.c Wed Nov 8 23:09:58 2000 @@ -76,7 +76,9 @@ if (bh_mask & bh_active) { #endif do_bottom_half(); - continue; + __sti(); + if (!current->need_resched) + continue; } if (current->need_resched) { schedule(); @@ -109,11 +111,13 @@ 0 returned you know you've got all the lines */ -int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_struct *tss,struct pt_regs * regs) -{ +static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs) +{ int linelen=0; int regno,chaincnt; u32 backchain,prev_backchain,endchain; + u32 ksp = 0; + char *mode = "???"; enum { @@ -134,34 +138,36 @@ sp_kern_backchain1 }; - if(task) - tss=&task->tss; - if(tss) - regs=tss->regs; + if (task) + ksp = task->tss.ksp; + if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE)) + ksp = regs->gprs[15]; + + if (regs) + mode = (regs->psw.mask & PSW_PROBLEM_STATE)? + "User" : "Kernel"; + switch(line) { - case sp_linefeed: linelen=sprintf(buff,"\n"); + case sp_linefeed: + linelen=sprintf(buff,"\n"); break; case sp_psw: if(regs) - linelen=sprintf(buff,"User PSW: %08lx %08lx\n", + linelen=sprintf(buff, "%s PSW: %08lx %08lx\n", mode, (unsigned long) regs->psw.mask, (unsigned long) regs->psw.addr); else linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n"); break; case sp_ksp: - if(task) - linelen+=sprintf(&buff[linelen],"task: %08x ",(addr_t)task); - if(tss) - linelen+=sprintf(&buff[linelen],"tss: %08x ksp: %08x ", - (addr_t)tss,(addr_t)tss->ksp); - if(regs) - linelen+=sprintf(&buff[linelen],"pt_regs: %08x\n",(addr_t)regs); + linelen=sprintf(&buff[linelen], + "task: %08x ksp: %08x pt_regs: %08x\n", + (addr_t)task, (addr_t)ksp, (addr_t)regs); break; case sp_gprs: if(regs) - linelen=sprintf(buff,"User GPRS:\n"); + linelen=sprintf(buff, "%s GPRS:\n", mode); break; case sp_gprs1 ... sp_gprs4: if(regs) @@ -176,7 +182,7 @@ break; case sp_acrs: if(regs) - linelen=sprintf(buff,"User ACRS:\n"); + linelen=sprintf(buff, "%s ACRS:\n", mode); break; case sp_acrs1 ... sp_acrs4: if(regs) @@ -190,14 +196,14 @@ } break; case sp_kern_backchain: - if(tss&&tss->ksp&®s) - linelen=sprintf(buff,"Kernel BackChain CallChain BackChain CallChain\n"); + if (ksp) + linelen=sprintf(buff, "Kernel BackChain CallChain\n"); break; default: - if(tss&&tss->ksp&®s) + if (ksp) { - backchain=(tss->ksp&PSW_ADDR_MASK); + backchain=ksp&PSW_ADDR_MASK; endchain=((backchain&(-8192))+8192); prev_backchain=backchain-1; line-=sp_kern_backchain1; @@ -206,34 +212,48 @@ if((backchain==0)||(backchain>=endchain) ||(chaincnt>=8)||(prev_backchain>=backchain)) break; - if((chaincnt>>1)==line) + if(chaincnt==line) { - linelen+=sprintf(&buff[linelen],"%s%08x %08x ", - (chaincnt&1) ? "":" ", - backchain,*(u32 *)(backchain+56)); - } - if((chaincnt>>1)>line) + linelen+=sprintf(&buff[linelen]," %08x [<%08x>]\n", + backchain, + *(u32 *)(backchain+56)&PSW_ADDR_MASK); break; + } prev_backchain=backchain; backchain=(*((u32 *)backchain))&PSW_ADDR_MASK; } - if(linelen) - linelen+=sprintf(&buff[linelen],"\n"); } } return(linelen); } -void show_regs(struct task_struct * task,struct thread_struct *tss,struct pt_regs *regs) +void show_regs(struct pt_regs *regs) { char buff[80]; int line; + + printk("CPU: %d\n",smp_processor_id()); + printk("Process %s (pid: %d, stackpage=%08X)\n", + current->comm, current->pid, 4096+(addr_t)current); - for(line=0;sprintf_regs(line,buff,task,tss,regs);line++) + for (line = 0; sprintf_regs(line, buff, current, regs); line++) printk(buff); } +char *task_show_regs(struct task_struct *task, char *buffer) +{ + int line, len; + + for (line = 0; ; line++) + { + len = sprintf_regs(line, buffer, task, task->tss.regs); + if (!len) break; + buffer += len; + } + return buffer; +} + int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int clone_arg = flags | CLONE_VM; @@ -283,15 +303,15 @@ struct task_struct * p, struct pt_regs * regs) { struct stack_frame - { - unsigned long back_chain; - unsigned long eos; - unsigned long glue1; - unsigned long glue2; - unsigned long scratch[2]; - unsigned long gprs[10]; /* gprs 6 -15 */ - unsigned long fprs[4]; /* fpr 4 and 6 */ - unsigned long empty[4]; + { + unsigned long back_chain; + unsigned long eos; + unsigned long glue1; + unsigned long glue2; + unsigned long scratch[2]; + unsigned long gprs[10]; /* gprs 6 -15 */ + unsigned long fprs[4]; /* fpr 4 and 6 */ + unsigned long empty[4]; #if CONFIG_REMOTE_DEBUG gdb_pt_regs childregs; #else @@ -344,7 +364,7 @@ lock_kernel(); clone_flags = regs.gprs[3]; - newsp = regs.gprs[2]; + newsp = regs.orig_gpr2; if (!newsp) newsp = regs.gprs[15]; ret = do_fork(clone_flags, newsp, ®s); @@ -383,7 +403,19 @@ goto out; error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], ®s); if (error == 0) + { current->flags &= ~PF_DTRACE; + current->tss.fp_regs.fpc=0; + if(MACHINE_HAS_IEEE) + { + __asm__ __volatile__ + ("sr 0,0\n\t" + "sfpc 0,0\n\t" + : + : + :"0"); + } + } putname(filename); out: unlock_kernel(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c --- v2.2.17/arch/s390/kernel/ptrace.c Sun Jun 11 21:44:09 2000 +++ linux/arch/s390/kernel/ptrace.c Wed Nov 8 23:04:59 2000 @@ -229,7 +229,7 @@ struct vm_area_struct * vma; addr=ADDR_BITS_REMOVE(addr); vma= find_extend_vma(tsk, addr); - + if (!vma) return -EIO; if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { @@ -478,15 +478,15 @@ /* ieee_instruction_pointer from the user structure DJB */ if(child!=current) { - if (!(child->flags & PF_PTRACED)) - goto out; - if (child->state != TASK_STOPPED) - { - if (request != PTRACE_KILL) + if (!(child->flags & PF_PTRACED)) + goto out; + if (child->state != TASK_STOPPED) + { + if (request != PTRACE_KILL) + goto out; + } + if (child->p_pptr != current) goto out; - } - if (child->p_pptr != current) - goto out; } switch (request) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c --- v2.2.17/arch/s390/kernel/s390_ext.c Sun Jun 11 21:44:09 2000 +++ linux/arch/s390/kernel/s390_ext.c Wed Nov 8 23:09:58 2000 @@ -13,7 +13,7 @@ #include /* - * Simple hash strategy: index = ((code >> 8) + code) & 0xff; + * Simple hash strategy: index = code & 0xff; * ext_int_hash[index] is the start of the list for all external interrupts * that hash to this index. With the current set of external interrupts * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000 @@ -27,7 +27,7 @@ ext_int_info_t *p; int index; - index = (code + (code >> 8)) & 0xff; + index = code & 0xff; p = ext_int_hash[index]; while (p != NULL) { if (p->code == code) @@ -54,7 +54,7 @@ ext_int_info_t *p, *q; int index; - index = (code + (code >> 8)) & 0xff; + index = code & 0xff; q = NULL; p = ext_int_hash[index]; while (p != NULL) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c --- v2.2.17/arch/s390/kernel/s390_ksyms.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/s390_ksyms.c Wed Nov 8 23:09:58 2000 @@ -5,20 +5,18 @@ */ #include #include +#include #include #include #include #include #include -#include +#include #include #include #include #include #include -#if CONFIG_CHANDEV -#include -#endif #if CONFIG_IP_MULTICAST #include #endif @@ -27,6 +25,7 @@ * I/O subsystem */ EXPORT_SYMBOL(halt_IO); +EXPORT_SYMBOL(clear_IO); EXPORT_SYMBOL(do_IO); EXPORT_SYMBOL(resume_IO); EXPORT_SYMBOL(ioinfo); @@ -42,21 +41,31 @@ EXPORT_SYMBOL(s390_device_register); EXPORT_SYMBOL(s390_device_unregister); +EXPORT_SYMBOL(s390_bh_lock); + EXPORT_SYMBOL(ccw_alloc_request); EXPORT_SYMBOL(ccw_free_request); EXPORT_SYMBOL(register_external_interrupt); EXPORT_SYMBOL(unregister_external_interrupt); -/* +/* * debug feature */ EXPORT_SYMBOL(debug_register); EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); EXPORT_SYMBOL(debug_event); +EXPORT_SYMBOL(debug_int_event); EXPORT_SYMBOL(debug_text_event); EXPORT_SYMBOL(debug_exception); +EXPORT_SYMBOL(debug_int_exception); EXPORT_SYMBOL(debug_text_exception); +EXPORT_SYMBOL(debug_hex_view); +EXPORT_SYMBOL(debug_ascii_view); +EXPORT_SYMBOL(debug_ebcdic_view); +EXPORT_SYMBOL(debug_dflt_header_fn); /* * memory management @@ -81,6 +90,7 @@ EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); +EXPORT_SYMBOL_NOVERS(strstr); EXPORT_SYMBOL_NOVERS(_ascebc_500); EXPORT_SYMBOL_NOVERS(_ebcasc_500); @@ -92,6 +102,8 @@ /* * misc. */ +EXPORT_SYMBOL(__copy_from_user_fixup); +EXPORT_SYMBOL(__copy_to_user_fixup); EXPORT_SYMBOL(__udelay); #ifdef CONFIG_SMP #include @@ -104,12 +116,13 @@ EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(smp_ctl_set_bit); EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_do_callback_all); #endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(genhd_dasd_name); -#if CONFIG_IP_MULTICAST +#ifdef CONFIG_IP_MULTICAST /* Required for lcs gigibit ethernet multicast support */ EXPORT_SYMBOL(arp_mc_map); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/s390dyn.c linux/arch/s390/kernel/s390dyn.c --- v2.2.17/arch/s390/kernel/s390dyn.c Sun Jun 11 21:44:09 2000 +++ linux/arch/s390/kernel/s390dyn.c Wed Nov 8 23:04:59 2000 @@ -3,7 +3,7 @@ * S/390 dynamic device attachment * * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/s390fpu.c linux/arch/s390/kernel/s390fpu.c --- v2.2.17/arch/s390/kernel/s390fpu.c Fri Apr 21 12:45:48 2000 +++ linux/arch/s390/kernel/s390fpu.c Wed Nov 8 23:09:58 2000 @@ -80,6 +80,11 @@ { int has_ieee=MACHINE_HAS_IEEE; + /* If we don't mask with the FPC_VALID_MASK here + * we've got a very quick shutdown -h now command + * via a kernel specification exception. + */ + fpregs->fpc&=FPC_VALID_MASK; asm volatile ("LD 0,8(%0)\n\t" "LD 2,24(%0)\n\t" "LD 4,40(%0)\n\t" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c --- v2.2.17/arch/s390/kernel/s390io.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/s390io.c Wed Nov 8 23:09:58 2000 @@ -33,16 +33,16 @@ #include #include -#undef CONFIG_DEBUG_IO +#undef CONFIG_DEBUG_IO #define CONFIG_DEBUG_CRW #define REIPL_DEVID_MAGIC 0x87654321 struct s390_irqaction init_IRQ_action; -unsigned int highest_subchannel; -ioinfo_t *ioinfo_head = NULL; -ioinfo_t *ioinfo_tail = NULL; -ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = { +unsigned int highest_subchannel; +ioinfo_t *ioinfo_head = NULL; +ioinfo_t *ioinfo_tail = NULL; +ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = { [0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA }; @@ -83,9 +83,9 @@ int s390_DevicePathVerification( int irq, __u8 domask ); -extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs); -extern int enable_none(unsigned int irq); -extern int disable_none(unsigned int irq); +extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs); +extern int enable_none(unsigned int irq); +extern int disable_none(unsigned int irq); extern void tod_wait(unsigned long usecs); asmlinkage void do_IRQ( struct pt_regs regs, @@ -124,9 +124,9 @@ int s390_request_irq_special( int irq, io_handler_func_t io_handler, not_oper_handler_func_t not_oper_handler, - unsigned long irqflags, - const char *devname, - void *dev_id) + unsigned long irqflags, + const char *devname, + void *dev_id) { int retval; struct s390_irqaction *action; @@ -137,35 +137,35 @@ if ( !io_handler || !dev_id ) return -EINVAL; - /* - * during init_IRQ() processing we don't have memory - * management yet, thus need to use a statically - * allocated irqaction control block - */ - if ( init_IRQ_complete ) - { + /* + * during init_IRQ() processing we don't have memory + * management yet, thus need to use a statically + * allocated irqaction control block + */ + if ( init_IRQ_complete ) + { action = (struct s390_irqaction *) kmalloc( sizeof(struct s390_irqaction), GFP_KERNEL); - } - else - { - action = &init_IRQ_action; + } + else + { + action = &init_IRQ_action; - } /* endif */ + } /* endif */ if (!action) - { + { return -ENOMEM; - } /* endif */ + } /* endif */ action->handler = io_handler; action->flags = irqflags; action->name = devname; action->dev_id = dev_id; - retval = s390_setup_irq(irq, action); + retval = s390_setup_irq( irq, action); if ( init_IRQ_complete ) { @@ -174,10 +174,10 @@ s390_DevicePathVerification( irq, 0 ); } else - { - kfree(action); + { + kfree(action); - } /* endif */ + } /* endif */ } /* endif */ @@ -228,7 +228,7 @@ } /* endif */ - s390irq_spin_lock_irqsave(irq,flags); + s390irq_spin_lock_irqsave( irq, flags); #ifdef CONFIG_KERNEL_DEBUG if ( irq != cons_dev ) @@ -251,7 +251,7 @@ ioinfo[irq]->ui.flags.unready = 1; do - { + { ret = disable_subchannel( irq); count++; @@ -305,15 +305,15 @@ disable_subchannel( irq); if ( ioinfo[irq]->ui.flags.busy ) - { - printk( KERN_CRIT"free_irq(%04X) " - "- device %04X busy, retry " - "count exceeded\n", - irq, - ioinfo[irq]->devstat.devno); - - } /* endif */ + { + printk( KERN_CRIT"free_irq(%04X) " + "- device %04X busy, retry " + "count exceeded\n", + irq, + ioinfo[irq]->devstat.devno); + } /* endif */ + break; /* sigh, let's give up ... */ } /* endif */ @@ -325,11 +325,11 @@ if ( init_IRQ_complete ) kfree( ioinfo[irq]->irq_desc.action ); - ioinfo[irq]->irq_desc.action = NULL; - ioinfo[irq]->ui.flags.ready = 0; + ioinfo[irq]->irq_desc.action = NULL; + ioinfo[irq]->ui.flags.ready = 0; ioinfo[irq]->irq_desc.handler->enable = enable_none; ioinfo[irq]->irq_desc.handler->disable = disable_none; - ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ + ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ ioinfo[irq]->nopfunc = NULL; @@ -405,15 +405,15 @@ */ static int enable_subchannel( unsigned int irq) { - int ret; - int ccode; - int retry = 5; + int ret; + int ccode; + int retry = 5; - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); + if ( irq > highest_subchannel || irq < 0 ) + { + return( -ENODEV ); - } /* endif */ + } /* endif */ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) return( -ENODEV); @@ -425,18 +425,18 @@ if ( ioinfo[irq]->ui.flags.d_disable ) { ioinfo[irq]->ui.flags.d_disable = 0; - ret = 0; + ret = 0; } else { ccode = stsch(irq, &(ioinfo[irq]->schib) ); - if ( ccode ) - { - ret = -ENODEV; - } - else - { + if ( ccode ) + { + ret = -ENODEV; + } + else + { ioinfo[irq]->schib.pmcw.ena = 1; if ( irq == cons_dev ) @@ -445,28 +445,28 @@ } else { - ioinfo[irq]->schib.pmcw.isc = 3; + ioinfo[irq]->schib.pmcw.isc = 3; } /* endif */ - do - { + do + { ccode = msch( irq, &(ioinfo[irq]->schib) ); - switch (ccode) { - case 0: - ret = 0; - break; + switch (ccode) { + case 0: + ret = 0; + break; - case 1: - /* + case 1: + /* * very bad, requires interrupt alike * processing, where "rbh" is a dummy * parameter for interface compatibility * only. Bottom-half handling cannot be * required as this must be an * unsolicited interrupt (!busy). - */ + */ ioinfo[irq]->ui.flags.s_pend = 1; s390_process_IRQ( irq ); @@ -475,8 +475,8 @@ ret = -EIO; /* might be overwritten */ /* ... on re-driving */ /* ... the msch() */ - retry--; - break; + retry--; + break; case 2: tod_wait(100); /* allow for recovery */ @@ -484,24 +484,24 @@ retry--; break; - case 3: + case 3: ioinfo[irq]->ui.flags.oper = 0; - ret = -ENODEV; - break; + ret = -ENODEV; + break; - default: + default: printk( KERN_CRIT"enable_subchannel(%04X) " " : ccode 2 on msch() for device " "%04X received !\n", irq, ioinfo[irq]->devstat.devno); - ret = -ENODEV; // never reached - } + ret = -ENODEV; // never reached + } - } while ( (ccode == 1) && retry ); + } while ( (ccode == 1) && retry ); - } /* endif */ + } /* endif */ } /* endif */ @@ -514,9 +514,9 @@ */ static int disable_subchannel( unsigned int irq) { - int cc; /* condition code */ - int ret; /* function return value */ - int retry = 5; + int cc; /* condition code */ + int ret; /* function return value */ + int retry = 5; if ( irq > highest_subchannel ) { @@ -525,7 +525,7 @@ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); - } + } else if ( ioinfo[irq]->ui.flags.busy ) { /* @@ -554,17 +554,17 @@ { ioinfo[irq]->schib.pmcw.ena = 0; - do - { + do + { cc = msch( irq, &(ioinfo[irq]->schib) ); - switch (cc) { - case 0 : - ret = 0; /* done */ - break; + switch (cc) { + case 0 : + ret = 0; /* done */ + break; - case 1 : - /* + case 1 : + /* * very bad, requires interrupt alike * processing, where "rbh" is a dummy * parm for interface compatibility @@ -577,46 +577,46 @@ ioinfo[irq]->ui.flags.s_pend = 0; ret = -EIO; /* might be overwritten */ - /* ... on re-driving the */ - /* ... msch() call */ - retry--; - break; - - case 2 : - /* - * *** must not occur ! *** - * *** *** + /* ... on re-driving the */ + /* ... msch() call */ + retry--; + break; + + case 2 : + /* + * *** must not occur ! *** + * *** *** * *** indicates our internal *** * *** interrupt accounting is out *** - * *** of sync ===> panic() *** - */ + * *** of sync ===> panic() *** + */ printk( KERN_CRIT"disable_subchannel(%04X) " "- unexpected busy condition for " "device %04X received !\n", irq, ioinfo[irq]->devstat.devno); ret = -EBUSY; - break; + break; - case 3 : - /* + case 3 : + /* * should hardly occur ?! - */ + */ ioinfo[irq]->ui.flags.oper = 0; ioinfo[irq]->ui.flags.d_disable = 1; ret = 0; /* if the device has gone we */ /* ... don't need to disable */ /* ... it anymore ! */ - break; + break; - default : - ret = -ENODEV; // never reached ... - break; + default : + ret = -ENODEV; // never reached ... + break; - } /* endswitch */ + } /* endswitch */ - } while ( (cc == 1) && retry ); + } while ( (cc == 1) && retry ); } /* endif */ @@ -716,10 +716,10 @@ * As we don't know about the calling environment * we assure running disabled. Before leaving the * function we resestablish the old environment. - * - * Note : as we don't need a system wide lock, therefore - * we shouldn't use cli(), but __cli() as this - * affects the current CPU only. + * + * Note : as we don't need a system wide lock, therefore + * we shouldn't use cli(), but __cli() as this + * affects the current CPU only. */ __save_flags(flags); __cli(); @@ -730,7 +730,7 @@ cr6 = 0; asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - s390_process_subchannels(); + s390_process_subchannels(); /* * enable default I/O-interrupt sublass 3 @@ -740,7 +740,7 @@ s390_device_recognition_all(); - init_IRQ_complete = 1; + init_IRQ_complete = 1; __restore_flags(flags); @@ -788,7 +788,7 @@ ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH); ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE); ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND ) - && (flag & DOIO_SUPPRESS_INTER) ); + && (flag & DOIO_SUPPRESS_INTER) ); if ( flag & DOIO_VALID_LPM ) { @@ -800,7 +800,7 @@ } /* endif */ - ioinfo[irq]->orb.cpa = (ccw1_t *)virt_to_phys( cpa); + ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa); /* * If sync processing was requested we lock the sync ISC, modify the @@ -849,7 +849,7 @@ case 0: if ( !ioinfo[irq]->ui.flags.w4sense ) - { + { /* * init the device driver specific devstat irb area * @@ -895,7 +895,7 @@ } /* endif */ ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm; - + /* * If synchronous I/O processing is requested, we have * to wait for the corresponding interrupt to occur by @@ -906,54 +906,54 @@ */ if ( flag & DOIO_WAIT_FOR_INTERRUPT ) { - int io_sub = -1; - psw_t io_new_psw; - int ccode; + psw_t io_new_psw; + int ccode; uint64_t time_start; uint64_t time_curr; - int ready = 0; - struct _lowcore *lc = NULL; + int ready = 0; + int io_sub = -1; + struct _lowcore *lc = NULL; int do_retry = 1; - /* + /* * We shouldn't perform a TPI loop, waiting for an * interrupt to occur, but should load a WAIT PSW * instead. Otherwise we may keep the channel subsystem * busy, not able to present the interrupt. When our * sync. interrupt arrived we reset the I/O old PSW to * its original value. - */ - memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t)); + */ + memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t)); ccode = iac(); switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "start_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; + case 0: // primary-space + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_PRIM_SPACE_MODE + | _PSW_IO_WAIT; + break; + case 1: // secondary-space + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_SEC_SPACE_MODE + | _PSW_IO_WAIT; + break; + case 2: // access-register + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_ACC_REG_MODE + | _PSW_IO_WAIT; + break; + case 3: // home-space + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_HOME_SPACE_MODE + | _PSW_IO_WAIT; + break; + default: + panic( "start_IO() : unexpected " + "address-space-control %d\n", + ccode); + break; } /* endswitch */ io_sync_wait.addr = FIX_PSW(&&io_wakeup); @@ -974,8 +974,8 @@ { tpi_info_t tpi_info; - do - { + do + { if ( tpi(&tpi_info) == 1 ) { io_sub = tpi_info.irq; @@ -990,20 +990,20 @@ do_retry = 0; } /* endif */ - + } while ( do_retry ); } else { - asm volatile ( "lpsw %0" : : "m" (io_sync_wait) ); + asm volatile ("lpsw %0" : : "m" (io_sync_wait)); io_wakeup: - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; + io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; } /* endif */ if ( do_retry ) - ready = s390_process_IRQ( io_sub ); + ready = s390_process_IRQ( io_sub ); /* * surrender when retry count's exceeded ... @@ -1032,9 +1032,9 @@ memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, '\0', sizeof( irb_t) ); - /* - * Let the common interrupt handler process the pending status. - * However, we must avoid calling the user action handler, as + /* + * Let the common interrupt handler process the pending status. + * However, we must avoid calling the user action handler, as * it won't be prepared to handle a pending status during * do_IO() processing inline. This also implies that process_IRQ * must terminate synchronously - especially if device sensing @@ -1076,8 +1076,8 @@ if ( ioinfo[irq]->opm == 0 ) { - ret = -ENODEV; - ioinfo[irq]->ui.flags.oper = 0; + ret = -ENODEV; + ioinfo[irq]->ui.flags.oper = 0; } else { @@ -1088,12 +1088,12 @@ ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; #ifdef CONFIG_DEBUG_IO - { - char buffer[80]; + { + char buffer[80]; stsch(irq, &(ioinfo[irq]->schib) ); - sprintf( buffer, "s390_start_IO(%04X) - irb for " + sprintf( buffer, "s390_start_IO(%04X) - irb for " "device %04X, after status pending\n", irq, ioinfo[irq]->devstat.devno ); @@ -1102,7 +1102,7 @@ &(ioinfo[irq]->devstat.ii.irb) , sizeof(irb_t)); - sprintf( buffer, "s390_start_IO(%04X) - schib for " + sprintf( buffer, "s390_start_IO(%04X) - schib for " "device %04X, after status pending\n", irq, ioinfo[irq]->devstat.devno ); @@ -1113,7 +1113,7 @@ if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) - { + { sprintf( buffer, "s390_start_IO(%04X) - sense " "data for " "device %04X, after status pending\n", @@ -1125,12 +1125,12 @@ ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt); } /* endif */ - } + } #endif } else { - ret = -EIO; + ret = -EIO; ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 1; @@ -1144,7 +1144,7 @@ break; default: /* device/path not operational */ - + if ( flag & DOIO_VALID_LPM ) { ioinfo[irq]->opm &= ~lpm; @@ -1154,27 +1154,27 @@ ioinfo[irq]->opm = 0; } /* endif */ - + if ( ioinfo[irq]->opm == 0 ) { ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; + ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; } /* endif */ ret = -ENODEV; memcpy( ioinfo[irq]->irq_desc.action->dev_id, - &(ioinfo[irq]->devstat), - sizeof( devstat_t) ); + &(ioinfo[irq]->devstat), + sizeof( devstat_t) ); #ifdef CONFIG_DEBUG_IO - { - char buffer[80]; + { + char buffer[80]; stsch(irq, &(ioinfo[irq]->schib) ); - sprintf( buffer, "s390_start_IO(%04X) - schib for " + sprintf( buffer, "s390_start_IO(%04X) - schib for " "device %04X, after 'not oper' status\n", irq, ioinfo[irq]->devstat.devno ); @@ -1211,7 +1211,7 @@ } while ( retry && (iret == -EBUSY ) ); - sync_isc_locked = 0; // local setting + sync_isc_locked = 0; // local setting ioinfo[irq]->ui.flags.syncio = 0; // global setting spin_unlock_irqrestore( &sync_isc, psw_flags); @@ -1222,7 +1222,7 @@ { ioinfo[irq]->ui.flags.repnone = 0; - } /* endif */ + } /* endif */ return( ret); } @@ -1324,27 +1324,27 @@ ccode = rsch( irq); switch (ccode) { - case 0 : - break; + case 0 : + break; - case 1 : + case 1 : s390_process_IRQ( irq ); - ret = -EBUSY; - break; + ret = -EBUSY; + break; - case 2 : - ret = -EINVAL; - break; + case 2 : + ret = -EINVAL; + break; - case 3 : - /* - * useless to wait for request completion - * as device is no longer operational ! - */ + case 3 : + /* + * useless to wait for request completion + * as device is no longer operational ! + */ ioinfo[irq]->ui.flags.oper = 0; ioinfo[irq]->ui.flags.busy = 0; - ret = -ENODEV; - break; + ret = -ENODEV; + break; } /* endswitch */ @@ -1364,7 +1364,7 @@ * it allows the device interrupt handler to associate the upcoming * interrupt with the halt_IO() request. */ -int halt_IO( int irq, +int halt_IO( int irq, unsigned long user_intparm, unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ { @@ -1482,13 +1482,13 @@ { int io_sub; __u32 io_parm; - psw_t io_new_psw; - int ccode; + psw_t io_new_psw; + int ccode; int ready = 0; - struct _lowcore *lc = NULL; + struct _lowcore *lc = NULL; - /* + /* * We shouldn't perform a TPI loop, waiting for * an interrupt to occur, but should load a * WAIT PSW instead. Otherwise we may keep the @@ -1504,31 +1504,31 @@ ccode = iac(); switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "halt_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; + case 0: // primary-space + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_PRIM_SPACE_MODE + | _PSW_IO_WAIT; + break; + case 1: // secondary-space + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_SEC_SPACE_MODE + | _PSW_IO_WAIT; + break; + case 2: // access-register + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_ACC_REG_MODE + | _PSW_IO_WAIT; + break; + case 3: // home-space + io_sync_wait.mask = _IO_PSW_MASK + | _PSW_HOME_SPACE_MODE + | _PSW_IO_WAIT; + break; + default: + panic( "halt_IO() : unexpected " + "address-space-control %d\n", + ccode); + break; } /* endswitch */ io_sync_wait.addr = FIX_PSW(&&hio_wakeup); @@ -1568,7 +1568,7 @@ memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, '\0', sizeof( irb_t) ); - /* + /* * Let the common interrupt handler process the pending * status. However, we must avoid calling the user * action handler, as it won't be prepared to handle @@ -1600,13 +1600,13 @@ */ if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) { - ret = -ENODEV; + ret = -ENODEV; ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 0; } else { - ret = -EIO; + ret = -EIO; ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 1; @@ -1630,8 +1630,8 @@ { disable_cpu_sync_isc( irq ); - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting + sync_isc_locked = 0; // local setting + ioinfo[irq]->ui.flags.syncio = 0; // global setting spin_unlock_irqrestore( &sync_isc, psw_flags); @@ -1653,7 +1653,7 @@ unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ { int ret; - int ccode; + int ccode; unsigned long psw_flags; int sync_isc_locked = 0; @@ -1666,7 +1666,7 @@ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); - } + } /* * we only allow for halt_IO if the device has an I/O handler associated @@ -1675,62 +1675,62 @@ { ret = -ENODEV; } - /* + /* * we ignore the halt_io() request if ending_status was received but * a SENSE operation is waiting for completion. - */ + */ else if ( ioinfo[irq]->ui.flags.w4sense ) { ret = 0; } - /* + /* * We don't allow for halt_io with a sync do_IO() requests pending. * Concurrent I/O is possible in SMP environments only, but the * sync. I/O request can be gated to one CPU at a time only. - */ + */ else if ( ioinfo[irq]->ui.flags.syncio ) - { + { ret = -EBUSY; -} + } else { -/* + /* * If sync processing was requested we lock the sync ISC, * modify the device to present interrupts for this ISC only * and switch the CPU to handle this ISC + the console ISC * exclusively. - */ + */ if ( flag & DOIO_WAIT_FOR_INTERRUPT ) -{ + { // // check whether we run recursively (sense processing) // if ( !ioinfo[irq]->ui.flags.syncio ) { spin_lock_irqsave( &sync_isc, psw_flags); - + ret = enable_cpu_sync_isc( irq); if ( ret ) - { + { spin_unlock_irqrestore( &sync_isc, psw_flags); return( ret); } else - { + { sync_isc_locked = 1; // local ioinfo[irq]->ui.flags.syncio = 1; // global } /* endif */ + + } /* endif */ } /* endif */ - } /* endif */ - - /* + /* * Issue "Halt subchannel" and process condition code - */ + */ ccode = csch( irq ); switch ( ccode ) { @@ -1739,7 +1739,7 @@ ioinfo[irq]->ui.flags.haltio = 1; if ( !ioinfo[irq]->ui.flags.doio ) - { + { ioinfo[irq]->ui.flags.busy = 1; ioinfo[irq]->u_intparm = user_intparm; ioinfo[irq]->devstat.cstat = 0; @@ -1748,12 +1748,12 @@ ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION; ioinfo[irq]->devstat.scnt = 0; - } - else - { + } + else + { ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION; - } /* endif */ + } /* endif */ /* * If synchronous I/O processing is requested, we have @@ -1764,16 +1764,16 @@ * pops up. */ if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { + { int io_sub; __u32 io_parm; psw_t io_new_psw; int ccode; - + int ready = 0; struct _lowcore *lc = NULL; - /* + /* * We shouldn't perform a TPI loop, waiting for * an interrupt to occur, but should load a * WAIT PSW instead. Otherwise we may keep the @@ -1781,7 +1781,7 @@ * the interrupt. When our sync. interrupt * arrived we reset the I/O old PSW to its * original value. - */ + */ memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t)); @@ -1818,14 +1818,14 @@ io_sync_wait.addr = FIX_PSW(&&cio_wakeup); - /* + /* * Martin didn't like modifying the new PSW, now we take * a fast exit in do_IRQ() instead - */ + */ *(__u32 *)__LC_SYNC_IO_WORD = 1; do - { + { asm volatile ( "lpsw %0" : : "m" (io_sync_wait) ); cio_wakeup: @@ -1838,13 +1838,13 @@ *(__u32 *)__LC_SYNC_IO_WORD = 0; - } /* endif */ + } /* endif */ ret = 0; break; - - case 1 : /* status pending */ + case 1 : /* status pending */ + ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; /* @@ -1888,14 +1888,14 @@ ret = -ENODEV; ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 0; - } - else - { + } + else + { ret = -EIO; ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 1; - } /* endif */ + } /* endif */ break; @@ -1914,32 +1914,32 @@ if ( sync_isc_locked ) { disable_cpu_sync_isc( irq ); - + sync_isc_locked = 0; // local setting ioinfo[irq]->ui.flags.syncio = 0; // global setting spin_unlock_irqrestore( &sync_isc, psw_flags); - + } /* endif */ - + } /* endif */ return( ret ); } - /* +/* * do_IRQ() handles all normal I/O device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). - * + * * Returns: 0 - no ending status received, no further action taken * 1 - interrupt handler was called with ending status - */ + */ asmlinkage void do_IRQ( struct pt_regs regs, unsigned int irq, __u32 s390_intparm ) - { +{ #ifdef CONFIG_FAST_IRQ int ccode; tpi_info_t tpi_info; @@ -1958,15 +1958,15 @@ return; /* this keeps the device boxed ... */ } - /* + /* * take fast exit if CPU is in sync. I/O state - * + * * Note: we have to turn off the WAIT bit and re-disable * interrupts prior to return as this was the initial * entry condition to synchronous I/O. - */ + */ if ( *(__u32 *)__LC_SYNC_IO_WORD ) - { + { regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT); return; @@ -1983,9 +1983,9 @@ #ifdef CONFIG_FAST_IRQ - /* + /* * more interrupts pending ? - */ + */ ccode = tpi( &tpi_info ); if ( ! ccode ) @@ -1993,29 +1993,29 @@ new_irq = tpi_info.irq; - /* + /* * if the interrupt is for a different irq we * release the current irq lock and obtain * a new one ... - */ + */ if ( new_irq != use_irq ) - { + { s390irq_spin_unlock(use_irq); use_irq = new_irq; s390irq_spin_lock(use_irq); - } /* endif */ + } /* endif */ } while ( 1 ); #endif /* CONFIG_FAST_IRQ */ s390irq_spin_unlock(use_irq); - + return; - } +} - /* +/* * s390_process_IRQ() handles status pending situations and interrupts * * Called by : do_IRQ() - for "real" interrupts @@ -2025,7 +2025,7 @@ * * Returns: 0 - no ending status received, no further action taken * 1 - interrupt handler was called with ending status - */ + */ int s390_process_IRQ( unsigned int irq ) { int ccode; /* cond code from tsch() operation */ @@ -2056,18 +2056,18 @@ else { action = ioinfo[irq]->irq_desc.action; - - } /* endif */ + + } /* endif */ #ifdef CONFIG_DEBUG_IO - /* + /* * It might be possible that a device was not-oper. at the time * of free_irq() processing. This means the handler is no longer * available when the device possibly becomes ready again. In * this case we perform delayed disable_subchannel() processing. - */ + */ if ( action == NULL ) - { + { if ( !ioinfo[irq]->ui.flags.d_disable ) { printk( KERN_CRIT"s390_process_IRQ(%04X) " @@ -2077,14 +2077,15 @@ ioinfo[irq]->devstat.devno); } /* endif */ + } /* endif */ #endif - /* + /* * retrieve the i/o interrupt information (irb), * update the device specific status information * and possibly call the interrupt handler. - * + * * Note 1: At this time we don't process the resulting * condition code (ccode) from tsch(), although * we probably should. @@ -2097,75 +2098,72 @@ * parameter relates to it. If a halt function was * issued for an idle device, the intparm must not * be taken from lowcore, but from the devstat area. - */ + */ ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) ); // // We must only accumulate the status if the device is busy already // if ( ioinfo[irq]->ui.flags.busy ) - { - ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat; - ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat; - } - else - { - ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat; - ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat; - - ioinfo[irq]->devstat.flag = 0; // reset status flags - - } /* endif */ - - ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum; - - if ( ioinfo[irq]->ui.flags.busy) { - ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm; + ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat; + ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat; + ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm; + + } + else + { + ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat; + ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat; + ioinfo[irq]->devstat.flag = 0; // reset status flags + ioinfo[irq]->devstat.intparm = 0; + } /* endif */ - /* + ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum; + + /* * reset device-busy bit if no longer set in irb - */ + */ if ( (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY ) && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0)) - { + { ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY; } /* endif */ - /* + /* * Save residual count and CCW information in case primary and * secondary status are presented with different interrupts. - */ + */ if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) ) - { + { ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count; ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa; #ifdef CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "residual count from irb after tsch() %d\n", - irq, ioinfo[irq]->devstat.rescnt ); + if ( irq != cons_dev ) + printk( "s390_process_IRQ( %04X ) : " + "residual count from irb after tsch() %d\n", + irq, ioinfo[irq]->devstat.rescnt ); #endif } /* endif */ irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc; - // + // // check for any kind of channel or interface control check but don't // issue the message for the console device - // + // if ( (ioinfo[irq]->devstat.ii.irb.scsw.cstat & ( SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK ) ) && (irq != cons_dev ) ) - { + { printk( "Channel-Check or Interface-Control-Check " "received\n" " ... device %04X on subchannel %04X, dev_stat " @@ -2187,22 +2185,22 @@ ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt; ioinfo[irq]->devstat.flag |= DEVSTAT_FLAG_SENSE_AVAIL; - + sdevstat = sizeof( devstat_t); #ifdef CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "concurrent sense bytes avail %d\n", - irq, ioinfo[irq]->devstat.scnt ); + if ( irq != cons_dev ) + printk( "s390_process_IRQ( %04X ) : " + "concurrent sense bytes avail %d\n", + irq, ioinfo[irq]->devstat.scnt ); #endif - } - else - { + } + else + { /* don't copy the sense data area ! */ sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT; - } /* endif */ + } /* endif */ switch ( irb_cc ) { case 1: /* status pending */ @@ -2311,7 +2309,7 @@ sizeof( devstat_t) ); s_ccw->cmd_code = CCW_CMD_BASIC_SENSE; - s_ccw->cda = (char *)virt_to_phys( ioinfo[irq]->sense_data); + s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->sense_data ); s_ccw->count = SENSE_MAX_COUNT; s_ccw->flags = CCW_FLAG_SLI; @@ -2995,8 +2993,8 @@ // // Output : none // -void VM_virtual_device_info( unsigned int devno, - senseid_t *ps ) +void VM_virtual_device_info( unsigned int devno, + senseid_t *ps ) { diag210_t diag_data; int ccode; @@ -3222,7 +3220,7 @@ error = 1; - break; + break; } /* endswitch */ @@ -3322,19 +3320,19 @@ } if ( ioinfo[irq]->ui.flags.oper == 0 ) - { + { return( -ENODEV ); } /* endif */ - /* + /* * Before playing around with irq locks we should assure * running disabled on (just) our CPU. Sync. I/O requests * also require to run disabled. * * Note : as no global lock is required, we must not use * cli(), but __cli() instead. - */ + */ __save_flags(flags); __cli(); @@ -3357,11 +3355,11 @@ if ( !ret ) { if ( ! *buffer ) - { + { rdc_buf = kmalloc( length, GFP_KERNEL); - } - else - { + } + else + { rdc_buf = *buffer; } /* endif */ @@ -3375,7 +3373,7 @@ do { rdc_ccw->cmd_code = CCW_CMD_RDC; - rdc_ccw->cda = (char *)virt_to_phys( rdc_buf ); + rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf ); rdc_ccw->count = length; rdc_ccw->flags = CCW_FLAG_SLI; @@ -3398,21 +3396,21 @@ } /* endif */ if ( !retry ) - { + { ret = -EBUSY; } /* endif */ __restore_flags(flags); - /* + /* * on success we update the user input parms - */ + */ if ( !ret ) { *buffer = rdc_buf; - } /* endif */ + } /* endif */ if ( emulated ) { @@ -3425,11 +3423,11 @@ return( ret ); } - /* +/* * Read Configuration data - */ + */ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) - { +{ unsigned long flags; int ciw_cnt; @@ -3439,7 +3437,7 @@ if ( (irq > highest_subchannel) || (irq < 0 ) ) { return( -ENODEV ); - } + } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); @@ -3456,12 +3454,12 @@ { return( -EOPNOTSUPP ); - } /* endif */ + } /* endif */ - /* + /* * scan for RCD command in extended SenseID data - */ - + */ + for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ ) { if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD ) @@ -3473,15 +3471,16 @@ { found = 1; - } /* endif */ + } /* endif */ break; + } /* endif */ } /* endfor */ if ( found ) -{ + { devstat_t devstat; /* inline device status area */ devstat_t *pdevstat; int ioflags; @@ -3506,9 +3505,9 @@ emulated = 1; } /* endif */ - } + } else - { + { pdevstat = ioinfo[irq]->irq_desc.action->dev_id; } /* endif */ @@ -3519,9 +3518,9 @@ { rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count, GFP_KERNEL); - } + } else - { + { rcd_buf = alloc_bootmem( ioinfo[irq]->senseid.ciw[ciw_cnt].count); } /* endif */ @@ -3530,18 +3529,18 @@ { ret = -ENOMEM; - } /* endif */ + } /* endif */ if ( !ret ) { memset( rcd_buf, '\0', ioinfo[irq]->senseid.ciw[ciw_cnt].count); - + do - { + { rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd; - rcd_ccw->cda = (char *)virt_to_phys( rcd_buf ); + rcd_ccw->cda = (__u32)virt_to_phys( rcd_buf ); rcd_ccw->count = ioinfo[irq]->senseid.ciw[ciw_cnt].count; rcd_ccw->flags = CCW_FLAG_SLI; @@ -3552,13 +3551,13 @@ ioflags = DOIO_WAIT_FOR_INTERRUPT | DOIO_VALID_LPM | DOIO_DONT_CALL_INTHDLR; - } - else - { + } + else + { ioflags = DOIO_WAIT_FOR_INTERRUPT | DOIO_DONT_CALL_INTHDLR; - - } /* endif */ + + } /* endif */ ret = s390_start_IO( irq, rcd_ccw, @@ -3575,12 +3574,12 @@ | DEVSTAT_FLAG_SENSE_AVAIL ) ) ) { retry = 0; // we got it ... - } - else - { + } + else + { retry--; // try again ... - } /* endif */ + } /* endif */ break; @@ -3612,9 +3611,9 @@ if ( init_IRQ_complete ) { kfree( rcd_buf ); - } - else - { + } + else + { free_bootmem( (unsigned long)rcd_buf, ioinfo[irq]->senseid.ciw[ciw_cnt].count); @@ -3624,7 +3623,7 @@ *buffer = NULL; *length = 0; - + } /* endif */ if ( emulated ) @@ -3645,7 +3644,6 @@ return( get_dev_info_by_irq( irq, pdi)); } - static int __inline__ get_next_available_irq( ioinfo_t *pi) { int ret_val; @@ -3667,7 +3665,7 @@ if ( pi == NULL ) { ret_val = -ENODEV; - break; + break; } } /* endif */ @@ -3696,7 +3694,7 @@ else { ret_irq = -ENODEV; - + } /* endif */ } else @@ -3820,8 +3818,8 @@ && ioinfo[i]->schib.pmcw.dev == devno ) { - pdi->irq = i; - pdi->devno = devno; + pdi->irq = i; + pdi->devno = devno; if ( ioinfo[i]->ui.flags.oper && !ioinfo[i]->ui.flags.unknown ) @@ -3845,7 +3843,7 @@ else { pdi->status = DEVSTAT_NOT_OPER; - + memset( &(pdi->sid_data), '\0', sizeof( senseid_t)); @@ -3858,7 +3856,7 @@ pdi->status |= DEVSTAT_DEVICE_OWNED; rc = 0; /* found */ - break; + break; } /* endif */ @@ -3889,7 +3887,7 @@ } /* endif */ } /* endfor */ - + } /* endif */ return( rc); @@ -3903,7 +3901,7 @@ || ( ioinfo[irq] == INVALID_STORAGE_AREA ) ) { return -1; - + } /* endif */ /* @@ -3955,7 +3953,7 @@ * single I/O during boot (IPL) processing. */ spin_lock_irqsave( &sync_isc, psw_flags); - + ret = enable_cpu_sync_isc( irq); if ( ret ) @@ -3964,7 +3962,7 @@ } else { - ioinfo[irq]->ui.flags.syncio = 1; // global + ioinfo[irq]->ui.flags.syncio = 1; // global ioinfo[irq]->ui.flags.unknown = 0; memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t)); @@ -4022,7 +4020,7 @@ free_irq( irq, &devstat ); } /* endif */ - + } /* endif */ } @@ -4063,13 +4061,14 @@ { ret = s390_validate_subchannel( irq, 0); - irq++; - + if ( ret != -ENXIO) + irq++; + } while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) ); - highest_subchannel = --irq; + highest_subchannel = (--irq); - printk( "\nHighest subchannel number detected: %u\n", + printk( "Highest subchannel number detected (hex) : %04X\n", highest_subchannel); } @@ -4136,7 +4135,6 @@ { if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { - if ( !init_IRQ_complete ) { ioinfo[irq] = @@ -4156,7 +4154,7 @@ sizeof( schib_t)); ioinfo[irq]->irq_desc.status = IRQ_DISABLED; ioinfo[irq]->irq_desc.handler = &no_irq_type; - + /* * We have to insert the new ioinfo element * into the linked list, either at its head, @@ -4191,14 +4189,14 @@ ioinfo[irq]->prev = pi; pi->next->prev = ioinfo[irq]; pi->next = ioinfo[irq]; - break; - + break; + } /* endif */ pi = pi->next; } while ( 1 ); - + } /* endif */ } /* endif */ @@ -4218,7 +4216,7 @@ ioinfo[irq]->schib.pmcw.pam, ioinfo[irq]->schib.pmcw.pom); -/* + /* * initialize ioinfo structure */ ioinfo[irq]->irq = irq; @@ -4232,9 +4230,9 @@ /* * We should have at least one CHPID ... - */ + */ if ( ioinfo[irq]->opm ) -{ + { /* * We now have to initially ... * ... set "interruption sublass" @@ -4260,15 +4258,15 @@ && ( ioinfo[irq]->opm != 0x04 ) && ( ioinfo[irq]->opm != 0x02 ) && ( ioinfo[irq]->opm != 0x01 ) ) - { + { ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ - } /* endif */ + } /* endif */ retry = 5; do - { + { ccode2 = msch_err( irq, &ioinfo[irq]->schib); switch (ccode2) { @@ -4280,7 +4278,7 @@ ioinfo[irq]->ui.flags.consns = 1; ret = 0; break; - + case 1: // status pending // // How can we have a pending status as @@ -4293,12 +4291,12 @@ retry--; ret = -EIO; break; - + case 2: // busy - /* + /* * we mark it not-oper as we can't * properly operate it ! - */ + */ ioinfo[irq]->ui.flags.oper = 0; tod_wait( 100); /* allow for recovery */ retry--; @@ -4315,39 +4313,39 @@ #define PGMCHK_OPERAND_EXC 0x15 if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC ) - { + { /* * re-issue the modify subchannel without trying to * enable the concurrent sense facility */ ioinfo[irq]->schib.pmcw.csense = 0; - + ccode2 = msch_err( irq, &ioinfo[irq]->schib); if ( ccode2 != 0 ) - { + { printk( " ... msch() (2) failed with CC = %X\n", ccode2 ); ioinfo[irq]->ui.flags.oper = 0; ret = -EIO; - } - else - { + } + else + { ioinfo[irq]->ui.flags.oper = 1; ioinfo[irq]->ui.flags.consns = 0; ret = 0; - } /* endif */ - } - else - { + } /* endif */ + } + else + { printk( " ... msch() (1) failed with CC = %X\n", ccode2); ioinfo[irq]->ui.flags.oper = 0; ret = -EIO; - } /* endif */ - + } /* endif */ + retry = 0; break; @@ -4356,13 +4354,13 @@ } while ( ccode2 && retry ); if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) ) - { + { printk( " ... msch() retry count for " "subchannel %04X exceeded, CC = %d\n", irq, ccode2); - } /* endif */ + } /* endif */ } else { @@ -4373,19 +4371,18 @@ } /* endif */ } else - { + { ret = -ENODEV; - } /* endif */ + } /* endif */ } else { - ret = -ENXIO; - } /* endif */ + } /* endif */ - return( ret ); + return( ret ); } /* @@ -4417,70 +4414,70 @@ senseid_t *psid = sid;/* start with the external buffer */ int sbuffer = 0; /* switch SID data buffer */ - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); + if ( (irq > highest_subchannel) || (irq < 0 ) ) + { + return( -ENODEV ); - } + } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); - } /* endif */ + } /* endif */ - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); + if ( ioinfo[irq]->ui.flags.oper == 0 ) + { + return( -ENODEV ); - } /* endif */ + } /* endif */ - if ( !ioinfo[irq]->ui.flags.ready ) - { + if ( !ioinfo[irq]->ui.flags.ready ) + { pdevstat = &devstat; - /* + /* * Perform SENSE ID command processing. We have to request device * ownership and provide a dummy I/O handler. We issue sync. I/O * requests and evaluate the devstat area on return therefore * we don't need a real I/O handler in place. - */ + */ irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat); if ( irq_ret == 0 ) inlreq = 1; - } - else - { + } + else + { inlreq = 0; irq_ret = 0; pdevstat = ioinfo[irq]->irq_desc.action->dev_id; - } /* endif */ + } /* endif */ if ( irq_ret == 0 ) -{ + { int i; s390irq_spin_lock( irq); // more than one path installed ? if ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) -{ + { sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN; sense_ccw[0].cda = 0; sense_ccw[0].count = 0; sense_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID; - sense_ccw[1].cda = (char *)virt_to_phys( psid ); + sense_ccw[1].cda = (__u32)virt_to_phys( sid ); sense_ccw[1].count = sizeof( senseid_t); sense_ccw[1].flags = CCW_FLAG_SLI; } else { sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID; - sense_ccw[0].cda = (char *)virt_to_phys( psid ); + sense_ccw[0].cda = (__u32)virt_to_phys( sid ); sense_ccw[0].count = sizeof( senseid_t); sense_ccw[0].flags = CCW_FLAG_SLI; @@ -4496,7 +4493,7 @@ domask &= lpm; if ( domask ) - { + { psid->cu_type = 0xFFFF; /* initialize fields ... */ psid->cu_model = 0; psid->dev_type = 0; @@ -4504,14 +4501,14 @@ retry = 5; /* retry count */ io_retry = 1; /* enable retries */ - + /* * We now issue a SenseID request. In case of BUSY, * STATUS PENDING or non-CMD_REJECT error conditions * we run simple retries. */ do - { + { memset( pdevstat, '\0', sizeof( devstat_t) ); irq_ret = s390_start_IO( irq, @@ -4533,9 +4530,9 @@ // if ( psid->cu_type == 0xFFFF ) - { + { if ( pdevstat->flag & DEVSTAT_STATUS_PENDING ) - { + { #ifdef CONFIG_DEBUG_IO printk( "SenseID : device %04X on " "Subchannel %04X " @@ -4548,14 +4545,14 @@ } /* endif */ if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { + { /* * if the device doesn't support the SenseID * command further retries wouldn't help ... */ if ( pdevstat->ii.sense.data[0] & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) ) - { + { #ifdef CONFIG_DEBUG_IO printk( "SenseID : device %04X on " "Subchannel %04X " @@ -4565,10 +4562,10 @@ irq); #endif io_retry = 1; - } + } #ifdef CONFIG_DEBUG_IO - else - { + else + { printk( "SenseID : UC on " "dev %04X, " "retry %d, " @@ -4590,12 +4587,12 @@ pdevstat->ii.sense.data[6], pdevstat->ii.sense.data[7]); - } /* endif */ + } /* endif */ #endif - } + } else if ( ( pdevstat->flag & DEVSTAT_NOT_OPER ) || ( irq_ret == -ENODEV ) ) - { + { #ifdef CONFIG_DEBUG_IO printk( "SenseID : path %02X for " "device %04X on " @@ -4608,8 +4605,8 @@ io_retry = 0; ioinfo[irq]->opm &= ~domask; - -} + + } #ifdef CONFIG_DEBUG_IO else if ( (pdevstat->flag != ( DEVSTAT_START_FUNCTION @@ -4630,11 +4627,11 @@ } /* endif */ #endif - } + } else // we got it ... - { + { if ( !sbuffer ) // switch buffers - { + { /* * we report back the * first hit only @@ -4642,14 +4639,14 @@ psid = &isid; if ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) - { - sense_ccw[1].cda = (char *)virt_to_phys( psid ); - } - else - { - sense_ccw[0].cda = (char *)virt_to_phys( psid ); + { + sense_ccw[1].cda = (__u32)virt_to_phys( psid ); + } + else + { + sense_ccw[0].cda = (__u32)virt_to_phys( psid ); - } /* endif */ + } /* endif */ /* * if just the very first @@ -4662,35 +4659,35 @@ sbuffer = 1; - } /* endif */ + } /* endif */ if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) ) -{ + { ioinfo[irq]->ui.flags.esid = 1; - + } /* endif */ io_retry = 0; - + } /* endif */ if ( io_retry ) - { + { retry--; - + if ( retry == 0 ) { io_retry = 0; - } /* endif */ - + } /* endif */ + } /* endif */ - + } while ( (io_retry) ); } /* endif - domask */ - } /* endfor */ + } /* endfor */ s390irq_spin_unlock( irq); @@ -4713,7 +4710,7 @@ } /* endif */ if ( sid->cu_type == 0xFFFF ) -{ + { /* * SenseID CU-type of 0xffff indicates that no device * information could be retrieved (pre-init value). @@ -4733,10 +4730,10 @@ /* * Issue device info message if unit was operational . */ - if ( ioinfo[irq]->ui.flags.unknown ) - { + if ( !ioinfo[irq]->ui.flags.unknown ) + { if ( sid->dev_type != 0 ) - { + { printk( "SenseID : device %04X reports: CU Type/Mod = %04X/%02X," " Dev Type/Mod = %04X/%02X\n", ioinfo[irq]->schib.pmcw.dev, @@ -4746,18 +4743,18 @@ sid->dev_model); } else - { + { printk( "SenseID : device %04X reports:" " Dev Type/Mod = %04X/%02X\n", ioinfo[irq]->schib.pmcw.dev, sid->cu_type, sid->cu_model); - } /* endif */ + } /* endif */ - } /* endif */ + } /* endif */ - if ( ioinfo[irq]->ui.flags.unknown ) + if ( !ioinfo[irq]->ui.flags.unknown ) irq_ret = 0; else irq_ret = -ENODEV; @@ -4774,7 +4771,7 @@ cc = stsch( irq, &ioinfo[irq]->schib ); if ( !cc ) - { + { ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ cc = msch( irq, &ioinfo[irq]->schib ); @@ -4812,17 +4809,17 @@ if ( ccode ) { ret = -ENODEV; -} + } else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 ) { -/* + /* * no error, just not required for single path only devices - */ + */ ioinfo[irq]->ui.flags.pgid_supp = 0; ret = 0; } else -{ + { int i; pgid_t pgid; __u8 dev_path; @@ -4833,16 +4830,16 @@ & ioinfo[irq]->schib.pmcw.pom; if ( usermask ) - { + { dev_path = usermask; - } - else - { + } + else + { dev_path = ioinfo[irq]->opm; - } /* endif */ + } /* endif */ - /* + /* * let's build a path group ID if we don't have one yet */ if ( ioinfo[irq]->ui.flags.pgid == 0) @@ -4854,7 +4851,7 @@ ioinfo[irq]->ui.flags.pgid = 1; - } /* endif */ + } /* endif */ memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t)); @@ -4865,7 +4862,7 @@ domask = dev_path & pathmask; if ( domask ) - { + { ret = s390_SetPGID( irq, domask, &pgid ); /* @@ -4879,30 +4876,30 @@ if ( ret == -EOPNOTSUPP && first ) { *(int *)&pgid = 0; - + ret = s390_SensePGID( irq, domask, &pgid); first = 0; - + if ( ret == 0 ) { - /* + /* * Check whether we retrieved * a reasonable PGID ... - */ + */ if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED ) - { + { memcpy( &(ioinfo[irq]->pgid), &pgid, sizeof(pgid_t) ); - } + } else // ungrouped or garbage ... - { + { ret = -EOPNOTSUPP; } /* endif */ - } + } else - { + { ioinfo[irq]->ui.flags.pgid_supp = 0; #ifdef CONFIG_DEBUG_IO @@ -4924,18 +4921,18 @@ " support path grouping\n", irq, ioinfo[irq]->schib.pmcw.dev); - + #endif ioinfo[irq]->ui.flags.pgid_supp = 0; } /* endif */ - - } /* endif */ + + } /* endif */ } /* endfor */ - } /* endif */ + } /* endif */ return ret; #else @@ -4943,14 +4940,14 @@ #endif } - /* +/* * s390_SetPGID * * Set Path Group ID - * - */ + * + */ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) - { +{ ccw1_t spid_ccw[2]; /* ccw area for SPID command */ devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; @@ -4966,7 +4963,7 @@ } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { + { return( -ENODEV); } /* endif */ @@ -5001,7 +4998,7 @@ } /* endif */ if ( irq_ret == 0 ) - { + { s390irq_spin_lock( irq); spid_ccw[0].cmd_code = 0x5B; /* suspend multipath reconnect */ @@ -5010,16 +5007,16 @@ spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; spid_ccw[1].cmd_code = CCW_CMD_SET_PGID; - spid_ccw[1].cda = (char *)virt_to_phys( pgid ); + spid_ccw[1].cda = (__u32)virt_to_phys( pgid ); spid_ccw[1].count = sizeof( pgid_t); spid_ccw[1].flags = CCW_FLAG_SLI; pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH; - /* + /* * We now issue a SenseID request. In case of BUSY * or STATUS PENDING conditions we retry 5 times. - */ + */ do { memset( pdevstat, '\0', sizeof( devstat_t) ); @@ -5049,7 +5046,7 @@ if ( pdevstat->flag == ( DEVSTAT_START_FUNCTION | DEVSTAT_FINAL_STATUS ) ) - { + { retry = 0; // successfully set ... } else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) @@ -5106,28 +5103,28 @@ ioinfo[irq]->schib.pmcw.dev, irq); - retry = 0; + retry = 0; } /* endif */ } else if ( irq_ret != -ENODEV ) - { + { retry--; } else { retry = 0; - } /* endif */ + } /* endif */ } while ( retry > 0 ); s390irq_spin_unlock( irq); - /* + /* * If we installed the irq action handler we have to * release it too. - */ + */ if ( inlreq ) free_irq( irq, pdevstat); @@ -5146,12 +5143,12 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) { ccw1_t snid_ccw; /* ccw area for SNID command */ - devstat_t devstat; /* required by request_irq() */ + devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline request_irq() */ + int irq_ret = 0; /* return code */ + int retry = 5; /* retry count */ + int inlreq = 0; /* inline request_irq() */ if ( (irq > highest_subchannel) || (irq < 0 ) ) { @@ -5175,9 +5172,9 @@ /* * Perform SENSE ID command processing. We have to request device * ownership and provide a dummy I/O handler. We issue sync. I/O - * requests and evaluate the devstat area on return therefore - * we don't need a real I/O handler in place. - */ + * requests and evaluate the devstat area on return therefore + * we don't need a real I/O handler in place. + */ irq_ret = request_irq( irq, init_IRQ_handler, 0, @@ -5195,11 +5192,11 @@ } /* endif */ if ( irq_ret == 0 ) - { + { s390irq_spin_lock( irq); snid_ccw.cmd_code = CCW_CMD_SENSE_PGID; - snid_ccw.cda = (char *)virt_to_phys( pgid ); + snid_ccw.cda = (__u32)virt_to_phys( pgid ); snid_ccw.count = sizeof( pgid_t); snid_ccw.flags = CCW_FLAG_SLI; @@ -5220,7 +5217,7 @@ | DOIO_DONT_CALL_INTHDLR ); if ( irq_ret == 0 ) - { + { if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) { /* @@ -5230,7 +5227,7 @@ */ if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT ) { - retry = 0; + retry = 0; irq_ret = -EOPNOTSUPP; } else @@ -5270,12 +5267,12 @@ retry = 0; - } + } else - { + { retry = 0; // success ... - } /* endif */ + } /* endif */ } else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY { @@ -5296,7 +5293,7 @@ " start_io() reports rc : %d, retrying ...\n", ioinfo[irq]->schib.pmcw.dev, irq_ret); - retry--; + retry--; } else // -ENODEV ... { @@ -5320,16 +5317,16 @@ return( irq_ret ); } - /* +/* * s390_do_crw_pending * * Called by the machine check handler to process CRW pending * conditions. It may be a single CRW, or CRWs may be chained. * * Note : we currently process CRWs for subchannel source only - */ + */ void s390_do_crw_pending( crwe_t *pcrwe ) - { +{ int irq; int dev_oper = 0; int dev_no = -1; @@ -5340,7 +5337,7 @@ #endif while ( pcrwe != NULL ) - { + { switch ( pcrwe->crw.rsc ) { case CRW_RSC_SCH : @@ -5364,7 +5361,7 @@ if ( ioinfo[irq]->ui.flags.dval ) dev_no = ioinfo[irq]->devno; - } /* endif */ + } /* endif */ #ifdef CONFIG_DEBUG_CRW printk( "do_crw_pending : subchannel validation - start ...\n"); @@ -5377,19 +5374,19 @@ #ifdef CONFIG_DEBUG_CRW printk( "do_crw_pending : subchannel validation - done\n"); #endif - /* + /* * After the validate processing * the ioinfo control block * should be allocated ... - */ + */ if ( lock ) - { + { s390irq_spin_unlock( irq ); } /* endif */ #ifdef CONFIG_DEBUG_CRW - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) + if ( ioinfo[irq] != INVALID_STORAGE_AREA ) { printk( "do_crw_pending : ioinfo at %08X\n", (unsigned)ioinfo[irq]); @@ -5397,7 +5394,7 @@ } /* endif */ #endif - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) + if ( ioinfo[irq] != INVALID_STORAGE_AREA ) { if ( ioinfo[irq]->ui.flags.oper == 0 ) { @@ -5408,15 +5405,15 @@ if ( ( dev_oper == 1 ) && ( ioinfo[irq]->nopfunc != NULL ) ) { - free_irq( irq, - ioinfo[irq]->irq_desc.action->dev_id ); - ioinfo[irq]->nopfunc( irq, - DEVSTAT_DEVICE_GONE ); + free_irq( irq, + ioinfo[irq]->irq_desc.action->dev_id ); + ioinfo[irq]->nopfunc( irq, + DEVSTAT_DEVICE_GONE ); } /* endif */ - } - else - { + } + else + { #ifdef CONFIG_DEBUG_CRW printk( "do_crw_pending : device " "recognition - start ...\n"); @@ -5442,7 +5439,7 @@ if ( pdevreg->oper_func != NULL ) pdevreg->oper_func( irq, pdevreg ); - } /* endif */ + } /* endif */ } /* * ... it is and was operational, but @@ -5453,11 +5450,11 @@ ioinfo[irq]->nopfunc( irq, DEVSTAT_REVALIDATE ); - } /* endif */ + } /* endif */ } /* endif */ - } /* endif */ + } /* endif */ break; @@ -5516,13 +5513,13 @@ /* added by Holger Smolinski for reipl support in reipl.S */ extern void do_reipl (int); -void +void reipl ( int sch ) { - int i; + int i; for ( i = 0; i < highest_subchannel; i ++ ) { - free_irq ( i, (void*)REIPL_DEVID_MAGIC ); + free_irq ( i, (void*)REIPL_DEVID_MAGIC ); } do_reipl( 0x10000 | sch ); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/s390mach.c linux/arch/s390/kernel/s390mach.c --- v2.2.17/arch/s390/kernel/s390mach.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/s390mach.c Thu Dec 7 14:51:17 2000 @@ -4,7 +4,7 @@ * currently only channel-reports are supported * * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) */ @@ -20,16 +20,16 @@ #include #include -#define S390_MACHCHK_DEBUG +#undef S390_MACHCHK_DEBUG -static int __init s390_machine_check_handler( void * parm ); +static int s390_machine_check_handler( void * parm ); static void s390_enqueue_mchchk( mache_t *mchchk ); static mache_t *s390_dequeue_mchchk( void ); static void s390_enqueue_free_mchchk( mache_t *mchchk ); static mache_t *s390_dequeue_free_mchchk( void ); static int s390_collect_crw_info( void ); -static struct semaphore s_sem[2]; +static struct semaphore s_sem; static mache_t *mchchk_queue_head = NULL; static mache_t *mchchk_queue_tail = NULL; @@ -38,16 +38,6 @@ static spinlock_t mchchk_queue_lock = SPIN_LOCK_UNLOCKED; static spinlock_t crw_queue_lock = SPIN_LOCK_UNLOCKED; -static inline void init_MUTEX (struct semaphore *sem) -{ - sema_init(sem, 1); -} - -static inline void init_MUTEX_LOCKED (struct semaphore *sem) -{ - sema_init(sem, 0); -} - /* * s390_init_machine_check * @@ -58,8 +48,7 @@ crwe_t *pcrwe; /* CRW buffer element pointer */ mache_t *pmache; /* machine check element pointer */ - init_MUTEX_LOCKED( &s_sem[0] ); - init_MUTEX_LOCKED( &s_sem[1] ); + init_MUTEX_LOCKED( &s_sem ); pcrwe = kmalloc( MAX_CRW_PENDING * sizeof( crwe_t), GFP_KERNEL); @@ -69,7 +58,7 @@ crw_buffer_anchor = pcrwe; - for ( i=0; i < MAX_CRW_PENDING; i++) + for ( i=0; i < MAX_CRW_PENDING-1; i++) { pcrwe->crwe_next = (crwe_t *)((unsigned long)pcrwe + sizeof(crwe_t)); pcrwe = pcrwe->crwe_next; @@ -108,16 +97,7 @@ printk( "init_mach : starting machine check handler\n"); #endif - kernel_thread( s390_machine_check_handler, s_sem, 0); - - /* - * wait for the machine check handler to be ready - */ -#ifdef S390_MACHCHK_DEBUG - printk( "init_mach : waiting for machine check handler coming up ... \n"); -#endif - - down( &s_sem[0]); + kernel_thread( s390_machine_check_handler, &s_sem, 0); ctl_clear_bit( 14, 25 ); // disable damage MCH #if 1 @@ -145,10 +125,10 @@ * mchine check pre-processor, collecting the machine check info, * queueing it and posting the machine check handler for processing. */ -void __init s390_do_machine_check( void ) +void s390_do_machine_check( void ) { int crw_count; - mcic_t mcic; + mcic_t mcic; #ifdef S390_MACHCHK_DEBUG printk( "s390_do_machine_check : starting ...\n"); @@ -164,7 +144,7 @@ if ( crw_count ) { - up( &s_sem[1] ); + up( &s_sem ); } /* endif */ @@ -183,7 +163,7 @@ * machine check handler, dequeueing machine check entries * and processing them */ -static int __init s390_machine_check_handler( void *parm) +static int s390_machine_check_handler( void *parm) { struct semaphore *sem = parm; int flags; @@ -191,11 +171,12 @@ int found = 0; -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : up\n"); -#endif + /* set name to something sensible */ + strncpy(current->comm,"kmcheck",15); + current->comm[15]=0; - up( &sem[0] ); + /* block all signals */ + sigfillset(¤t->blocked); #ifdef S390_MACHCHK_DEBUG printk( "mach_handler : ready\n"); @@ -207,15 +188,18 @@ printk( "mach_handler : waiting for wakeup\n"); #endif - down_interruptible( &sem[1] ); + down_interruptible( sem ); #ifdef S390_MACHCHK_DEBUG printk( "\nmach_handler : wakeup ... \n"); #endif + found = 0; /* init ... */ __save_flags( flags ); __cli(); + do { + pmache = s390_dequeue_mchchk(); if ( pmache ) @@ -256,18 +240,19 @@ } else { - found = 0; // unconditional surrender ... #ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : terminated \n"); + printk( "mach_handler : nothing to do, sleeping\n"); #endif } /* endif */ + } while ( pmache ); + __restore_flags( flags ); - } while ( found ); + } while ( 1 ); return( 0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c --- v2.2.17/arch/s390/kernel/setup.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/setup.c Thu Dec 7 14:51:17 2000 @@ -137,7 +137,7 @@ #ifndef CONFIG_SMP void machine_restart(char * __unused) { - reipl(S390_lowcore.ipl_device); + reipl(S390_lowcore.ipl_device); } void machine_halt(void) @@ -145,14 +145,14 @@ if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 0); signal_processor(smp_processor_id(), sigp_stop_and_store_status); - } +} void machine_power_off(void) { if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) cpcmd(vmpoff_cmd, NULL, 0); signal_processor(smp_processor_id(), sigp_stop_and_store_status); - } +} #endif /* @@ -177,7 +177,7 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { - static unsigned int smptrap=0; + static unsigned int smptrap = 0; unsigned long memory_start, memory_end; char c, cn, *to, *from; @@ -332,8 +332,8 @@ p += sprintf(p,"vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", - smp_num_cpus, loops_per_sec/500000, - (loops_per_sec/5000)%100); + smp_num_cpus, loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); for (i = 0; i < smp_num_cpus; i++) { cpuinfo = &safe_get_cpu_lowcore(i).cpu_data; p += sprintf(p,"processor %i: " diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c --- v2.2.17/arch/s390/kernel/signal.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/signal.c Wed Nov 8 23:09:58 2000 @@ -39,7 +39,7 @@ #define SIGFRAME_COMMON \ __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \ struct sigcontext sc; \ -sigregs sregs; \ +_sigregs sregs; \ __u8 retcode[S390_SYSCALL_SIZE]; typedef struct @@ -79,7 +79,7 @@ schedule(); if (do_signal(regs, &saveset)) return -EINTR; - } + } } asmlinkage int @@ -100,17 +100,17 @@ current->blocked = newset; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - regs->gprs[2] = -EINTR; + regs->gprs[2] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(regs, &saveset)) return -EINTR; - } + } } -asmlinkage int +asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) { @@ -126,7 +126,7 @@ __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); - } + } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); @@ -137,22 +137,21 @@ return -EFAULT; __put_user(old_ka.sa.sa_flags, &oact->sa_flags); __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + } return ret; } asmlinkage int -sys_sigaltstack(const stack_t *uss, stack_t *uoss) +sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *) &uss; return do_sigaltstack(uss, uoss, regs->gprs[15]); } -static int save_sigregs(struct pt_regs *regs,sigregs *sregs) +static int save_sigregs(struct pt_regs *regs,_sigregs *sregs) { int err; s390_fp_regs fpregs; @@ -167,7 +166,7 @@ } -static int restore_sigregs(struct pt_regs *regs,sigregs *sregs) +static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs) { int err; s390_fp_regs fpregs; @@ -189,13 +188,13 @@ static int restore_sigcontext(struct sigcontext *sc, pt_regs *regs, - sigregs *sregs,sigset_t *set) + _sigregs *sregs,sigset_t *set) { unsigned int err; err=restore_sigregs(regs,sregs); if(!err) - err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE); + err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE); return(err); } @@ -220,20 +219,20 @@ { if (sigreturn_common(regs,sizeof(sigframe))) - goto badframe; + goto badframe; return regs->gprs[2]; - + badframe: force_sig(SIGSEGV, current); return 0; - } +} asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { rt_sigframe *frame = (rt_sigframe *)regs->gprs[15]; if (sigreturn_common(regs,sizeof(rt_sigframe))) - goto badframe; + goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]); @@ -279,7 +278,7 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs, int frame_size,u16 retcode) - { +{ sigframe *frame; int err; @@ -291,7 +290,7 @@ err=__put_user(&frame->sregs,&frame->sc.sregs); if(!err) - err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE); + err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE); if(!err) { regs->gprs[2]=(current->exec_domain @@ -377,29 +376,29 @@ /* * OK, we're invoking a handler - */ + */ static void handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) - { +{ /* Are we from a system call? */ if (regs->orig_gpr2 >= 0) { /* If so, check system call restarting.. */ switch (regs->gprs[2]) { - case -ERESTARTNOHAND: + case -ERESTARTNOHAND: regs->gprs[2] = -EINTR; break; - case -ERESTARTSYS: + case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->gprs[2] = -EINTR; - break; - } + regs->gprs[2] = -EINTR; + break; + } /* fallthrough */ - case -ERESTARTNOINTR: - regs->gprs[2] = regs->orig_gpr2; - regs->psw.addr -= 2; + case -ERESTARTNOINTR: + regs->gprs[2] = regs->orig_gpr2; + regs->psw.addr -= 2; } } @@ -430,7 +429,7 @@ * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -int do_signal(struct pt_regs *regs,sigset_t *oldset) +int do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; struct k_sigaction *ka; @@ -554,9 +553,9 @@ if (regs->gprs[2] == -ERESTARTNOHAND || regs->gprs[2] == -ERESTARTSYS || regs->gprs[2] == -ERESTARTNOINTR) { - regs->gprs[2] = regs->orig_gpr2; + regs->gprs[2] = regs->orig_gpr2; regs->psw.addr -= 2; + } } -} return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c --- v2.2.17/arch/s390/kernel/smp.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/kernel/smp.c Wed Nov 8 23:04:59 2000 @@ -108,7 +108,7 @@ if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 0); signal_processor(smp_processor_id(), sigp_stop_and_store_status); - } +} void machine_halt(void) { @@ -125,7 +125,7 @@ if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) cpcmd(vmpoff_cmd, NULL, 0); signal_processor(smp_processor_id(), sigp_stop_and_store_status); - } +} void machine_power_off(void) { @@ -248,6 +248,14 @@ __flush_tlb(); atomic_set(&ec->status, ec_done); return; + case ec_callback: { + ec_callback_parms *cbp; + cbp = (ec_callback_parms *) ec->parms; + atomic_set(&ec->status,ec_executing); + (cbp->callback)(cbp->data); + atomic_set(&ec->status,ec_done); + return; + } default: } ec = ec->next; @@ -463,6 +471,19 @@ __ctl_clear_bit(cr, bit); } +/* + * Execute a callback function on all cpus + */ +void smp_do_callback_all(void (*callback)(void *), void *data) { + ec_callback_parms parms; + + if (atomic_read(&smp_commenced) != 0) { + parms.callback = callback; + parms.data = data; + smp_ext_call_sync_others(ec_callback, &parms); + } + (callback)(data); +} /* * Lets check how many CPUs we have. @@ -573,7 +594,7 @@ sigp_ccode ccode; int curr_cpu; int i; - + /* request the 0x1202 external interrupt */ if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1202"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c --- v2.2.17/arch/s390/kernel/traps.c Sun Jun 11 21:44:11 2000 +++ linux/arch/s390/kernel/traps.c Wed Nov 8 23:09:58 2000 @@ -43,134 +43,14 @@ typedef void pgm_check_handler_t(struct pt_regs *, long); pgm_check_handler_t *pgm_check_table[128]; -extern pgm_check_handler_t default_trap_handler; extern pgm_check_handler_t do_page_fault; -asmlinkage int system_call(void); - static inline void console_verbose(void) { extern int console_loglevel; console_loglevel = 15; } -#define DO_ERROR(trapnr, signr, str, name, tsk) \ -asmlinkage void name(struct pt_regs * regs, long error_code) \ -{ \ - if (check_for_fixup(regs) == 0) { \ - tsk->tss.error_code = error_code; \ - tsk->tss.trap_no = trapnr; \ - force_sig(signr, tsk); \ - die(str,regs,error_code); \ - } \ -} - - -void page_exception(void); - -/* TODO: define these as 'pgm_check_handler_t xxx;' -asmlinkage void divide_error(void); -asmlinkage void debug(void); -asmlinkage void nmi(void); -asmlinkage void int3(void); -asmlinkage void overflow(void); -asmlinkage void bounds(void); -asmlinkage void invalid_op(void); -asmlinkage void device_not_available(void); -asmlinkage void double_fault(void); -asmlinkage void coprocessor_segment_overrun(void); -asmlinkage void invalid_TSS(void); -asmlinkage void segment_not_present(void); -asmlinkage void stack_segment(void); -asmlinkage void general_protection(void); -asmlinkage void coprocessor_error(void); -asmlinkage void reserved(void); -asmlinkage void alignment_check(void); -asmlinkage void spurious_interrupt_bug(void); -*/ - -int kstack_depth_to_print = 24; - -/* - * These constants are for searching for possible module text - * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is - * a guess of how much space is likely to be vmalloced. - */ -#define VMALLOC_OFFSET (8*1024*1024) -#define MODULE_RANGE (8*1024*1024) - -void show_crashed_task_info(void) -{ - printk("CPU: %d\n",smp_processor_id()); - printk("Process %s (pid: %d, stackpage=%08X)\n", - current->comm, current->pid, 4096+(addr_t)current); - show_regs(current,NULL,NULL); -} -#if 0 -static void show_registers(struct pt_regs *regs) -{ - printk("CPU: %d\nPSW: %08lx %08lx\n", - smp_processor_id(), (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr); - printk("GPRS:\n"); - - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[0], regs->gprs[1], - regs->gprs[2], regs->gprs[3]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[4], regs->gprs[5], - regs->gprs[6], regs->gprs[7]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[8], regs->gprs[9], - regs->gprs[10], regs->gprs[11]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[12], regs->gprs[13], - regs->gprs[14], regs->gprs[15]); - printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ", - current->comm, current->pid, 4096+(unsigned long)current); -/* - stack = (unsigned long *) esp; - for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) - break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", get_seg_long(ss,stack++)); - } - printk("\nCall Trace: "); - stack = (unsigned long *) esp; - i = 1; - module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); - module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); - module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { - addr = get_seg_long(ss, stack++); */ - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ -/* if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); - i++; - } - } - printk("\nCode: "); - for(i=0;i<20;i++) - printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip))); - printk("\n"); -*/ -} -#endif - - spinlock_t die_lock; void die(const char * str, struct pt_regs * regs, long err) @@ -178,22 +58,36 @@ console_verbose(); spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); - show_crashed_task_info(); + show_regs(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } -int check_for_fixup(struct pt_regs * regs) +#define DO_ERROR(signr, str, name) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + do_trap(interruption_code, signr, str, regs); \ +} + +static void inline do_trap(long interruption_code, int signr, char *str, + struct pt_regs *regs) { - if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { - unsigned long fixup; - fixup = search_exception_table(regs->psw.addr); - if (fixup) { + if (regs->psw.mask & PSW_PROBLEM_STATE) { + struct task_struct *tsk = current; + tsk->tss.trap_no = interruption_code; + force_sig(signr, tsk); +#ifdef CONFIG_PROCESS_DEBUG + printk("User process fault: interruption code 0x%lX\n", + interruption_code); + show_regs(regs); +#endif + } else { + unsigned long fixup = search_exception_table(regs->psw.addr); + if (fixup) regs->psw.addr = fixup; - return 1; - } + else + die(str, regs, interruption_code); } - return 0; } int do_debugger_trap(struct pt_regs *regs,int signal) @@ -219,39 +113,16 @@ return(FALSE); } -asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code) -{ - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = error_code; - force_sig(SIGSEGV, current); - die("Unknown program exception",regs,error_code); - } -} - -DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current) -DO_ERROR(3, SIGILL, "execute exception", execute_exception, current) -DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current) -DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current) -DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current) -DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current) -DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current) - -/* need to define -DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) -DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) -DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math) -DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) -DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) -DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) -DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) -DO_ERROR(18, SIGSEGV, "reserved", reserved, current) -DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current) -*/ - -#ifdef CONFIG_IEEEFPU_EMULATION +DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler); +DO_ERROR(SIGILL, "privileged operation", privileged_op) +DO_ERROR(SIGILL, "execute exception", execute_exception) +DO_ERROR(SIGSEGV, "addressing exception", addressing_exception) +DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception) +DO_ERROR(SIGILL, "translation exception", translation_exception) +DO_ERROR(SIGILL, "special operand exception", special_op_exception) +DO_ERROR(SIGILL, "operand exception", operand_exception) -asmlinkage void illegal_op(struct pt_regs * regs, long error_code) +asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; @@ -269,6 +140,7 @@ if(do_debugger_trap(regs,SIGTRAP)) do_sig=1; } +#ifdef CONFIG_IEEEFPU_EMULATION else if (problem_state ) { if (opcode[0] == 0xb3) { @@ -289,20 +161,19 @@ do_sig = math_emu_lfpc(opcode, regs); } else do_sig = 1; - } else - do_sig = 1; - if (do_sig) { - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = 1; - force_sig(SIGILL, current); - die("illegal operation", regs, error_code); - } } +#endif + else + do_sig = 1; + if (do_sig) + do_trap(interruption_code, SIGILL, "illegal operation", regs); unlock_kernel(); } -asmlinkage void specification_exception(struct pt_regs * regs, long error_code) + + +#ifdef CONFIG_IEEEFPU_EMULATION +asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; @@ -314,26 +185,26 @@ get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - math_emu_ldr(opcode); + do_sig=math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - math_emu_ler(opcode); + do_sig=math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_std(opcode, regs); + do_sig=math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ld(opcode, regs); + do_sig=math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ste(opcode, regs); + do_sig=math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_le(opcode, regs); + do_sig=math_emu_le(opcode, regs); break; default: do_sig = 1; @@ -341,25 +212,22 @@ } } else do_sig = 1; - if (do_sig) { - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = 1; - force_sig(SIGILL, current); - die("illegal operation", regs, error_code); - } - } + if (do_sig) + do_trap(interruption_code, SIGILL, "specification exception", regs); unlock_kernel(); } +#else +DO_ERROR(SIGILL, "specification exception", specification_exception) +#endif -asmlinkage void data_exception(struct pt_regs * regs, long error_code) +asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; int do_sig = 0; lock_kernel(); - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); if(MACHINE_HAS_IEEE) { __asm__ volatile ("stfpc %0\n\t" @@ -374,31 +242,32 @@ (addr_t)ADDR_BITS_REMOVE((addr_t)location); force_sig(SIGFPE, current); } +#ifdef CONFIG_IEEEFPU_EMULATION else if ((regs->psw.mask & 0x00010000L)) { get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - math_emu_ldr(opcode); + do_sig=math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - math_emu_ler(opcode); + do_sig=math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_std(opcode, regs); + do_sig=math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ld(opcode, regs); + do_sig=math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ste(opcode, regs); + do_sig=math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_le(opcode, regs); + do_sig=math_emu_le(opcode, regs); break; case 0xb3: get_user(*((__u16 *) (opcode+2)), location+1); @@ -427,24 +296,14 @@ break; } } +#endif else do_sig = 1; - if (do_sig) { - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = 7; - force_sig(SIGILL, current); - die("data exception", regs, error_code); - } - } + if (do_sig) + do_trap(interruption_code, SIGILL, "data exception", regs); unlock_kernel(); } -#else -DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current) -DO_ERROR(6, SIGILL, "specification exception", specification_exception, current) -DO_ERROR(7, SIGILL, "data exception", data_exception, current) -#endif /* CONFIG_IEEEFPU_EMULATION */ /* init is done in lowcore.S and head.S */ @@ -487,7 +346,7 @@ /* I've seen this possibly a task structure being reused ? */ printk("Spurious per exception detected\n"); printk("switching off per tracing for this task.\n"); - show_crashed_task_info(); + show_regs(regs); /* Hopefully switching off per tracing will help us survive */ regs->psw.mask &= ~PSW_PER_MASK; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/lib/Makefile linux/arch/s390/lib/Makefile --- v2.2.17/arch/s390/lib/Makefile Fri Apr 21 12:45:48 2000 +++ linux/arch/s390/lib/Makefile Wed Nov 8 23:09:58 2000 @@ -11,7 +11,7 @@ endif L_TARGET = lib.a -L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o +L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/lib/delay.c linux/arch/s390/lib/delay.c --- v2.2.17/arch/s390/lib/delay.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/lib/delay.c Wed Nov 8 23:04:59 2000 @@ -27,7 +27,7 @@ * yield the megahertz number of the cpu. The important function * is udelay and that is done using the tod clock. -- martin. */ - __asm__ __volatile__( + __asm__ __volatile__( "0: brct %0,0b" : /* no outputs */ : "r" (loops/2) ); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/lib/uaccess.S linux/arch/s390/lib/uaccess.S --- v2.2.17/arch/s390/lib/uaccess.S Thu Jan 1 01:00:00 1970 +++ linux/arch/s390/lib/uaccess.S Wed Nov 8 23:09:58 2000 @@ -0,0 +1,51 @@ +/* + * arch/s390/lib/uaccess.S + * fixup routines for copy_{from|to}_user functions. + * + * s390 + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * These functions have a non-standard call interface + */ + +#include + + .text + .align 4 + .globl __copy_from_user_fixup +__copy_from_user_fixup: + l 1,__LC_PGM_OLD_PSW+4 + sll 4,1 + srl 4,1 +0: lhi 3,-4096 + sll 3,1 + srl 3,1 + n 3,__LC_TRANS_EXC_ADDR + sr 3,4 + bm 4(1) +1: mvcle 2,4,0 + b 4(1) + .section __ex_table,"a" + .long 1b,0b + .previous + + .align 4 + .text + .globl __copy_to_user_fixup +__copy_to_user_fixup: + l 1,__LC_PGM_OLD_PSW+4 + sll 4,1 + srl 4,1 +0: lhi 5,-4096 + sll 5,1 + srl 5,1 + n 5,__LC_TRANS_EXC_ADDR + sr 5,4 + bm 4(1) +1: mvcle 4,2,0 + b 4(1) + .section __ex_table,"a" + .long 1b,0b + .previous + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c --- v2.2.17/arch/s390/mm/fault.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/mm/fault.c Wed Nov 8 23:09:58 2000 @@ -48,6 +48,7 @@ int write; unsigned long psw_mask; unsigned long psw_addr; + int kernel_address = 0; /* * get psw mask of Program old psw to find out, @@ -71,6 +72,49 @@ if (atomic_read(&S390_lowcore.local_irq_count)) die("page fault from irq handler",regs,error_code); + /* + * Check which address space the address belongs to + */ + switch (S390_lowcore.trans_exc_code & 3) + { + case 0: /* Primary Segment Table Descriptor */ + kernel_address = 1; + goto no_context; + + case 1: /* STD determined via access register */ + if (S390_lowcore.exc_access_id == 0) + { + kernel_address = 1; + goto no_context; + } + if (regs && S390_lowcore.exc_access_id < NUM_ACRS) + { + if (regs->acrs[S390_lowcore.exc_access_id] == 0) + { + kernel_address = 1; + goto no_context; + } + if (regs->acrs[S390_lowcore.exc_access_id] == 1) + { + /* user space address */ + break; + } + } + die("page fault via unknown access register", regs, error_code); + break; + + case 2: /* Secondary Segment Table Descriptor */ + case 3: /* Home Segment Table Descriptor */ + /* user space address */ + break; + } + + + /* + * When we get here, the fault happened in the current + * task's user address space, so we search the VMAs + */ + down(&mm->mmap_sem); vma = find_vma(mm, address); @@ -129,12 +173,12 @@ /* User mode accesses just cause a SIGSEGV */ if (psw_mask & PSW_PROBLEM_STATE) { tsk->tss.prot_addr = address; - tsk->tss.error_code = error_code; - tsk->tss.trap_no = 14; - + tsk->tss.trap_no = error_code; +#ifdef CONFIG_PROCESS_DEBUG printk("User process fault: interruption code 0x%lX\n",error_code); printk("failing address: %lX\n",address); - show_crashed_task_info(); + show_regs(regs); +#endif force_sig(SIGSEGV, tsk); return; } @@ -149,14 +193,13 @@ /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. - * - * First we check if it was the bootup rw-test, though.. */ - if (address < PAGE_SIZE) - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + if (kernel_address) + printk(KERN_ALERT "Unable to handle kernel pointer dereference" + " at virtual kernel address %08lx\n", address); else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); + printk(KERN_ALERT "Unable to handle kernel paging request" + " at virtual user address %08lx\n", address); /* * need to define, which information is useful here */ @@ -171,17 +214,17 @@ */ out_of_memory: if (tsk->pid == 1) - { + { tsk->policy |= SCHED_YIELD; schedule(); goto survive; - } + } up(&mm->mmap_sem); if (psw_mask & PSW_PROBLEM_STATE) { printk("VM: killing process %s\n", tsk->comm); do_exit(SIGKILL); - } + } goto no_context; do_sigbus: @@ -192,8 +235,7 @@ * or user mode. */ tsk->tss.prot_addr = address; - tsk->tss.error_code = error_code; - tsk->tss.trap_no = 14; + tsk->tss.trap_no = error_code; force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/mm/init.c linux/arch/s390/mm/init.c --- v2.2.17/arch/s390/mm/init.c Sun Jun 11 21:44:11 2000 +++ linux/arch/s390/mm/init.c Wed Nov 8 23:09:58 2000 @@ -251,6 +251,7 @@ unsigned long tmp; unsigned long address=0; unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; + static const int ssm_mask = 0x04000000L; /* unmap whole virtual address space */ @@ -295,7 +296,9 @@ /* enable virtual mapping in kernel mode */ __asm__ __volatile__(" LCTL 1,1,%0\n" " LCTL 7,7,%0\n" - " LCTL 13,13,%0" : :"m" (pgdir_k)); + " LCTL 13,13,%0\n" + " SSM %1" + : : "m" (pgdir_k), "m" (ssm_mask)); local_flush_tlb(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/dasdfmt/dasdfmt.8 linux/arch/s390/tools/dasdfmt/dasdfmt.8 --- v2.2.17/arch/s390/tools/dasdfmt/dasdfmt.8 Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.8 Wed Nov 8 23:04:59 2000 @@ -1,68 +1,68 @@ -.TH DASDFMT 8 "Tue Jan 25 2000" -.UC 4 -.SH NAME -dasdfmt \- formatting of DSAD (ECKD) disk drives. -.SH SYNOPSIS +.TH DASDFMT 8 "Tue Jan 25 2000" +.UC 4 +.SH NAME +dasdfmt \- formatting of DSAD (ECKD) disk drives. +.SH SYNOPSIS \fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR -.SH DESCRIPTION -\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it -for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of -\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR. - -.SH OPTIONS -.TP -\fB-t\fR -Disables any modification of the disk drive. \fBdasdfmt\fR just prints -out, what it \fBwould\fR do. - -.TP -\fB-v\fR -Increases verbosity. - -.TP -\fB-y\fR -Start formatting without further user-confirmation. - -.TP +.SH DESCRIPTION +\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it +for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of +\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR. + +.SH OPTIONS +.TP +\fB-t\fR +Disables any modification of the disk drive. \fBdasdfmt\fR just prints +out, what it \fBwould\fR do. + +.TP +\fB-v\fR +Increases verbosity. + +.TP +\fB-y\fR +Start formatting without further user-confirmation. + +.TP \fB-L\fR Omit the writing of a disk label after formatting. .TP -\fB-V\fR -Print version number and exit. - -.TP -\fB-b\fR \fIblockSize\fR -Specify blocksize to be used. \fIblocksize\fR must be a positive integer -and always be a power of two. Due due some limitations in the driver, -it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR. - -.TP +\fB-V\fR +Print version number and exit. + +.TP +\fB-b\fR \fIblockSize\fR +Specify blocksize to be used. \fIblocksize\fR must be a positive integer +and always be a power of two. Due due some limitations in the driver, +it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR. + +.TP \fB-l\fR \fIdiskLabel\fR Specify the label to be written to disk after formatting. If no label is specified, a sensible default is used. \fIdiskLabel\fR is interpreted as ASCII string and is automatically converted to EBCDIC. - -.TP -\fIdiskSpec\fR -This parameter specified the device to be formatted. It also can be -given in two variants: -.sp + +.TP +\fIdiskSpec\fR +This parameter specified the device to be formatted. It also can be +given in two variants: +.sp \fB-f\fR \fB/dev/dasd\fR\fIX\fR -.br -or -.br - \fB-n\fR \fIdevnum\fR -.sp -The first form uses the commonly used -.SM UNIX -device notation where \fIX\fR is a single lowercase letter. +.br +or +.br + \fB-n\fR \fIdevnum\fR +.sp +The first form uses the commonly used +.SM UNIX +device notation where \fIX\fR is a single lowercase letter. The second form uses simply the device number. - -.SH BUGS -None so far ;-) - -.SH AUTHOR -.nf -This man-page was written by Fritz Elfert -.fi + +.SH BUGS +None so far ;-) + +.SH AUTHOR +.nf +This man-page was written by Fritz Elfert +.fi diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c --- v2.2.17/arch/s390/tools/dasdfmt/dasdfmt.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.c Wed Nov 8 23:04:59 2000 @@ -458,12 +458,11 @@ void do_format_dasd(char *dev_name,format_data_t format_params,int testmode, int verbosity,int writenolabel,int labelspec, - char *label,int withoutprompt) + char *label,int withoutprompt,int devno) { int fd,rc; struct stat stat_buf; kdev_t minor_no,major_no; - int devno; int new_blksize; unsigned int label_position; struct hd_geometry new_geometry; @@ -489,7 +488,7 @@ minor_no=MINOR(stat_buf.st_rdev); } check_mounted(major_no, minor_no); - + if ((!writenolabel) && (!labelspec)) { sprintf(label,"LNX1 x%04x",devno); } @@ -645,9 +644,10 @@ endptr=NULL; /* set default values */ - format_params.start_unit=0; - format_params.stop_unit=-1; - format_params.blksize=4096; + format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT; + format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT; + format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE; + format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY; testmode=0; verbosity=0; withoutprompt=0; @@ -811,7 +811,7 @@ /******* issue the real command and reread part table *******/ do_format_dasd(dev_name,format_params,testmode,verbosity, - writenolabel,labelspec,label,withoutprompt); + writenolabel,labelspec,label,withoutprompt,devno); /*************** cleanup ********************************/ if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/hwc/Makefile linux/arch/s390/tools/hwc/Makefile --- v2.2.17/arch/s390/tools/hwc/Makefile Thu Jan 1 01:00:00 1970 +++ linux/arch/s390/tools/hwc/Makefile Wed Nov 8 23:04:59 2000 @@ -0,0 +1,12 @@ +CROSS_COMPILE = s390- + +hwc_measure: hwc_measure.c + $(CROSS_COMPILE)gcc -o $@ $^ + +hwc_cntl_key: hwc_cntl_key.c + $(CROSS_COMPILE)gcc -o $@ $^ + +clean: + rm -f hwc_measure + rm -f hwc_cntl_key + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/hwc/hwc_cntl_key.c linux/arch/s390/tools/hwc/hwc_cntl_key.c --- v2.2.17/arch/s390/tools/hwc/hwc_cntl_key.c Thu Jan 1 01:00:00 1970 +++ linux/arch/s390/tools/hwc/hwc_cntl_key.c Wed Nov 8 23:04:59 2000 @@ -0,0 +1,69 @@ +/* + * small application to set string that will be used as CNTL-C + * employing a HWC terminal ioctl command + * + * returns: number of written or read characters + * + * Copyright (C) 2000 IBM Corporation + * Author(s): Martin Peschke + */ + +#include +#include + +/* everything about the HWC terminal driver ioctl-commands */ +#include "../../../../drivers/s390/char/hwc_tty.h" + +/* standard input, should be our HWC tty */ +#define DESCRIPTOR 0 + +int main(int argc, char *argv[], char *env[]) +{ + unsigned char buf[HWC_TTY_MAX_CNTL_SIZE]; + + if (argc >= 2) { + if (strcmp(argv[1], "c") == 0 || + strcmp(argv[1], "C") == 0 || + strcmp(argv[1], "INTR_CHAR") == 0) { + if (argc == 2) { + ioctl(DESCRIPTOR, TIOCHWCTTYGINTRC, buf); + printf("%s\n", buf); + return strlen(buf); + } else return ioctl(DESCRIPTOR, TIOCHWCTTYSINTRC, argv[2]); +// currently not yet implemented in HWC terminal driver +#if 0 + } else if (strcmp(argv[1], "d") == 0 || + strcmp(argv[1], "D") == 0 || + strcmp(argv[1], "EOF_CHAR") == 0) { + if (argc == 2) { + ioctl(DESCRIPTOR, TIOCHWCTTYGEOFC, buf); + printf("%s\n", buf); + return strlen(buf); + } else return ioctl(DESCRIPTOR, TIOCHWCTTYSEOFC, argv[2]); + } else if (strcmp(argv[1], "z") == 0 || + strcmp(argv[1], "Z") == 0 || + strcmp(argv[1], "SUSP_CHAR") == 0) { + if (argc == 2) { + ioctl(DESCRIPTOR, TIOCHWCTTYGSUSPC, buf); + printf("%s\n", buf); + return strlen(buf); + } else return ioctl(DESCRIPTOR, TIOCHWCTTYSSUSPC, argv[2]); + } else if (strcmp(argv[1], "n") == 0 || + strcmp(argv[1], "N") == 0 || + strcmp(argv[1], "NEW_LINE") == 0) { + if (argc == 2) { + ioctl(DESCRIPTOR, TIOCHWCTTYGNL, buf); + printf("%s\n", buf); + return strlen(buf); + } else return ioctl(DESCRIPTOR, TIOCHWCTTYSNL, argv[2]); +#endif + } + } + + printf("usage: hwc_cntl_key []\n"); + printf(" ::= \"c\" | \"C\" | \"INTR_CHAR\" |\n"); + printf(" \"d\" | \"D\" | \"EOF_CHAR\" |\n"); + printf(" \"z\" | \"Z\" | \"SUSP_CHAR\" |\n"); + printf(" \"n\" | \"N\" | \"NEW_LINE\"\n"); + return -1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/hwc/hwc_measure.c linux/arch/s390/tools/hwc/hwc_measure.c --- v2.2.17/arch/s390/tools/hwc/hwc_measure.c Thu Jan 1 01:00:00 1970 +++ linux/arch/s390/tools/hwc/hwc_measure.c Wed Nov 8 23:04:59 2000 @@ -0,0 +1,79 @@ +/* + * small application for HWC measurement + * + * Copyright (C) 2000 IBM Corporation + * Author(s): Martin Peschke + */ + +#include +#include +#include +#include + +/* everything about the HWC low level driver ioctl-commands */ +#include "../../../../drivers/s390/char/hwc_rw.h" + +/* standard input, should be our HWC tty */ +#define DESCRIPTOR 0 + +int main(int argc, char *argv[], char *env[]) +{ + ioctl_meas_t measured = 0; + signed int retval = 0; + + if (argc = 2) { + + if (strcmp(argv[1], "lines") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCGMEASL, + &measured); + if (retval < 0) + return errno; + else { + printf("%ld\n", measured); + return retval; + } + } + + if (strcmp(argv[1], "chars") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCGMEASC, + &measured); + if (retval < 0) + return errno; + else { + printf("%ld\n", measured); + return retval; + } + } + + if (strcmp(argv[1], "wcalls") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCGMEASS, + &measured); + if (retval < 0) + return errno; + else { + printf("%ld\n", measured); + return retval; + } + } + + if (strcmp(argv[1], "reset") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCSMEAS); + if (retval < 0) + return errno; + else return retval; + } + } + + printf("usage:\n"); + printf(" hwc_measure lines " + "(prints # of measured lines) or\n"); + printf(" hwc_measure_chars " + "(prints # of measured characters) or\n"); + printf(" hwc_measure wcalls " + "(prints # of measured write calls to HWC interface) or\n"); + printf(" hwc_measure reset " + "(resets measurement counters)\n"); + + return -1; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/hwc_cntl_key/Makefile linux/arch/s390/tools/hwc_cntl_key/Makefile --- v2.2.17/arch/s390/tools/hwc_cntl_key/Makefile Sun Jun 11 21:44:11 2000 +++ linux/arch/s390/tools/hwc_cntl_key/Makefile Thu Jan 1 01:00:00 1970 @@ -1,11 +0,0 @@ -CROSS_COMPILE = s390- - -all: hwc_cntl_key - -hwc_cntl_key: hwc_cntl_key.c - $(CROSS_COMPILE)gcc -o $@ $^ - $(STRIP) $@ - -clean: - rm -f hwc_cntl_key.c - diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c linux/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c --- v2.2.17/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c Thu Jan 1 01:00:00 1970 @@ -1,69 +0,0 @@ -/* - * small application to set string that will be used as CNTL-C - * employing a HWC terminal ioctl command - * - * returns: number of written or read characters - * - * Copyright (C) 2000 IBM Corporation - * Author(s): Martin Peschke - */ - -#include -#include - -/* everything about the HWC terminal driver ioctl-commands */ -#include "../../../../drivers/s390/char/hwc_tty.h" - -/* standard input, should be our HWC tty */ -#define DESCRIPTOR 0 - -int main(int argc, char *argv[], char *env[]) -{ - unsigned char buf[HWC_TTY_MAX_CNTL_SIZE]; - - if (argc >= 2) { - if (strcmp(argv[1], "c") == 0 || - strcmp(argv[1], "C") == 0 || - strcmp(argv[1], "INTR_CHAR") == 0) { - if (argc == 2) { - ioctl(DESCRIPTOR, TIOCHWCTTYGINTRC, buf); - printf("%s\n", buf); - return strlen(buf); - } else return ioctl(DESCRIPTOR, TIOCHWCTTYSINTRC, argv[2]); -// currently not yet implemented in HWC terminal driver -#if 0 - } else if (strcmp(argv[1], "d") == 0 || - strcmp(argv[1], "D") == 0 || - strcmp(argv[1], "EOF_CHAR") == 0) { - if (argc == 2) { - ioctl(DESCRIPTOR, TIOCHWCTTYGEOFC, buf); - printf("%s\n", buf); - return strlen(buf); - } else return ioctl(DESCRIPTOR, TIOCHWCTTYSEOFC, argv[2]); - } else if (strcmp(argv[1], "z") == 0 || - strcmp(argv[1], "Z") == 0 || - strcmp(argv[1], "SUSP_CHAR") == 0) { - if (argc == 2) { - ioctl(DESCRIPTOR, TIOCHWCTTYGSUSPC, buf); - printf("%s\n", buf); - return strlen(buf); - } else return ioctl(DESCRIPTOR, TIOCHWCTTYSSUSPC, argv[2]); - } else if (strcmp(argv[1], "n") == 0 || - strcmp(argv[1], "N") == 0 || - strcmp(argv[1], "NEW_LINE") == 0) { - if (argc == 2) { - ioctl(DESCRIPTOR, TIOCHWCTTYGNL, buf); - printf("%s\n", buf); - return strlen(buf); - } else return ioctl(DESCRIPTOR, TIOCHWCTTYSNL, argv[2]); -#endif - } - } - - printf("usage: hwc_cntl_key []\n"); - printf(" ::= \"c\" | \"C\" | \"INTR_CHAR\" |\n"); - printf(" \"d\" | \"D\" | \"EOF_CHAR\" |\n"); - printf(" \"z\" | \"Z\" | \"SUSP_CHAR\" |\n"); - printf(" \"n\" | \"N\" | \"NEW_LINE\"\n"); - return -1; -} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/tools/silo/silo.c linux/arch/s390/tools/silo/silo.c --- v2.2.17/arch/s390/tools/silo/silo.c Sat Sep 9 18:42:33 2000 +++ linux/arch/s390/tools/silo/silo.c Wed Nov 8 23:04:59 2000 @@ -144,7 +144,7 @@ if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp) o->parmfile = tmp; if ( ! o -> ramdisk ) - o->ramdisk = cfg_get_strg(cf_options, "ramdisk"); + o->ramdisk = cfg_get_strg(cf_options, "ramdisk"); tmp = cfg_get_strg(cf_options, "bootsect"); if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp) o->bootsect = tmp; @@ -181,7 +181,7 @@ return pfile; of = fopen(pfile, "r"); if ( of ) { - NTRY( fn = tempnam(NULL,"parm.")); + NTRY( fn = tempnam(NULL,"parm.")); } else { fn = pfile; } @@ -193,11 +193,11 @@ } } if (root) - fprintf(f, "root=%s ", root); + fprintf(f, " root=%s", root); if (ro) - fprintf(f, "ro "); + fprintf(f, " ro"); if (append) - fprintf(f, "%s", append); + fprintf(f, " %s", append); fprintf(f, "\n"); fclose(f); fclose(of); @@ -312,7 +312,7 @@ int bs = 1024; int l; - ITRY (stat (name, &dst)); + ITRY(stat ( name, &dst )); if (S_ISREG (dst.st_mode)) { if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK)) @@ -394,9 +394,9 @@ PRINT_LEVEL (1, "...ok..."); o->parmfile = gen_tmpparm(o->parmfile); PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile); - ITRY (verify_file (o->parmfile, dev)); - PRINT_LEVEL (1, "...ok..."); - PRINT_LEVEL (0, "\n"); + ITRY (verify_file (o->parmfile, dev)); + PRINT_LEVEL (1, "...ok..."); + PRINT_LEVEL (0, "\n"); if (o->ramdisk) { @@ -492,9 +492,9 @@ int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff); PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr); if ( o->testlevel <= 1 ) { - NTRY (write (s_fd, &offset, sizeof (int))); - NTRY (write (s_fd, &addrct, sizeof (int))); - } + NTRY (write (s_fd, &offset, sizeof (int))); + NTRY (write (s_fd, &addrct, sizeof (int))); + } } ITRY (ioctl (s_fd,FIGETBSZ, &bs)); ITRY (stat (o->bootmap, &s_st)); @@ -508,7 +508,7 @@ NTRY ( tmpdev = tmpnam(NULL) ); ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev)); ITRY (bd_fd = open (tmpdev, O_RDONLY)); - ITRY ( ioctl(s_fd,FIBMAP,&boots)); + ITRY (ioctl(s_fd,FIBMAP,&boots)); ITRY (ioctl (bd_fd, BIODASDRWTB, &boots)); PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots); close (bd_fd); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/s390/vmlinux.lds linux/arch/s390/vmlinux.lds --- v2.2.17/arch/s390/vmlinux.lds Fri Apr 21 12:45:48 2000 +++ linux/arch/s390/vmlinux.lds Tue Sep 5 22:20:06 2000 @@ -42,8 +42,16 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; + . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/config.in linux/arch/sparc/config.in --- v2.2.17/arch/sparc/config.in Sun Jun 11 21:44:11 2000 +++ linux/arch/sparc/config.in Thu Nov 2 13:05:35 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.68.2.1 1999/09/22 11:37:34 jj Exp $ +# $Id: config.in,v 1.68.2.7 2000/10/24 21:00:53 davem Exp $ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # @@ -23,6 +23,9 @@ define_bool CONFIG_VT y define_bool CONFIG_VT_CONSOLE y + +# Identify this as a Sparc32 build +define_bool CONFIG_SPARC32 y bool 'Support for AP1000 multicomputer' CONFIG_AP1000 bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.2.17/arch/sparc/defconfig Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/defconfig Sat Nov 18 00:37:55 2000 @@ -19,6 +19,7 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y +CONFIG_SPARC32=y # CONFIG_AP1000 is not set # CONFIG_SMP is not set # CONFIG_SUN4 is not set @@ -69,8 +70,8 @@ # # CONFIG_SPARCAUDIO is not set # CONFIG_SPARCAUDIO_AMD7930 is not set -# CONFIG_SPARCAUDIO_CS4231 is not set # CONFIG_SPARCAUDIO_DBRI is not set +# CONFIG_SPARCAUDIO_CS4231 is not set # CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y @@ -93,6 +94,7 @@ CONFIG_MD_MIRRORING=m CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m @@ -133,6 +135,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set +# CONFIG_NET_DIVERT is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -258,11 +261,14 @@ # CONFIG_CODA_FS=m CONFIG_NFS_FS=y +CONFIG_NFS_V3=y CONFIG_NFSD=m -# CONFIG_NFSD_SUN is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set CONFIG_NCP_FS=m # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set @@ -287,6 +293,7 @@ # # Native Language Support # +CONFIG_NLS_DEFAULT="cp437" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -303,6 +310,10 @@ # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v2.2.17/arch/sparc/kernel/entry.S Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/kernel/entry.S Sat Oct 14 00:28:12 2000 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.159.2.7 2000/01/21 01:05:35 davem Exp $ +/* $Id: entry.S,v 1.159.2.8 2000/10/05 04:17:17 anton Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1807,13 +1807,13 @@ C_LABEL(udelay): save %sp, -REGWIN_SZ, %sp mov %i0, %o0 - sethi %hi(0x10c6), %o1 + sethi %hi(0x10c600), %o1 call .umul - or %o1, %lo(0x10c6), %o1 + or %o1, %lo(0x10c600), %o1 #ifndef __SMP__ - sethi %hi(C_LABEL(loops_per_sec)), %o3 + sethi %hi(C_LABEL(loops_per_jiffy)), %o3 call .umul - ld [%o3 + %lo(C_LABEL(loops_per_sec))], %o1 + ld [%o3 + %lo(C_LABEL(loops_per_jiffy))], %o1 #else GET_PROCESSOR_OFFSET(o4, o2) set C_LABEL(cpu_data), %o3 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.2.17/arch/sparc/kernel/setup.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/kernel/setup.c Sat Oct 14 00:28:12 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.105.2.1 1999/11/16 06:29:31 davem Exp $ +/* $Id: setup.c,v 1.105.2.2 2000/10/05 04:17:17 anton Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -531,7 +531,7 @@ &cputypval, linux_num_cpus, smp_num_cpus #ifndef __SMP__ - , loops_per_sec/500000, (loops_per_sec/5000) % 100 + , loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100 #endif ); #ifdef __SMP__ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.2.17/arch/sparc/kernel/smp.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/kernel/smp.c Sat Oct 14 00:28:12 2000 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -85,7 +86,7 @@ __initfunc(void smp_store_cpu_info(int id)) { - cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */ + cpu_data[id].udelay_val = loops_per_jiffy; /* this is it on sparc. */ } __initfunc(void smp_commence(void)) @@ -288,8 +289,8 @@ if (cpu_present_map & (1 << i)) len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", i, - cpu_data[i].udelay_val/500000, - (cpu_data[i].udelay_val/5000)%100); + cpu_data[i].udelay_val/(500000/HZ), + (cpu_data[i].udelay_val/(5000/HZ))%100); return len; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.2.17/arch/sparc/kernel/sparc_ksyms.c Sat Sep 9 18:42:34 2000 +++ linux/arch/sparc/kernel/sparc_ksyms.c Sun Sep 17 17:57:13 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.77.2.5 2000/07/17 18:44:26 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.77.2.6 2000/09/16 14:15:15 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -65,6 +65,7 @@ extern int __ashrdi3(int, int); extern int __ashldi3(int, int); extern int __lshrdi3(int, int); +extern int __muldi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); @@ -272,6 +273,7 @@ EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(__ashldi3); EXPORT_SYMBOL_NOVERS(__lshrdi3); +EXPORT_SYMBOL_NOVERS(__muldi3); EXPORT_SYMBOL_DOT(rem); EXPORT_SYMBOL_DOT(urem); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c --- v2.2.17/arch/sparc/kernel/sun4d_smp.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/kernel/sun4d_smp.c Sat Oct 14 00:28:12 2000 @@ -278,11 +278,11 @@ smp_highest_cpu = i; } } - SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, (bogosum + 2500)/500000, ((bogosum + 2500)/5000)%100)); + SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100)); printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, - (bogosum + 2500)/500000, - ((bogosum + 2500)/5000)%100); + bogosum/(500000/HZ), + (bogosum/(5000/HZ))%100); smp_activated = 1; smp_num_cpus = cpucount + 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c --- v2.2.17/arch/sparc/kernel/sun4m_smp.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/kernel/sun4m_smp.c Sat Oct 14 00:28:12 2000 @@ -243,8 +243,8 @@ } printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, - (bogosum + 2500)/500000, - ((bogosum + 2500)/5000)%100); + bogosum/(500000/HZ), + (bogosum/(5000/HZ))%100); smp_activated = 1; smp_num_cpus = cpucount + 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.2.17/arch/sparc/kernel/sys_sunos.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/kernel/sys_sunos.c Sun Sep 17 17:57:13 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.94.2.4 2000/01/17 21:28:27 davem Exp $ +/* $Id: sys_sunos.c,v 1.94.2.5 2000/09/16 14:15:15 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -707,7 +707,7 @@ #define SMNT_SYS5 128 struct sunos_fh_t { - char fh_data [NFS_FHSIZE]; + char fh_data [NFS2_FHSIZE]; }; struct sunos_nfs_mount_args { @@ -774,7 +774,7 @@ server.sin_family = AF_INET; server.sin_addr = addr->sin_addr; - server.sin_port = NFS_PORT; + server.sin_port = NFS2_PORT; /* Call sys_connect */ ret = socket->ops->connect (socket, (struct sockaddr *) &server, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile --- v2.2.17/arch/sparc/lib/Makefile Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/lib/Makefile Sun Sep 17 17:57:13 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.28.2.1 1999/09/28 16:47:36 davem Exp $ +# $Id: Makefile,v 1.28.2.2 2000/09/16 14:15:15 davem Exp $ # Makefile for Sparc library files.. # @@ -6,7 +6,7 @@ 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 \ - ashldi3.o + ashldi3.o muldi3.o ifdef CONFIG_SMP OBJS += irqlock.o diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/lib/muldi3.S linux/arch/sparc/lib/muldi3.S --- v2.2.17/arch/sparc/lib/muldi3.S Thu Jan 1 01:00:00 1970 +++ linux/arch/sparc/lib/muldi3.S Fri Sep 15 22:10:43 2000 @@ -0,0 +1,76 @@ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + .text + .align 4 + .globl __muldi3 +__muldi3: + save %sp, -104, %sp + wr %g0, %i1, %y + sra %i3, 0x1f, %g2 + and %i1, %g2, %g2 + andcc %g0, 0, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, %i3, %g1 + mulscc %g1, 0, %g1 + add %g1, %g2, %l2 + rd %y, %o1 + mov %o1, %l3 + mov %i1, %o0 + call .umul + mov %i2, %o1 + mov %o0, %l0 + mov %i0, %o0 + call .umul + mov %i3, %o1 + add %l0, %o0, %l0 + mov %l2, %i0 + add %l2, %l0, %i0 + ret + restore %g0, %l3, %o1 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.2.17/arch/sparc/mm/srmmu.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/mm/srmmu.c Wed Sep 13 16:48:19 2000 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.187.2.9 2000/03/05 17:39:18 davem Exp $ +/* $Id: srmmu.c,v 1.187.2.10 2000/09/07 04:44:48 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -2056,8 +2056,8 @@ goto done; inode = file->f_dentry->d_inode; offset = (address & PAGE_MASK) - vma->vm_start; - vmaring = inode->i_mmap; - do { + vmaring = inode->i_mmap_shared; + if (vmaring) do { /* Do not mistake ourselves as another mapping. */ if(vmaring == vma) continue; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.2.17/arch/sparc/mm/sun4c.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/mm/sun4c.c Wed Sep 13 16:48:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.173.2.5 1999/10/11 08:24:44 davem Exp $ +/* $Id: sun4c.c,v 1.173.2.6 2000/09/07 04:44:48 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -2420,9 +2420,9 @@ inode = dentry->d_inode; if (inode) { unsigned long offset = (address & PAGE_MASK) - vma->vm_start; - struct vm_area_struct *vmaring = inode->i_mmap; + struct vm_area_struct *vmaring = inode->i_mmap_shared; int alias_found = 0; - do { + if (vmaring) do { unsigned long vaddr = vmaring->vm_start + offset; unsigned long start; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc/vmlinux.lds linux/arch/sparc/vmlinux.lds --- v2.2.17/arch/sparc/vmlinux.lds Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc/vmlinux.lds Sun Sep 10 14:47:06 2000 @@ -40,8 +40,17 @@ .text.init : { *(.text.init) } __init_text_end = .; .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); __init_end = .; + + __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.2.17/arch/sparc64/config.in Sat Sep 9 18:42:34 2000 +++ linux/arch/sparc64/config.in Thu Nov 2 13:05:35 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.67.2.11 2000/07/27 01:50:59 davem Exp $ +# $Id: config.in,v 1.67.2.13 2000/10/24 21:00:53 davem Exp $ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # @@ -26,12 +26,8 @@ bool 'Symmetric multi-processing support' CONFIG_SMP -mainmenu_option next_comment -comment 'Console drivers' -bool 'PROM console' CONFIG_PROM_CONSOLE -bool 'Support Frame buffer devices' CONFIG_FB -source drivers/video/Config.in -endmenu +# Identify this as a Sparc64 build +define_bool CONFIG_SPARC64 y # Global things across all Sun machines. define_bool CONFIG_SBUS y @@ -45,6 +41,14 @@ define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y bool 'PCI support' CONFIG_PCI + +mainmenu_option next_comment +comment 'Console drivers' +bool 'PROM console' CONFIG_PROM_CONSOLE +bool 'Support Frame buffer devices' CONFIG_FB +source drivers/video/Config.in +endmenu + source drivers/sbus/char/Config.in source drivers/sbus/audio/Config.in @@ -247,9 +251,10 @@ tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN fi -# bool 'FDDI driver support' CONFIG_FDDI -# if [ "$CONFIG_FDDI" = "y" ]; then -# fi + bool 'FDDI driver support' CONFIG_FDDI + if [ "$CONFIG_FDDI" = "y" ]; then + tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP + fi fi endmenu fi @@ -271,6 +276,12 @@ dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV fi fi +endmenu + +mainmenu_option next_comment +comment 'XFree86 DRI support' +bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM +dep_tristate ' Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM endmenu source fs/Config.in diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.2.17/arch/sparc64/defconfig Sat Sep 9 18:42:34 2000 +++ linux/arch/sparc64/defconfig Sat Nov 18 00:37:55 2000 @@ -20,6 +20,18 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_SMP is not set +CONFIG_SPARC64=y +CONFIG_SBUS=y +CONFIG_SBUSCHAR=y +CONFIG_SUN_MOUSE=y +CONFIG_SERIAL=y +CONFIG_SUN_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SUN_KEYBOARD=y +CONFIG_SUN_CONSOLE=y +CONFIG_SUN_AUXIO=y +CONFIG_SUN_IO=y +CONFIG_PCI=y # # Console drivers @@ -31,8 +43,6 @@ # CONFIG_FB_PM2_FIFO_DISCONNECT is not set CONFIG_FB_PM2_PCI=y CONFIG_FB_ATY=y -# CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY128 is not set CONFIG_FB_SBUS=y CONFIG_FB_CREATOR=y CONFIG_FB_CGSIX=y @@ -50,17 +60,6 @@ CONFIG_FBCON_FONTWIDTH8_ONLY=y CONFIG_FONT_SUN8x16=y # CONFIG_FBCON_FONTS is not set -CONFIG_SBUS=y -CONFIG_SBUSCHAR=y -CONFIG_SUN_MOUSE=y -CONFIG_SERIAL=y -CONFIG_SUN_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -CONFIG_SUN_KEYBOARD=y -CONFIG_SUN_CONSOLE=y -CONFIG_SUN_AUXIO=y -CONFIG_SUN_IO=y -CONFIG_PCI=y # # Misc Linux/SPARC drivers @@ -77,9 +76,7 @@ # Linux/SPARC audio subsystem (EXPERIMENTAL) # CONFIG_SPARCAUDIO=y -# CONFIG_SPARCAUDIO_AMD7930 is not set CONFIG_SPARCAUDIO_CS4231=y -# CONFIG_SPARCAUDIO_DBRI is not set # CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m CONFIG_PCI_OLD_PROC=y @@ -102,6 +99,7 @@ CONFIG_PRINTER=m CONFIG_PRINTER_READBACK=y CONFIG_ENVCTRL=m +CONFIG_DISPLAY7SEG=m # # Floppy, IDE, and other block devices @@ -113,6 +111,7 @@ CONFIG_MD_MIRRORING=m CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m @@ -164,6 +163,7 @@ # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set +# CONFIG_NET_DIVERT is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -262,6 +262,8 @@ CONFIG_NE2K_PCI=m CONFIG_EEXPRESS_PRO100=m CONFIG_SK98LIN=m +CONFIG_FDDI=y +CONFIG_SKFP=m # # Unix 98 PTY support @@ -276,6 +278,12 @@ CONFIG_VIDEO_BT848=y # +# XFree86 DRI support +# +CONFIG_DRM=y +CONFIG_DRM_FFB=m + +# # Filesystems # # CONFIG_QUOTA is not set @@ -308,11 +316,14 @@ # CONFIG_CODA_FS=m CONFIG_NFS_FS=y +CONFIG_NFS_V3=y CONFIG_NFSD=m -# CONFIG_NFSD_SUN is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set CONFIG_NCP_FS=m # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.2.17/arch/sparc64/kernel/entry.S Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc64/kernel/entry.S Wed Sep 13 16:48:19 2000 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.103.2.5 2000/03/06 22:30:22 davem Exp $ +/* $Id: entry.S,v 1.103.2.6 2000/09/08 14:00:04 jj Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -958,9 +958,9 @@ 1: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 -sparc_exit: rdpr %otherwin, %g1 - rdpr %pstate, %g2 +sparc_exit: rdpr %pstate, %g2 wrpr %g2, PSTATE_IE, %pstate + rdpr %otherwin, %g1 rdpr %cansave, %g3 add %g3, %g1, %g3 wrpr %g3, 0x0, %cansave diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.2.17/arch/sparc64/kernel/ioctl32.c Sat Sep 9 18:42:34 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Wed Nov 8 22:48:54 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.62.2.13 2000/07/27 01:50:59 davem Exp $ +/* $Id: ioctl32.c,v 1.62.2.17 2000/11/08 09:43:04 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -41,6 +41,9 @@ #include #include #include +#include +#include +#include #include /* Ugly hack. */ @@ -622,30 +625,64 @@ }; +struct in6_rtmsg32 { + struct in6_addr rtmsg_dst; + struct in6_addr rtmsg_src; + struct in6_addr rtmsg_gateway; + u32 rtmsg_type; + u16 rtmsg_dst_len; + u16 rtmsg_src_len; + u32 rtmsg_metric; + u32 rtmsg_info; + u32 rtmsg_flags; + s32 rtmsg_ifindex; +}; + +extern struct socket *sockfd_lookup(int fd, int *err); + static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct rtentry r; + int ret; + void *r = NULL; + struct in6_rtmsg r6; + struct rtentry r4; char devname[16]; u32 rtdev; - int ret; mm_segment_t old_fs = get_fs(); - - ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); - ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); - ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); - ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); - ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window)); - ret |= __get_user (r.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); - ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); - if (rtdev) { - ret |= copy_from_user (devname, (char *)A(rtdev), 15); - r.rt_dev = devname; devname[15] = 0; - } else - r.rt_dev = 0; + struct socket *mysock = sockfd_lookup(fd, &ret); + + if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */ + ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst), + 3 * sizeof(struct in6_addr)); + ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type)); + ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len)); + ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len)); + ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric)); + ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info)); + ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags)); + ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex)); + + r = (void *)&r6; + } else { /* ipv4 */ + ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); + ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); + ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); + ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); + ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window)); + ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); + ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); + if (rtdev) { + ret |= copy_from_user (devname, (char *)A(rtdev), 15); + r4.rt_dev = devname; devname[15] = 0; + } else + r4.rt_dev = 0; + + r = (void *)&r4; + } if (ret) return -EFAULT; set_fs (KERNEL_DS); - ret = sys_ioctl (fd, cmd, (long)&r); + ret = sys_ioctl (fd, cmd, (unsigned long) r); set_fs (old_fs); return ret; } @@ -1739,6 +1776,544 @@ return err; } +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) +/* This really belongs in include/linux/drm.h -DaveM */ +#include "../../../drivers/char/drm/drm.h" + +typedef struct drm32_version { + int version_major; /* Major version */ + int version_minor; /* Minor version */ + int version_patchlevel;/* Patch level */ + int name_len; /* Length of name buffer */ + u32 name; /* Name of driver */ + int date_len; /* Length of date buffer */ + u32 date; /* User-space buffer to hold date */ + int desc_len; /* Length of desc buffer */ + u32 desc; /* User-space buffer to hold desc */ +} drm32_version_t; +#define DRM32_IOCTL_VERSION DRM_IOWR(0x00, drm32_version_t) + +static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_version_t *uversion = (drm32_version_t *)arg; + char *name_ptr, *date_ptr, *desc_ptr; + u32 tmp1, tmp2, tmp3; + drm_version_t kversion; + mm_segment_t old_fs; + int ret; + + memset(&kversion, 0, sizeof(kversion)); + if (get_user(kversion.name_len, &uversion->name_len) || + get_user(kversion.date_len, &uversion->date_len) || + get_user(kversion.desc_len, &uversion->desc_len) || + get_user(tmp1, &uversion->name) || + get_user(tmp2, &uversion->date) || + get_user(tmp3, &uversion->desc)) + return -EFAULT; + + name_ptr = (char *) A(tmp1); + date_ptr = (char *) A(tmp2); + desc_ptr = (char *) A(tmp3); + + ret = -ENOMEM; + if (kversion.name_len && name_ptr) { + kversion.name = kmalloc(kversion.name_len, GFP_KERNEL); + if (!kversion.name) + goto out; + } + if (kversion.date_len && date_ptr) { + kversion.date = kmalloc(kversion.date_len, GFP_KERNEL); + if (!kversion.date) + goto out; + } + if (kversion.desc_len && desc_ptr) { + kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL); + if (!kversion.desc) + goto out; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion); + set_fs(old_fs); + + if (!ret) { + if ((kversion.name && + copy_to_user(name_ptr, kversion.name, kversion.name_len)) || + (kversion.date && + copy_to_user(date_ptr, kversion.date, kversion.date_len)) || + (kversion.desc && + copy_to_user(desc_ptr, kversion.desc, kversion.desc_len))) + ret = -EFAULT; + if (put_user(kversion.version_major, &uversion->version_major) || + put_user(kversion.version_minor, &uversion->version_minor) || + put_user(kversion.version_patchlevel, &uversion->version_patchlevel) || + put_user(kversion.name_len, &uversion->name_len) || + put_user(kversion.date_len, &uversion->date_len) || + put_user(kversion.desc_len, &uversion->desc_len)) + ret = -EFAULT; + } + +out: + if (kversion.name) + kfree(kversion.name); + if (kversion.date) + kfree(kversion.date); + if (kversion.desc) + kfree(kversion.desc); + return ret; +} + +typedef struct drm32_unique { + int unique_len; /* Length of unique */ + u32 unique; /* Unique name for driver instantiation */ +} drm32_unique_t; +#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t) +#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t) + +static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_unique_t *uarg = (drm32_unique_t *)arg; + drm_unique_t karg; + mm_segment_t old_fs; + char *uptr; + u32 tmp; + int ret; + + if (get_user(karg.unique_len, &uarg->unique_len)) + return -EFAULT; + karg.unique = NULL; + + if (get_user(tmp, &uarg->unique)) + return -EFAULT; + + uptr = (char *) A(tmp); + + if (uptr) { + karg.unique = kmalloc(karg.unique_len, GFP_KERNEL); + if (!karg.unique) + return -ENOMEM; + if (cmd == DRM32_IOCTL_SET_UNIQUE && + copy_from_user(karg.unique, uptr, karg.unique_len)) { + kfree(karg.unique); + return -EFAULT; + } + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + if (cmd == DRM32_IOCTL_GET_UNIQUE) + ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg); + else + ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg); + set_fs(old_fs); + + if (!ret) { + if (cmd == DRM32_IOCTL_GET_UNIQUE && + uptr != NULL && + copy_to_user(uptr, karg.unique, karg.unique_len)) + ret = -EFAULT; + if (put_user(karg.unique_len, &uarg->unique_len)) + ret = -EFAULT; + } + + if (karg.unique != NULL) + kfree(karg.unique); + + return ret; +} + +typedef struct drm32_map { + u32 offset; /* Requested physical address (0 for SAREA)*/ + u32 size; /* Requested physical size (bytes) */ + drm_map_type_t type; /* Type of memory to map */ + drm_map_flags_t flags; /* Flags */ + u32 handle; /* User-space: "Handle" to pass to mmap */ + /* Kernel-space: kernel-virtual address */ + int mtrr; /* MTRR slot used */ + /* Private data */ +} drm32_map_t; +#define DRM32_IOCTL_ADD_MAP DRM_IOWR(0x15, drm32_map_t) + +static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_map_t *uarg = (drm32_map_t *) arg; + drm_map_t karg; + mm_segment_t old_fs; + u32 tmp; + int ret; + + ret = get_user(karg.offset, &uarg->offset); + ret |= get_user(karg.size, &uarg->size); + ret |= get_user(karg.type, &uarg->type); + ret |= get_user(karg.flags, &uarg->flags); + ret |= get_user(tmp, &uarg->handle); + ret |= get_user(karg.mtrr, &uarg->mtrr); + if (ret) + return -EFAULT; + + karg.handle = (void *) A(tmp); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + ret = put_user(karg.offset, &uarg->offset); + ret |= put_user(karg.size, &uarg->size); + ret |= put_user(karg.type, &uarg->type); + ret |= put_user(karg.flags, &uarg->flags); + tmp = (u32) (long)karg.handle; + ret |= put_user(tmp, &uarg->handle); + ret |= put_user(karg.mtrr, &uarg->mtrr); + if (ret) + ret = -EFAULT; + } + + return ret; +} + +typedef struct drm32_buf_info { + int count; /* Entries in list */ + u32 list; /* (drm_buf_desc_t *) */ +} drm32_buf_info_t; +#define DRM32_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm32_buf_info_t) + +static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg; + drm_buf_desc_t *ulist; + drm_buf_info_t karg; + mm_segment_t old_fs; + int orig_count, ret; + u32 tmp; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->list)) + return -EFAULT; + + ulist = (drm_buf_desc_t *) A(tmp); + + orig_count = karg.count; + + karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL); + if (!karg.list) + return -EFAULT; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (karg.count <= orig_count && + (copy_to_user(ulist, karg.list, + karg.count * sizeof(drm_buf_desc_t)))) + ret = -EFAULT; + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + + kfree(karg.list); + + return ret; +} + +typedef struct drm32_buf_free { + int count; + u32 list; /* (int *) */ +} drm32_buf_free_t; +#define DRM32_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm32_buf_free_t) + +static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg; + drm_buf_free_t karg; + mm_segment_t old_fs; + int *ulist; + int ret; + u32 tmp; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->list)) + return -EFAULT; + + ulist = (int *) A(tmp); + + karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL); + if (!karg.list) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int)))) + goto out; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg); + set_fs(old_fs); + +out: + kfree(karg.list); + + return ret; +} + +typedef struct drm32_buf_pub { + int idx; /* Index into master buflist */ + int total; /* Buffer size */ + int used; /* Amount of buffer in use (for DMA) */ + u32 address; /* Address of buffer (void *) */ +} drm32_buf_pub_t; + +typedef struct drm32_buf_map { + int count; /* Length of buflist */ + u32 virtual; /* Mmaped area in user-virtual (void *) */ + u32 list; /* Buffer information (drm_buf_pub_t *) */ +} drm32_buf_map_t; +#define DRM32_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm32_buf_map_t) + +static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg; + drm32_buf_pub_t *ulist; + drm_buf_map_t karg; + mm_segment_t old_fs; + int orig_count, ret, i; + u32 tmp1, tmp2; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp1, &uarg->virtual) || + get_user(tmp2, &uarg->list)) + return -EFAULT; + + karg.virtual = (void *) A(tmp1); + ulist = (drm32_buf_pub_t *) A(tmp2); + + orig_count = karg.count; + + karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL); + if (!karg.list) + return -ENOMEM; + + ret = -EFAULT; + for (i = 0; i < karg.count; i++) { + if (get_user(karg.list[i].idx, &ulist[i].idx) || + get_user(karg.list[i].total, &ulist[i].total) || + get_user(karg.list[i].used, &ulist[i].used) || + get_user(tmp1, &ulist[i].address)) + goto out; + + karg.list[i].address = (void *) A(tmp1); + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + for (i = 0; i < orig_count; i++) { + tmp1 = (u32) (long) karg.list[i].address; + if (put_user(karg.list[i].idx, &ulist[i].idx) || + put_user(karg.list[i].total, &ulist[i].total) || + put_user(karg.list[i].used, &ulist[i].used) || + put_user(tmp1, &ulist[i].address)) { + ret = -EFAULT; + goto out; + } + } + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + +out: + kfree(karg.list); + return ret; +} + +typedef struct drm32_dma { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int context; /* Context handle */ + int send_count; /* Number of buffers to send */ + u32 send_indices; /* List of handles to buffers (int *) */ + u32 send_sizes; /* Lengths of data to send (int *) */ + drm_dma_flags_t flags; /* Flags */ + int request_count; /* Number of buffers requested */ + int request_size; /* Desired size for buffers */ + u32 request_indices; /* Buffer information (int *) */ + u32 request_sizes; /* (int *) */ + int granted_count; /* Number of buffers granted */ +} drm32_dma_t; +#define DRM32_IOCTL_DMA DRM_IOWR(0x29, drm32_dma_t) + +/* RED PEN The DRM layer blindly dereferences the send/request + * indice/size arrays even though they are userland + * pointers. -DaveM + */ +static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_dma_t *uarg = (drm32_dma_t *) arg; + int *u_si, *u_ss, *u_ri, *u_rs; + drm_dma_t karg; + mm_segment_t old_fs; + int ret; + u32 tmp1, tmp2, tmp3, tmp4; + + karg.send_indices = karg.send_sizes = NULL; + karg.request_indices = karg.request_sizes = NULL; + + if (get_user(karg.context, &uarg->context) || + get_user(karg.send_count, &uarg->send_count) || + get_user(tmp1, &uarg->send_indices) || + get_user(tmp2, &uarg->send_sizes) || + get_user(karg.flags, &uarg->flags) || + get_user(karg.request_count, &uarg->request_count) || + get_user(karg.request_size, &uarg->request_size) || + get_user(tmp3, &uarg->request_indices) || + get_user(tmp4, &uarg->request_sizes) || + get_user(karg.granted_count, &uarg->granted_count)) + return -EFAULT; + + u_si = (int *) A(tmp1); + u_ss = (int *) A(tmp2); + u_ri = (int *) A(tmp3); + u_rs = (int *) A(tmp4); + + if (karg.send_count) { + karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL); + karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL); + + ret = -ENOMEM; + if (!karg.send_indices || !karg.send_sizes) + goto out; + + ret = -EFAULT; + if (copy_from_user(karg.send_indices, u_si, + (karg.send_count * sizeof(int))) || + copy_from_user(karg.send_sizes, u_ss, + (karg.send_count * sizeof(int)))) + goto out; + } + + if (karg.request_count) { + karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL); + karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL); + + ret = -ENOMEM; + if (!karg.request_indices || !karg.request_sizes) + goto out; + + ret = -EFAULT; + if (copy_from_user(karg.request_indices, u_ri, + (karg.request_count * sizeof(int))) || + copy_from_user(karg.request_sizes, u_rs, + (karg.request_count * sizeof(int)))) + goto out; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (put_user(karg.context, &uarg->context) || + put_user(karg.send_count, &uarg->send_count) || + put_user(karg.flags, &uarg->flags) || + put_user(karg.request_count, &uarg->request_count) || + put_user(karg.request_size, &uarg->request_size) || + put_user(karg.granted_count, &uarg->granted_count)) + ret = -EFAULT; + + if (karg.send_count) { + if (copy_to_user(u_si, karg.send_indices, + (karg.send_count * sizeof(int))) || + copy_to_user(u_ss, karg.send_sizes, + (karg.send_count * sizeof(int)))) + ret = -EFAULT; + } + if (karg.request_count) { + if (copy_to_user(u_ri, karg.request_indices, + (karg.request_count * sizeof(int))) || + copy_to_user(u_rs, karg.request_sizes, + (karg.request_count * sizeof(int)))) + ret = -EFAULT; + } + } + +out: + if (karg.send_indices) + kfree(karg.send_indices); + if (karg.send_sizes) + kfree(karg.send_sizes); + if (karg.request_indices) + kfree(karg.request_indices); + if (karg.request_sizes) + kfree(karg.request_sizes); + + return ret; +} + +typedef struct drm32_ctx_res { + int count; + u32 contexts; /* (drm_ctx_t *) */ +} drm32_ctx_res_t; +#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm32_ctx_res_t) + +static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg; + drm_ctx_t *ulist; + drm_ctx_res_t karg; + mm_segment_t old_fs; + int orig_count, ret; + u32 tmp; + + karg.contexts = NULL; + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->contexts)) + return -EFAULT; + + ulist = (drm_ctx_t *) A(tmp); + + orig_count = karg.count; + if (karg.count && ulist) { + karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL); + if (!karg.contexts) + return -ENOMEM; + if (copy_from_user(karg.contexts, ulist, + (karg.count * sizeof(drm_ctx_t)))) { + kfree(karg.contexts); + return -EFAULT; + } + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (orig_count) { + if (copy_to_user(ulist, karg.contexts, + (orig_count * sizeof(drm_ctx_t)))) + ret = -EFAULT; + } + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + + if (karg.contexts) + kfree(karg.contexts); + + return ret; +} + +#endif /* defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) */ + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; @@ -1930,6 +2505,44 @@ error = do_smb_getmountuid(fd, cmd, arg); goto out; +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) + case DRM32_IOCTL_VERSION: + error = drm32_version(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_GET_UNIQUE: + error = drm32_getsetunique(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_SET_UNIQUE: + error = drm32_getsetunique(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_ADD_MAP: + error = drm32_addmap(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_INFO_BUFS: + error = drm32_info_bufs(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_FREE_BUFS: + error = drm32_free_bufs(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_MAP_BUFS: + error = drm32_map_bufs(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_DMA: + error = drm32_dma(fd, cmd, arg); + goto out; + + case DRM32_IOCTL_RES_CTX: + error = drm32_res_ctx(fd, cmd, arg); + goto out; +#endif /* DRM */ + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ @@ -2180,6 +2793,7 @@ case ENVCTRL_RD_ETHERNET_TEMPERATURE: case ENVCTRL_RD_MTHRBD_TEMPERATURE: case ENVCTRL_RD_CPU_VOLTAGE: + case ENVCTRL_RD_GLOBALADDRESS: case D7SIOCWR: /* case D7SIOCRD: Same value as ENVCTRL_RD_VOLTAGE_STATUS */ case D7SIOCTM: @@ -2486,6 +3100,30 @@ /* SMB ioctls which do not need any translations */ case SMB_IOC_NEWCONN: + +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) + /* DRM ioctls which do not need any translations */ + case DRM_IOCTL_GET_MAGIC: + case DRM_IOCTL_IRQ_BUSID: + case DRM_IOCTL_AUTH_MAGIC: + case DRM_IOCTL_BLOCK: + case DRM_IOCTL_UNBLOCK: + case DRM_IOCTL_CONTROL: + case DRM_IOCTL_ADD_BUFS: + case DRM_IOCTL_MARK_BUFS: + case DRM_IOCTL_ADD_CTX: + case DRM_IOCTL_RM_CTX: + case DRM_IOCTL_MOD_CTX: + case DRM_IOCTL_GET_CTX: + case DRM_IOCTL_SWITCH_CTX: + case DRM_IOCTL_NEW_CTX: + case DRM_IOCTL_ADD_DRAW: + case DRM_IOCTL_RM_DRAW: + case DRM_IOCTL_LOCK: + case DRM_IOCTL_UNLOCK: + case DRM_IOCTL_FINISH: +#endif /* DRM */ + error = sys_ioctl (fd, cmd, arg); goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c --- v2.2.17/arch/sparc64/kernel/psycho.c Sat Sep 9 18:42:34 2000 +++ linux/arch/sparc64/kernel/psycho.c Thu Nov 2 13:05:35 2000 @@ -1,4 +1,4 @@ -/* $Id: psycho.c,v 1.85.2.10 2000/06/14 07:41:19 davem Exp $ +/* $Id: psycho.c,v 1.85.2.11 2000/10/24 21:00:53 davem Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -30,13 +30,6 @@ #define dprintf printk #endif -unsigned long pci_dvma_offset = 0x00000000UL; -unsigned long pci_dvma_mask = 0xffffffffUL; - -#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL -unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; -unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; - /* If this is non-NULL it points to Sabre's DMA write-sync register * which is used by drivers of devices behind bridges other than APB * to synchronize DMA write streams with interrupt delivery. @@ -69,6 +62,13 @@ } #else + +unsigned long pci_dvma_offset = 0x00000000UL; +unsigned long pci_dvma_mask = 0xffffffffUL; + +#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL +unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; +unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.2.17/arch/sparc64/kernel/setup.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc64/kernel/setup.c Sat Oct 14 00:28:12 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.43.2.3 2000/03/03 23:50:37 davem Exp $ +/* $Id: setup.c,v 1.43.2.5 2000/10/02 02:05:37 anton Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -550,7 +550,7 @@ init_task.tss.kregs = &fake_swapper_regs; #ifdef CONFIG_IP_PNP - if (!ic_set_manually) { + if (ic_myaddr == INADDR_NONE) { int chosen = prom_finddevice ("/chosen"); u32 cl, sv, gw; @@ -642,7 +642,7 @@ prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff, linux_num_cpus, smp_num_cpus #ifndef __SMP__ - , loops_per_sec/500000, (loops_per_sec/5000) % 100 + , loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100 #endif ); #ifdef __SMP__ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.2.17/arch/sparc64/kernel/smp.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc64/kernel/smp.c Sat Oct 14 00:28:12 2000 @@ -78,8 +78,8 @@ if(cpu_present_map & (1UL << i)) len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", - i, cpu_data[i].udelay_val / 500000, - (cpu_data[i].udelay_val / 5000) % 100); + i, cpu_data[i].udelay_val / (500000/HZ), + (cpu_data[i].udelay_val / (5000/HZ)) % 100); return len; } @@ -91,7 +91,7 @@ cpu_data[id].bh_count = 0; /* multiplier and counter set by smp_setup_percpu_timer() */ - cpu_data[id].udelay_val = loops_per_sec; + cpu_data[id].udelay_val = loops_per_jiffy; cpu_data[id].pgcache_size = 0; cpu_data[id].pte_cache[0] = NULL; @@ -280,8 +280,8 @@ } printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, - (bogosum + 2500)/500000, - ((bogosum + 2500)/5000)%100); + (bogosum + 2500)/(500000/HZ), + ((bogosum + 2500)/(5000/HZ))%100); smp_activated = 1; smp_num_cpus = cpucount + 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.2.17/arch/sparc64/kernel/sparc64_ksyms.c Sat Sep 9 18:42:34 2000 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Thu Nov 2 13:05:35 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.58.2.8 2000/06/14 07:41:19 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.58.2.11 2000/10/25 21:17:44 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -47,6 +47,7 @@ #endif #include #include +#include struct poll { int fd; @@ -83,11 +84,13 @@ extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg); extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); extern void VISenter(void); +extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs); #ifdef __SMP__ extern spinlock_t kernel_flag; @@ -197,11 +200,15 @@ EXPORT_SYMBOL(pci_dma_wsync); #endif +/* I/O device mmaping on Sparc64. */ +EXPORT_SYMBOL(io_remap_page_range); + /* Solaris/SunOS binary compatibility */ EXPORT_SYMBOL(_sigpause_common); /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); /* math-emu wants this */ EXPORT_SYMBOL(die_if_kernel); @@ -240,6 +247,7 @@ #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91) EXPORT_SYMBOL(strlen); #endif +EXPORT_SYMBOL(__strlen_user); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.2.17/arch/sparc64/kernel/sys_sparc32.c Sat Sep 9 18:42:34 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Thu Oct 19 01:15:54 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.107.2.9 2000/06/20 17:12:25 davem Exp $ +/* $Id: sys_sparc32.c,v 1.107.2.14 2000/10/10 04:50:50 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -45,6 +45,9 @@ #include #include #include +#include +#include +#include #include #include @@ -1377,7 +1380,7 @@ static void *do_ncp_super_data_conv(void *raw_data) { - struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data; + struct ncp_mount_data news, *n = &news; struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data; n->dir_mode = n32->dir_mode; @@ -1387,6 +1390,7 @@ 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; + memcpy(raw_data, n, sizeof(struct ncp_mount_data)); return raw_data; } @@ -1401,7 +1405,7 @@ static void *do_smb_super_data_conv(void *raw_data) { - struct smb_mount_data *s = (struct smb_mount_data *)raw_data; + struct smb_mount_data news, *s = &news; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; s->version = s32->version; @@ -1410,6 +1414,7 @@ s->gid = s32->gid; s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; + memcpy(raw_data, s, sizeof(struct smb_mount_data)); return raw_data; } @@ -2665,42 +2670,86 @@ 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, +static int do_set_attach_filter(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; + 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); + 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 ret; + 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; +} + +static int do_set_icmpv6_filter(int fd, int level, int optname, + char *optval, int optlen) +{ + struct icmp6_filter kfilter; + mm_segment_t old_fs; + int ret, i; + + if (copy_from_user(&kfilter, optval, sizeof(kfilter))) + return -EFAULT; + + + for (i = 0; i < 8; i += 2) { + u32 tmp = kfilter.data[i]; + + kfilter.data[i] = kfilter.data[i + 1]; + kfilter.data[i + 1] = tmp; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_setsockopt(fd, level, optname, + (char *) &kfilter, sizeof(kfilter)); + set_fs(old_fs); + + return ret; +} + +asmlinkage int sys32_setsockopt(int fd, int level, int optname, + char *optval, int optlen) +{ + if (optname == SO_ATTACH_FILTER) + return do_set_attach_filter(fd, level, optname, + optval, optlen); + if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER) + return do_set_icmpv6_filter(fd, level, optname, + optval, optlen); + return sys_setsockopt(fd, level, optname, optval, optlen); } @@ -2875,7 +2924,7 @@ /* * count32() counts the number of arguments/envelopes */ -static int count32(u32 * argv) +static int count32(u32 * argv, int max) { int i = 0; @@ -2884,9 +2933,13 @@ u32 p; int error; error = get_user(p,argv); - if (error) return error; - if (!p) break; - argv++; i++; + if (error) + return error; + if (!p) + break; + argv++; + if (++i > max) + return -E2BIG; } } return i; @@ -2903,18 +2956,24 @@ { u32 str; - if (!p) return 0; /* bullet-proofing */ + if ((long)p <= 0) + return p; /* bullet-proofing */ while (argc-- > 0) { int len; unsigned long pos; get_user(str, argv+argc); - if (!str) panic("VFS: argc is wrong"); - len = strlen_user((char *)A(str)); /* includes the '\0' */ - if (p < len) /* this shouldn't happen - 128kB */ - return 0; - p -= len; pos = p; - while (len) { + if (!str) + return -EFAULT; + + len = strnlen_user((char *)A(str), p); /* includes the '\0' */ + if (!len) + return -EFAULT; + if (len > p) + return -E2BIG; + p -= len; + pos = p; + while (len > 0) { char *pag; int offset, bytes_to_copy; @@ -2961,11 +3020,11 @@ bprm.java = 0; bprm.loader = 0; bprm.exec = 0; - if ((bprm.argc = count32(argv)) < 0) { + if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) { dput(dentry); return bprm.argc; } - if ((bprm.envc = count32(envp)) < 0) { + if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) { dput(dentry); return bprm.envc; } @@ -2977,11 +3036,11 @@ bprm.exec = bprm.p; bprm.p = copy_strings32(bprm.envc,envp,bprm.page,bprm.p); bprm.p = copy_strings32(bprm.argc,argv,bprm.page,bprm.p); - if (!bprm.p) - retval = -E2BIG; + if ((long)bprm.p < 0) + retval = (int) bprm.p; } - if(retval>=0) + if (retval >= 0) retval = search_binary_handler(&bprm,regs); if(retval>=0) /* execve success */ @@ -4021,4 +4080,56 @@ ret = -EFAULT; return ret; +} + +struct __sysctl_args32 { + u32 name; + int nlen; + u32 oldval; + u32 oldlenp; + u32 newval; + u32 newlen; + u32 __unused[4]; +}; + +extern int do_sysctl(int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen); + +asmlinkage long sys32_sysctl(struct __sysctl_args32 *args) +{ + struct __sysctl_args32 tmp; + int error; + size_t oldlen, *oldlenp = NULL; + unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7; + + if (copy_from_user(&tmp, args, sizeof(tmp))) + return -EFAULT; + + if (tmp.oldval && tmp.oldlenp) { + /* Duh, this is ugly and might not work if sysctl_args + is in read-only memory, but do_sysctl does indirectly + a lot of uaccess in both directions and we'd have to + basically copy the whole sysctl.c here, and + glibc's __sysctl uses rw memory for the structure + anyway. */ + if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) || + put_user(oldlen, (size_t *)addr)) + return -EFAULT; + oldlenp = (size_t *)addr; + } + + lock_kernel(); + error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval), + oldlenp, (void *)A(tmp.newval), tmp.newlen); + unlock_kernel(); + if (oldlenp) { + if (!error) { + if (get_user(oldlen, (size_t *)addr) || + put_user(oldlen, (u32 *)A(tmp.oldlenp))) + error = -EFAULT; + } + copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); + } + return error; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.2.17/arch/sparc64/kernel/sys_sunos32.c Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc64/kernel/sys_sunos32.c Sun Sep 17 17:57:13 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.22.2.3 2000/01/17 21:28:31 davem Exp $ +/* $Id: sys_sunos32.c,v 1.22.2.4 2000/09/16 14:15:15 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -672,7 +672,7 @@ #define SMNT_SYS5 128 struct sunos_fh_t { - char fh_data [NFS_FHSIZE]; + char fh_data [NFS2_FHSIZE]; }; struct sunos_nfs_mount_args { @@ -746,7 +746,7 @@ server.sin_family = AF_INET; server.sin_addr = addr->sin_addr; - server.sin_port = NFS_PORT; + server.sin_port = NFS2_PORT; /* Call sys_connect */ ret = socket->ops->connect (socket, (struct sockaddr *) &server, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.2.17/arch/sparc64/kernel/systbls.S Fri Apr 21 12:45:48 2000 +++ linux/arch/sparc64/kernel/systbls.S Sun Sep 10 14:49:10 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.53.2.4 2000/03/24 00:03:28 davem Exp $ +/* $Id: systbls.S,v 1.53.2.5 2000/08/23 04:18:26 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -69,7 +69,7 @@ .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 .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep -/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl +/*250*/ .word sys_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl .word sys_aplib /* Now the 64-bit native Linux syscall table. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds --- v2.2.17/arch/sparc64/vmlinux.lds Fri Apr 21 12:45:49 2000 +++ linux/arch/sparc64/vmlinux.lds Sun Sep 10 14:47:06 2000 @@ -39,8 +39,17 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); /* __setup() commandline parameters */ + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; /* the init functions to be called */ + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(8192); __init_end = .; + + __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/Makefile linux/drivers/Makefile --- v2.2.17/drivers/Makefile Fri Apr 21 12:46:14 2000 +++ linux/drivers/Makefile Wed Nov 8 23:00:34 2000 @@ -10,7 +10,7 @@ SUB_DIRS := block char net misc sound MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp \ - macintosh video dio zorro fc4 usb telephony i2o + macintosh video dio zorro fc4 nubus usb telephony i2o ifdef CONFIG_DIO SUB_DIRS += dio @@ -43,7 +43,7 @@ MOD_SUB_DIRS += video endif -ifdef CONFIG_PPC +ifdef CONFIG_POWERMAC SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/Makefile linux/drivers/acorn/Makefile --- v2.2.17/drivers/acorn/Makefile Thu Jan 1 01:00:00 1970 +++ linux/drivers/acorn/Makefile Fri Sep 15 23:31:12 2000 @@ -0,0 +1,12 @@ +# +# Makefile for the Acorn-specific Linux kernel device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (not a .c file). + +SUB_DIRS := block char net scsi +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/Config.in linux/drivers/acorn/block/Config.in --- v2.2.17/drivers/acorn/block/Config.in Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/Config.in Fri Sep 15 23:31:12 2000 @@ -10,9 +10,12 @@ dep_tristate ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_BLK_DEV_IDE fi -tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM -if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then - bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT +if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then + tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772 + tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM + if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then + bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT + fi fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/Makefile linux/drivers/acorn/block/Makefile --- v2.2.17/drivers/acorn/block/Makefile Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/Makefile Fri Sep 15 23:31:12 2000 @@ -14,13 +14,11 @@ M_OBJS := MOD_LIST_NAME := ACORN_BLOCK_MODULES -ifeq ($(CONFIG_ARCH_ARC),y) - ifeq ($(CONFIG_BLK_DEV_FD),y) - L_OBJS += fd1772.o fd1772dma.o - else - ifeq ($(CONFIG_BLK_DEV_FD),m) - M_OBJS += fd1772_mod.o - endif +ifeq ($(CONFIG_BLK_DEV_FD1772),y) + L_OBJS += fd1772.o fd1772dma.o +else + ifeq ($(CONFIG_BLK_DEV_FD1772),m) + M_OBJS += fd1772_mod.o endif endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c --- v2.2.17/drivers/acorn/block/fd1772.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/fd1772.c Fri Sep 15 23:31:12 2000 @@ -114,6 +114,10 @@ * I wish I knew why that timer didn't work..... * * 16/11/96 - Fiddled and frigged for 2.0.18 + * + * DAG 30/01/99 - Started frobbing for 2.2.1 + * DAG 20/06/99 - A little more frobbing: + Included include/asm/uaccess.h for get_user/put_user */ #include @@ -136,14 +140,16 @@ #include #include #include +#include #include -#include #include #include +#include + #define MAJOR_NR FLOPPY_MAJOR #define FLOPPY_DMA 0 -#include "blk.h" +#include /* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with * little additional rework in this file). But I'm not yet sure if @@ -1598,7 +1604,7 @@ }; -int floppy_init(void) +int fd1772_init(void) { int i; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/fd1772dma.S linux/drivers/acorn/block/fd1772dma.S --- v2.2.17/drivers/acorn/block/fd1772dma.S Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/fd1772dma.S Fri Sep 15 23:31:12 2000 @@ -4,45 +4,45 @@ .text - .global _fdc1772_dataaddr -_fdc1772_fiqdata: + .global fdc1772_dataaddr +fdc1772_fiqdata: @ Number of bytes left to DMA - .global _fdc1772_bytestogo -_fdc1772_bytestogo: + .global fdc1772_bytestogo +fdc1772_bytestogo: .word 0 @ Place to put/get data from in DMA - .global _fdc1772_dataaddr -_fdc1772_dataaddr: + .global fdc1772_dataaddr +fdc1772_dataaddr: .word 0 - .global _fdc1772_fdc_int_done -_fdc1772_fdc_int_done: + .global fdc1772_fdc_int_done +fdc1772_fdc_int_done: .word 0 - .global _fdc1772_comendstatus -_fdc1772_comendstatus: + .global fdc1772_comendstatus +fdc1772_comendstatus: .word 0 @ We hang this off DMA channel 1 - .global _fdc1772_comendhandler -_fdc1772_comendhandler: + .global fdc1772_comendhandler +fdc1772_comendhandler: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#2 subeqs pc,r14,#4 @ should I leave a space here orr r9,r8,#0x10000 @ FDC base - adr r8,_fdc1772_fdc_int_done + adr r8,fdc1772_fdc_int_done ldrb r10,[r9,#0] @ FDC status mov r9,#1 @ Got a FIQ flag stmia r8,{r9,r10} subs pc,r14,#4 - .global _fdc1772_dma_read -_fdc1772_dma_read: + .global fdc1772_dma_read +fdc1772_dma_read: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#1 - beq _fdc1772_dma_read_notours + beq fdc1772_dma_read_notours orr r8,r8,#0x10000 @ FDC base ldrb r10,[r8,#0xc] @ Read from FDC data reg (also clears interrupt) ldmia r11,{r8,r9} @@ -51,19 +51,19 @@ strplb r10,[r9],#1 @ Store the data and increment the pointer stmplia r11,{r8,r9} @ Update count/pointers @ Handle any other interrupts if there are any -_fdc1772_dma_read_notours: +fdc1772_dma_read_notours: @ Cant branch because this code has been copied down to the FIQ vector ldr pc,[pc,#-4] - .word _fdc1772_comendhandler - .global _fdc1772_dma_read_end -_fdc1772_dma_read_end: + .word fdc1772_comendhandler + .global fdc1772_dma_read_end +fdc1772_dma_read_end: - .global _fdc1772_dma_write -_fdc1772_dma_write: + .global fdc1772_dma_write +fdc1772_dma_write: mov r8,#IOC_BASE ldrb r9,[r8,#0x34] @ IOC FIQ status tst r9,#1 - beq _fdc1772_dma_write_notours + beq fdc1772_dma_write_notours orr r8,r8,#0x10000 @ FDC base ldmia r11,{r9,r10} subs r9,r9,#1 @ One less byte to go @@ -72,23 +72,23 @@ strplb r12,[r8,#0xc] @ write it to FDC data reg stmplia r11,{r9,r10} @ Update count and pointer - should clear interrupt @ Handle any other interrupts -_fdc1772_dma_write_notours: +fdc1772_dma_write_notours: @ Cant branch because this code has been copied down to the FIQ vector ldr pc,[pc,#-4] - .word _fdc1772_comendhandler + .word fdc1772_comendhandler - .global _fdc1772_dma_write_end -_fdc1772_dma_write_end: + .global fdc1772_dma_write_end +fdc1772_dma_write_end: @ Setup the FIQ R11 to point to the data and store the count, address @ for this dma @ R0=count @ R1=address - .global _fdc1772_setupdma -_fdc1772_setupdma: + .global fdc1772_setupdma +fdc1772_setupdma: @ The big job is flipping in and out of FIQ mode - adr r2,_fdc1772_fiqdata @ This is what we really came here for + adr r2,fdc1772_fiqdata @ This is what we really came here for stmia r2,{r0,r1} mov r3, pc teqp pc,#0x0c000001 @ Disable FIQs, IRQs and switch to FIQ mode diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/ide-ics.c linux/drivers/acorn/block/ide-ics.c --- v2.2.17/drivers/acorn/block/ide-ics.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/ide-ics.c Fri Sep 15 23:31:12 2000 @@ -4,8 +4,9 @@ * Copyright (c) 1996,1997 Russell King. * * Changelog: - * 08-06-1996 RMK Created - * 12-09-1997 RMK Added interrupt enable/disable + * 08-Jun-1996 RMK Created + * 12-Sep-1997 RMK Added interrupt enable/disable + * 17-Apr-1999 RMK Support for V6 EASI */ #include @@ -44,7 +45,8 @@ #define ICS_ARCIN_V6_IDESTEPPING 4 static const card_ids icside_cids[] = { - { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS2, PROD_ICS2_IDE }, { 0xffff, 0xffff } }; @@ -81,6 +83,8 @@ icside_irqenable_arcin_v5, icside_irqdisable_arcin_v5, NULL, + NULL, + NULL, NULL }; @@ -106,9 +110,22 @@ inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); } +/* Prototype: icside_irqprobe(struct expansion_card *ec) + * Purpose : detect an active interrupt from card + */ +static int icside_irqpending_arcin_v6(struct expansion_card *ec) +{ + unsigned int ide_base_port = (unsigned int)ec->irq_data; + + return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || + inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; +} + static const expansioncard_ops_t icside_ops_arcin_v6 = { icside_irqenable_arcin_v6, icside_irqdisable_arcin_v6, + icside_irqpending_arcin_v6, + NULL, NULL, NULL }; @@ -157,7 +174,7 @@ printk ("icside: ***********************************\n"); printk ("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id); printk ("icside: ***********************************\n"); - printk ("icside: please report this to: linux@arm.uk.linux.org\n"); + printk ("icside: please report this to linux@arm.linux.org.uk\n"); printk ("icside: defaulting to ARCIN V5\n"); iftype = ics_if_arcin_v5; break; @@ -166,7 +183,9 @@ return iftype; } -static int icside_register_port(unsigned long dataport, unsigned long ctrlport, int stepping, int irq) +static int +icside_register_port(unsigned long dataport, unsigned long ctrlport, + int stepping, int irq, int dma) { hw_regs_t hw; int i; @@ -179,6 +198,7 @@ } hw.io_ports[IDE_CONTROL_OFFSET] = ctrlport; hw.irq = irq; + hw.dma = dma; return ide_register_hw(&hw, NULL); } @@ -189,7 +209,7 @@ */ static inline void icside_register (struct expansion_card *ec, int index) { - unsigned long port; + unsigned long port, slot_port; result[index][0] = -1; result[index][1] = -1; @@ -201,44 +221,48 @@ break; case ics_if_arcin_v5: - port = ecard_address (ec, ECARD_MEMC, 0); - ec->irqaddr = ioaddr(port + ICS_ARCIN_V5_INTRSTAT); + slot_port = ecard_address (ec, ECARD_MEMC, 0); + ec->irqaddr = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT); ec->irqmask = 1; - ec->irq_data = (void *)port; + ec->irq_data = (void *)slot_port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5; /* * Be on the safe side - disable interrupts */ - inb (port + ICS_ARCIN_V5_INTROFFSET); - result[index][0] = icside_register_port(port + ICS_ARCIN_V5_IDEOFFSET, - port + ICS_ARCIN_V5_IDEALTOFFSET, + inb (slot_port + ICS_ARCIN_V5_INTROFFSET); + result[index][0] = icside_register_port(slot_port + ICS_ARCIN_V5_IDEOFFSET, + slot_port + ICS_ARCIN_V5_IDEALTOFFSET, ICS_ARCIN_V5_IDESTEPPING, - ec->irq); + ec->irq, ec->dma); result[index][1] = -1; break; case ics_if_arcin_v6: - port = ecard_address (ec, ECARD_IOC, ECARD_FAST); - ec->irqaddr = ioaddr(port + ICS_ARCIN_V6_INTRSTAT_1); - ec->irqmask = 1; + slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST); + port = ecard_address(ec, ECARD_EASI, ECARD_FAST); + if (port == 0) + port = slot_port; + else + outb(1 << 5, slot_port); + ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; /* * Be on the safe side - disable interrupts */ - inb (port + ICS_ARCIN_V6_INTROFFSET_1); - inb (port + ICS_ARCIN_V6_INTROFFSET_2); + inb(port + ICS_ARCIN_V6_INTROFFSET_1); + inb(port + ICS_ARCIN_V6_INTROFFSET_2); result[index][0] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_1, port + ICS_ARCIN_V6_IDEALTOFFSET_1, ICS_ARCIN_V6_IDESTEPPING, - ec->irq); + ec->irq, ec->dma); result[index][1] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_2, port + ICS_ARCIN_V6_IDEALTOFFSET_2, ICS_ARCIN_V6_IDESTEPPING, - ec->irq); + ec->irq, ec->dma); break; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/ide-rapide.c linux/drivers/acorn/block/ide-rapide.c --- v2.2.17/drivers/acorn/block/ide-rapide.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/ide-rapide.c Fri Sep 15 23:31:12 2000 @@ -13,7 +13,6 @@ #include #include #include -#include #include "../../block/ide.h" @@ -28,14 +27,20 @@ static inline int rapide_register(struct expansion_card *ec) { unsigned long port = ecard_address (ec, ECARD_MEMC, 0); - ide_ioregspec_t spec; + hw_regs_t hw; - spec.base = port; - spec.ctrl = port + 0x206; - spec.offset = 1 << 4; - spec.irq = ec->irq; + int i; - return ide_register_port(&spec); + memset(&hw, 0, sizeof(hw)); + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw.io_ports[i] = (ide_ioreg_t)port; + port += 1 << 4; + } + hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206; + hw.irq = ec->irq; + + return ide_register_hw(&hw, NULL); } int rapide_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/mfm.S linux/drivers/acorn/block/mfm.S --- v2.2.17/drivers/acorn/block/mfm.S Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/mfm.S Fri Sep 15 23:31:12 2000 @@ -1,44 +1,43 @@ -@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 -@ motherboard on ST506 podules. -@ (c) David Alan Gilbert (gilbertd@cs.man.ac.uk) 1996 +@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes +@ motherboard and on ST506 expansion podules. +@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999 #include -_hdc63463_irqdata: +hdc63463_irqdata: @ Controller base address - .global _hdc63463_baseaddress -_hdc63463_baseaddress: + .global hdc63463_baseaddress +hdc63463_baseaddress: .word 0 - .global _hdc63463_irqpolladdress -_hdc63463_irqpolladdress: + .global hdc63463_irqpolladdress +hdc63463_irqpolladdress: .word 0 - .global _hdc63463_irqpollmask -_hdc63463_irqpollmask: + .global hdc63463_irqpollmask +hdc63463_irqpollmask: .word 0 @ where to read/write data from the kernel data space - .global _hdc63463_dataptr -_hdc63463_dataptr: + .global hdc63463_dataptr +hdc63463_dataptr: .word 0 @ Number of bytes left to transfer - .global _hdc63463_dataleft -_hdc63463_dataleft: + .global hdc63463_dataleft +hdc63463_dataleft: .word 0 @ ------------------------------------------------------------------------- @ hdc63463_writedma: DMA from host to controller @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask @ r3=data ptr, r4=data left, r5,r6=temporary - .global _hdc63463_writedma -_hdc63463_writedma: + .global hdc63463_writedma +hdc63463_writedma: stmfd sp!,{r4-r7} - adr r5,_hdc63463_irqdata + adr r5,hdc63463_irqdata ldmia r5,{r0,r1,r2,r3,r4} - writedma_again: @ test number of remaining bytes to transfer @@ -89,12 +88,12 @@ @ If we were too slow we had better go through again - DAG - took out with new interrupt routine @ sub r0,r0,#32+8 - @ adr r2,_hdc63463_irqdata + @ adr r2,hdc63463_irqdata @ ldr r2,[r2,#8] @ b writedma_again writedma_end: - adr r5,_hdc63463_irqdata+12 + adr r5,hdc63463_irqdata+12 stmia r5,{r3,r4} ldmfd sp!,{r4-r7} RETINSTR(mov,pc,lr) @@ -103,10 +102,10 @@ @ hdc63463_readdma: DMA from controller to host @ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask @ r3=data ptr, r4=data left, r5,r6=temporary - .global _hdc63463_readdma -_hdc63463_readdma: + .global hdc63463_readdma +hdc63463_readdma: stmfd sp!,{r4-r7} - adr r5,_hdc63463_irqdata + adr r5,hdc63463_irqdata ldmia r5,{r0,r1,r2,r3,r4} readdma_again: @@ -157,7 +156,7 @@ @ b readdma_again readdma_end: - adr r5,_hdc63463_irqdata+12 + adr r5,hdc63463_irqdata+12 stmia r5,{r3,r4} ldmfd sp!,{r4-r7} RETINSTR(mov,pc,lr) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c --- v2.2.17/drivers/acorn/block/mfmhd.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/block/mfmhd.c Fri Sep 15 23:31:12 2000 @@ -123,6 +123,7 @@ #include #include #include +#include /* * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc @@ -261,7 +262,9 @@ void (*done) (int st); /* done handler */ } *cont = NULL; +#if 0 static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0}; +#endif int number_mfm_drives = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/char/Config.in linux/drivers/acorn/char/Config.in --- v2.2.17/drivers/acorn/char/Config.in Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/char/Config.in Thu Jan 1 01:00:00 1970 @@ -1,15 +0,0 @@ -if [ "$CONFIG_SERIAL" != "n" ]; then - tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL - tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL -fi - -if [ "$CONFIG_MOUSE" = "y" ]; then - if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - if [ "$CONFIG_ARCH_RPC" != "y" ]; then - define_bool CONFIG_KBDMOUSE y - else - define_bool CONFIG_RPCMOUSE y - fi - fi -fi - diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/char/Makefile linux/drivers/acorn/char/Makefile --- v2.2.17/drivers/acorn/char/Makefile Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/char/Makefile Fri Sep 15 23:31:12 2000 @@ -9,20 +9,19 @@ # parent makes.. # -L_TARGET := acorn-char.a -M_OBJS := -L_OBJS := +L_TARGET := acorn-char.a +M_OBJS := +L_OBJS := -ifeq ($(MACHINE),rpc) - MOUSE_OBJS += mouse_rpc.o - L_OBJS += keyb_ps2.o -endif +L_OBJS_arc := keyb_arc.o +L_OBJS_a5k := keyb_arc.o +L_OBJS_rpc := keyb_ps2.o -ifeq ($(CONFIG_MOUSE),y) - LX_OBJS += $(MOUSE_OBJS) +ifeq ($(CONFIG_RPCMOUSE),y) + LX_OBJS += mouse_rpc.o else - ifeq ($(CONFIG_MOUSE),m) - MX_OBJS += $(MOUSE_OBJS) + ifeq ($(CONFIG_RPCMOUSE),m) + MX_OBJS += mouse_rpc.o endif endif @@ -41,5 +40,7 @@ M_OBJS += serial-dualsp.o endif endif + +L_OBJS += $(L_OBJS_$(MACHINE)) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c --- v2.2.17/drivers/acorn/char/keyb_arc.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/acorn/char/keyb_arc.c Fri Sep 15 23:31:12 2000 @@ -0,0 +1,451 @@ +/* + * linux/arch/arm/drivers/char1/keyb_arc.c + * + * Acorn keyboard driver for ARM Linux. + * + * The Acorn keyboard appears to have a ***very*** buggy reset protocol - + * every reset behaves differently. We try to get round this by attempting + * a few things... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../../char/mouse.h" + +extern void kbd_reset_kdown(void); + +#define VERSION 108 + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + +#include +#include + +static char kbd_txval[4]; +static unsigned char kbd_txhead, kbd_txtail; +#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3) +static int kbd_id = -1; +static struct wait_queue *kbd_waitq; +#ifdef CONFIG_KBDMOUSE +static int mousedev; +#endif + +/* + * Protocol codes to send the keyboard. + */ +#define HRST 0xff /* reset keyboard */ +#define RAK1 0xfe /* reset response */ +#define RAK2 0xfd /* reset response */ +#define BACK 0x3f /* Ack for first keyboard pair */ +#define SMAK 0x33 /* Last data byte ack (key scanning + mouse movement scanning) */ +#define MACK 0x32 /* Last data byte ack (mouse movement scanning) */ +#define SACK 0x31 /* Last data byte ack (key scanning) */ +#define NACK 0x30 /* Last data byte ack (no scanning, mouse data) */ +#define RQMP 0x22 /* Request mouse data */ +#define PRST 0x21 /* nothing */ +#define RQID 0x20 /* Request ID */ + +#define UP_FLAG 1 + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char a5kkbd_sysrq_xlate[] = +{ + 27, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + '`', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '-', '=', 'Ł', 127, 0, + 0, 0, 0, '/', '*', '#', 9, 'q', + 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', + 'p', '[', ']', '\\', 22, 23, 25, '7', + '8', '9', '-', 0, 'a', 's', 'd', 'f', + 'g', 'h', 'j', 'k', 'l', ';', '\'', 13, + '4', '5', '6', '+', 0, 0, 'z', 'x', + 'c', 'v', 'b', 'n', 'm', ',', '.', '/', + 0, 0, '1', '2', '3', 0, 0, ' ', + 0, 0, 0, 0, 0, '0', '.', 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; +#endif + +/* + * This array converts the scancode that we get from the keyboard to the + * real rows/columns on the A5000 keyboard. This might be keyboard specific... + * + * It is these values that we use to maintain the key down array. That way, we + * should pick up on the ghost key presses (which is what happens when you press + * three keys, and the keyboard thinks you have pressed four!) + * + * Row 8 (0x80+c) is actually a column with one key per row. It is isolated from + * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc). + * + * Illegal scancodes are denoted by an 0xff (in other words, we don't know about + * them, and can't process them for ghosts). This does however, cause problems with + * autorepeat processing... + */ +static unsigned char scancode_2_colrow[256] = { + 0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60, + 0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79, + 0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a, + 0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34, + 0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12, + 0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03, + 0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff, +}; + +#define BITS_PER_SHORT (8*sizeof(unsigned short)) +static unsigned short ghost_down[128/BITS_PER_SHORT]; + +static void a5kkbd_key(unsigned int keycode, unsigned int up_flag) +{ + unsigned int real_keycode; + + if (keycode > 0x72) { +#ifdef KBD_REPORT_UNKN + printk ("kbd: unknown scancode 0x%04x\n", keycode); +#endif + return; + } + if (keycode >= 0x70) { +#ifdef CONFIG_KBDMOUSE + if (mousedev >= 0) + switch (keycode) { + case 0x70: /* Left mouse button */ + busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0); + break; + + case 0x71: /* Middle mouse button */ + busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0); + break; + + case 0x72:/* Right mouse button */ + busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0); + break; + } +#endif + return; + } + + /* + * We have to work out if we accept this key press as a real key, or + * if it is a ghost. IE. If you press three keys, the keyboard will think + * that you've pressed a fourth: (@ = key down, # = ghost) + * + * 0 1 2 3 4 5 6 7 + * | | | | | | | | + * 0-+-+-+-+-+-+-+-+- + * | | | | | | | | + * 1-+-@-+-+-+-@-+-+- + * | | | | | | | | + * 2-+-+-+-+-+-+-+-+- + * | | | | | | | | + * 3-+-@-+-+-+-#-+-+- + * | | | | | | | | + * + * This is what happens when you have a matrix keyboard... + */ + + real_keycode = scancode_2_colrow[keycode]; + + if ((real_keycode & 0x80) == 0) { + int rr, kc = (real_keycode >> 4) & 7; + int cc; + unsigned short res, kdownkc; + + kdownkc = ghost_down[kc] | (1 << (real_keycode & 15)); + + for (rr = 0; rr < 128/BITS_PER_SHORT; rr++) + if (rr != kc && (res = ghost_down[rr] & kdownkc)) { + /* + * we have found a second row with at least one key pressed in the + * same column. + */ + for (cc = 0; res; res >>= 1) + cc += (res & 1); + if (cc > 1) + return; /* ignore it */ + } + if (up_flag) + clear_bit (real_keycode, ghost_down); + else + set_bit (real_keycode, ghost_down); + } + + handle_scancode(keycode, !up_flag); +} + +static inline void a5kkbd_sendbyte(unsigned char val) +{ + kbd_txval[kbd_txhead] = val; + KBD_INCTXPTR(kbd_txhead); + enable_irq(IRQ_KEYBOARDTX); +} + +static inline void a5kkbd_reset(void) +{ + int i; + + for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++) + ghost_down[i] = 0; + + kbd_reset_kdown(); +} + +void a5kkbd_leds(unsigned char leds) +{ + leds = ((leds & (1<= 0) + busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy); +#endif + } + } + return kbd_state == KBD_IDLE ? 1 : 0; + +kbd_wontreset: +#ifdef KBD_REPORT_ERR + printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n", + kbd_state, keyval); +#endif + mdelay(1); + inb(IOC_KARTRX); + a5kkbd_sendbyte (HRST); + kbd_state = KBD_INITRST; + return 0; + +kbd_error: +#ifdef KBD_REPORT_ERR + printk ("kbd: keyboard out of sync - resetting\n"); +#endif + a5kkbd_sendbyte (HRST); + kbd_state = KBD_INITRST; + return 0; +} + +static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs) +{ + kbd_pt_regs = regs; + if (handle_rawcode(inb(IOC_KARTRX))) + mark_bh (KEYBOARD_BH); +} + +static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs) +{ + outb (kbd_txval[kbd_txtail], IOC_KARTTX); + KBD_INCTXPTR(kbd_txtail); + if (kbd_txtail == kbd_txhead) + disable_irq(irq); +} + +#ifdef CONFIG_KBDMOUSE +static struct busmouse a5kkbd_mouse = { + 6, "kbdmouse", NULL, NULL, 7 +}; +#endif + +__initfunc(void a5kkbd_init_hw (void)) +{ + unsigned long flags; + + save_flags_cli (flags); + if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0) + panic("Could not allocate keyboard transmit IRQ!"); + disable_irq (IRQ_KEYBOARDTX); + if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0) + panic("Could not allocate keyboard receive IRQ!"); + (void)inb(IOC_KARTRX); + restore_flags (flags); + + a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */ + + /* wait 1s for keyboard to initialise */ + interruptible_sleep_on_timeout(&kbd_waitq, HZ); + +#ifdef CONFIG_KBDMOUSE + mousedev = register_busmouse(&a5kkbd_mouse); + if (mousedev < 0) + printk(KERN_ERR "Unable to register mouse driver\n"); +#endif + + printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100); + if (kbd_id != -1) + printk ("id=%d ", kbd_id); + printk ("English)\n"); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/char/keyb_ps2.c linux/drivers/acorn/char/keyb_ps2.c --- v2.2.17/drivers/acorn/char/keyb_ps2.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/char/keyb_ps2.c Fri Sep 15 23:31:12 2000 @@ -25,6 +25,7 @@ #include #include #include +#include #include extern void kbd_reset_kdown(void); @@ -221,14 +222,7 @@ }; #endif -int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p) -{ - *uf_p = scancode & 0200; - *keycode_p = scancode & 0x7f; - return 1; -} - -static void ps2kbd_key(unsigned int keycode, unsigned int up_flag) +static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag) { handle_scancode(keycode, !up_flag); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/char/mouse_rpc.c linux/drivers/acorn/char/mouse_rpc.c --- v2.2.17/drivers/acorn/char/mouse_rpc.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/char/mouse_rpc.c Fri Sep 15 23:31:12 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/char/rpcmouse.c + * linux/drivers/char/mouse_rpc.c * * Copyright (C) 1996-1998 Russell King * @@ -16,6 +16,7 @@ #include #include #include +#include #include "../../char/mouse.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/char/serial-card.c linux/drivers/acorn/char/serial-card.c --- v2.2.17/drivers/acorn/char/serial-card.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/char/serial-card.c Fri Sep 15 23:31:12 2000 @@ -33,14 +33,20 @@ #ifdef MODULE static int __serial_ports[NUM_SERIALS]; static int __serial_pcount; +static int __serial_addr[NUM_SERIALS]; static struct expansion_card *expcard[MAX_ECARDS]; #define ADD_ECARD(ec,card) expcard[(card)] = (ec) -#define ADD_PORT(port) __serial_ports[__serial_pcount++] = (port) +#define ADD_PORT(port,addr) \ + do { \ + __serial_ports[__serial_pcount] = (port); \ + __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) +#define ADD_PORT(port,addr) #endif static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } }; @@ -75,12 +81,15 @@ cardaddr = MY_BASE_ADDRESS(ec); for (port = 0; port < MY_NUMPORTS; port ++) { + unsigned long address; int line; - line = serial_register_onedev (MY_PORT_ADDRESS(port, cardaddr), ec->irq); + address = MY_PORT_ADDRESS(port, cardaddr); + + line = serial_register_onedev (address, ec->irq); if (line < 0) break; - ADD_PORT(line); + ADD_PORT(line, address); } if (port) { @@ -97,8 +106,10 @@ { int i; - for (i = 0; i < __serial_pcount; i++) - unregister_serial (__serial_ports[i]); + for (i = 0; i < __serial_pcount; i++) { + unregister_serial(__serial_ports[i]); + release_region(__serial_addr[i], 8); + } for (i = 0; i < MAX_ECARDS; i++) if (expcard[i]) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.2.17/drivers/acorn/net/ether1.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/net/ether1.c Fri Sep 15 23:31:12 2000 @@ -71,7 +71,7 @@ #define BUS_16 16 #define BUS_8 8 -static const card_ids ether1_cids[] = { +static const card_ids __init ether1_cids[] = { { MANU_ACORN, PROD_ACORN_ETHER1 }, { 0xffff, 0xffff } }; @@ -128,7 +128,7 @@ { int used; - addr = IO_BASE + (addr << 2); + addr = ioaddr(addr); __asm__ __volatile__( "subs %3, %3, #2 @@ -171,7 +171,7 @@ { int used; - addr = IO_BASE + (addr << 2); + addr = ioaddr(addr); __asm__ __volatile__( "subs %3, %3, #2 @@ -659,12 +659,6 @@ /* Fill in the fields of the device structure with ethernet values */ ether_setup (dev); -#ifndef CLAIM_IRQ_AT_OPEN - if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) { - kfree (dev->priv); - return -EAGAIN; - } -#endif return 0; } @@ -751,6 +745,8 @@ if (ether1_init_for_open (dev)) printk (KERN_ERR "%s: unable to restart interface\n", dev->name); + else + priv->restart = 0; dev->start = 1; } @@ -759,18 +755,16 @@ ether1_open (struct device *dev) { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; -#ifdef CLAIM_IRQ_AT_OPEN + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) return -EAGAIN; -#endif + MOD_INC_USE_COUNT; memset (&priv->stats, 0, sizeof (struct enet_statistics)); if (ether1_init_for_open (dev)) { -#ifdef CLAIM_IRQ_AT_OPEN free_irq (dev->irq, dev); -#endif MOD_DEC_USE_COUNT; return -EAGAIN; } @@ -1080,12 +1074,10 @@ static int ether1_close (struct device *dev) { -#ifdef CLAIM_IRQ_AT_OPEN - free_irq (dev->irq, dev); -#endif - ether1_reset (dev); + free_irq(dev->irq, dev); + dev->start = 0; dev->tbusy = 0; @@ -1117,56 +1109,46 @@ #ifdef MODULE -static char ethernames[MAX_ECARDS][9]; -static struct device *my_ethers[MAX_ECARDS]; -static struct expansion_card *ec[MAX_ECARDS]; +static struct ether_dev { + struct expansion_card *ec; + char name[9]; + struct device dev; +} ether_devs[MAX_ECARDS]; int init_module (void) { - int i; + struct expansion_card *ec; + int i, ret = -ENODEV; - for (i = 0; i < MAX_ECARDS; i++) { - my_ethers[i] = NULL; - ec[i] = NULL; - strcpy (ethernames[i], " "); - } + memset(ether_devs, 0, sizeof(ether_devs)); + ecard_startfind (); + ec = ecard_find(0, ether1_cids); i = 0; - ecard_startfind (); + while (ec && i < MAX_ECARDS) { + ecard_claim(ec); - do { - if ((ec[i] = ecard_find(0, ether1_cids)) == NULL) + ether_devs[i].ec = ec; + ether_devs[i].dev.irq = ec->irq; + ether_devs[i].dev.base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST); + ether_devs[i].dev.init = ether1_probe; + ether_devs[i].dev.name = ether_devs[i].name; + + ret = register_netdev(ðer_devs[i].dev); + + if (ret) { + ecard_release(ec); + ether_devs[i].ec = NULL; break; - - my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL); - memset (my_ethers[i], 0, sizeof (struct device)); - - my_ethers[i]->irq = ec[i]->irq; - my_ethers[i]->base_addr = ecard_address (ec[i], ECARD_IOC, ECARD_FAST); - my_ethers[i]->init = ether1_probe; - my_ethers[i]->name = ethernames[i]; - - ecard_claim (ec[i]); - - if (register_netdev (my_ethers[i]) != 0) { - for (i = 0; i < 4; i++) { - if (my_ethers[i]) { - kfree (my_ethers[i]); - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release (ec[i]); - ec[i] = NULL; - } - } - return -EIO; } - i++; - } while (i < MAX_ECARDS); - return i != 0 ? 0 : -ENODEV; + i += 1; + ec = ecard_find(0, ether1_cids); + } + + return i != 0 ? 0 : ret; } void @@ -1175,18 +1157,15 @@ int i; for (i = 0; i < MAX_ECARDS; i++) { - if (my_ethers[i]) { - unregister_netdev (my_ethers[i]); - release_region (my_ethers[i]->base_addr, 16); - release_region (my_ethers[i]->base_addr + 0x800, 4096); -#ifndef CLAIM_IRQ_AT_OPEN - free_irq (my_ethers[i]->irq, my_ethers[i]); -#endif - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release (ec[i]); - ec[i] = NULL; + if (ether_devs[i].ec) { + unregister_netdev(ðer_devs[i].dev); + + release_region(ether_devs[i].dev.base_addr, 16); + release_region(ether_devs[i].dev.base_addr + 0x800, 4096); + + ecard_release(ether_devs[i].ec); + + ether_devs[i].ec = NULL; } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c --- v2.2.17/drivers/acorn/net/ether3.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/net/ether3.c Fri Sep 15 23:31:12 2000 @@ -33,11 +33,12 @@ * packet starts two bytes from the end of the * buffer, it corrupts the receiver chain, and * never updates the transmit status correctly. - * TODO: - * When we detect a fatal error on the interface, we should restart it. + * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing. + * 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy + * hardware. */ -static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n"; +static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.15\n"; #include #include @@ -66,7 +67,7 @@ #include "ether3.h" static unsigned int net_debug = NET_DEBUG; -static const card_ids ether3_cids[] = { +static const card_ids __init ether3_cids[] = { { MANU_ANT2, PROD_ANT_ETHER3 }, { MANU_ANT, PROD_ANT_ETHER3 }, { MANU_ANT, PROD_ANT_ETHERB }, /* trial - will etherb work? */ @@ -77,9 +78,6 @@ static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt); static void ether3_tx(struct device *dev, struct dev_priv *priv); -extern int inswb(int reg, void *buffer, int len); -extern int outswb(int reg, void *buffer, int len); - #define BUS_16 2 #define BUS_8 1 #define BUS_UNKNOWN 0 @@ -88,7 +86,7 @@ * I'm not sure what address we should default to if the internal one * is corrupted... */ -unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; +unsigned char def_eth_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; /* --------------------------------------------------------------------------- */ @@ -99,10 +97,20 @@ /* * ether3 read/write. Slow things down a bit... + * The SEEQ8005 doesn't like us writing to it's registers + * too quickly. */ -#define ether3_outb(v,r) { outb((v),(r)); udelay(1); } -#define ether3_outw(v,r) { outw((v),(r)); udelay(1); } +static inline void ether3_outb(int v, const int r) +{ + outb(v, r); + udelay(1); +} +static inline void ether3_outw(int v, const int r) +{ + outw(v, r); + udelay(1); +} #define ether3_inb(r) ({ unsigned int __v = inb((r)); udelay(1); __v; }) #define ether3_inw(r) ({ unsigned int __v = inw((r)); udelay(1); __v; }) @@ -138,7 +146,7 @@ * write data to the buffer memory */ #define ether3_writebuffer(dev,data,length) \ - outswb(REG_BUFWIN, (data), (length)) + outsw(REG_BUFWIN, (data), (length) >> 1) #define ether3_writeword(dev,data) \ outw((data), REG_BUFWIN) @@ -153,7 +161,7 @@ * read data from the buffer memory */ #define ether3_readbuffer(dev,data,length) \ - inswb(REG_BUFWIN, (data), (length)) + insw(REG_BUFWIN, (data), (length) >> 1) #define ether3_readword(dev) \ inw(REG_BUFWIN) @@ -249,7 +257,7 @@ } } else { if (bad != -1) { - if (bad != i - 1) + if (bad != i - 1) printk(" - 0x%04X\n", i - 1); printk("\n"); bad = -1; @@ -335,7 +343,6 @@ for (i = 0; i < 6; i++) ether3_outb(dev->dev_addr[i], REG_BUFWIN); - priv->tx_used = 0; priv->tx_head = 0; priv->tx_tail = 0; priv->regs.config2 |= CFG2_CTRLO; @@ -471,6 +478,25 @@ return error; } +__initfunc(static void +ether3_get_dev(struct device *dev, struct expansion_card *ec)) +{ + ecard_claim(ec); + + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); + dev->irq = ec->irq; + + if (ec->cid.manufacturer == MANU_ANT && + ec->cid.product == PROD_ANT_ETHERB) { + dev->base_addr += 0x200; + } + + ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr); + ec->irqmask = 0xf0; + + ether3_addr(dev->dev_addr, ec); +} + #ifndef MODULE __initfunc(int ether3_probe(struct device *dev)) @@ -485,12 +511,8 @@ if ((ec = ecard_find(0, ether3_cids)) == NULL) return ENODEV; - dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); - dev->irq = ec->irq; - - ecard_claim(ec); + ether3_get_dev(dev, ec); - ether3_addr(dev->dev_addr, ec); return ether3_probe1(dev); } #endif @@ -581,33 +603,6 @@ } /* - * Allocate memory in transmitter ring buffer. - */ -static int -ether3_alloc_tx(struct dev_priv *priv, int length, int alloc) -{ - int start, head, tail; - - tail = priv->tx_tail; - start = priv->tx_head; - head = start + length + 4; - - if (head >= TX_END) { - if (tail > priv->tx_head) - return -1; - head -= TX_END - TX_START; - if (tail < head) - return -1; - } else if (start < tail && tail < head) - return -1; - - if (alloc) - priv->tx_head = head; - - return start; -} - -/* * Transmit a packet */ static int @@ -622,7 +617,7 @@ if (!test_and_set_bit(0, (void *)&dev->tbusy)) { unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - int ptr; + unsigned int ptr, next_ptr; length = (length + 1) & ~1; @@ -633,23 +628,31 @@ return 0; } + next_ptr = (priv->tx_head + 1) & 15; + save_flags_cli(flags); - ptr = ether3_alloc_tx(priv, length, 1); - if (ptr == -1) + if (priv->tx_tail == next_ptr) { + restore_flags(flags); return 1; /* unable to queue */ + } + + dev->trans_start = jiffies; + ptr = 0x600 * priv->tx_head; + priv->tx_head = next_ptr; + next_ptr *= 0x600; #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) - ether3_setbuffer(dev, buffer_write, priv->tx_head); + ether3_setbuffer(dev, buffer_write, next_ptr); ether3_writelong(dev, 0); - ether3_setbuffer(dev, buffer_write, ptr); ether3_writelong(dev, 0); ether3_writebuffer(dev, skb->data, length); - + ether3_writeword(dev, htons(next_ptr)); + ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); ether3_setbuffer(dev, buffer_write, ptr); - ether3_writeword(dev, htons(priv->tx_head)); + ether3_writeword(dev, htons((ptr + length + 4))); ether3_writeword(dev, TXHDR_FLAGS >> 16); ether3_ledon(dev, priv); @@ -658,11 +661,10 @@ ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND); } - if (ether3_alloc_tx(priv, 2044, 0) != -1) + next_ptr = (priv->tx_head + 1) & 15; + if (priv->tx_tail != next_ptr) dev->tbusy = 0; - dev->trans_start = jiffies; - restore_flags(flags); dev_kfree_skb(skb); @@ -689,7 +691,7 @@ ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name, ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR)); - printk(KERN_ERR "%s: tx head=%04X tx tail=%04X\n", dev->name, + printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name, priv->tx_head, priv->tx_tail); ether3_setbuffer(dev, buffer_read, priv->tx_tail); printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); @@ -698,8 +700,9 @@ dev->tbusy = 0; priv->regs.config2 |= CFG2_CTRLO; priv->stats.tx_errors += 1; - ether3_outw(priv->regs.config2 , REG_CONFIG2); + ether3_outw(priv->regs.config2, REG_CONFIG2); dev->trans_start = jiffies; + priv->tx_head = priv->tx_tail = 0; goto retry; } } @@ -867,6 +870,7 @@ ether3_tx(struct device *dev, struct dev_priv *priv) { unsigned int tx_tail = priv->tx_tail; + int max_work = 14; do { unsigned long status; @@ -874,7 +878,7 @@ /* * Read the packet header */ - ether3_setbuffer(dev, buffer_read, tx_tail); + ether3_setbuffer(dev, buffer_read, tx_tail * 0x600); status = ether3_readlong(dev); /* @@ -895,95 +899,72 @@ if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++; } - tx_tail = htons(status & TX_NEXT); - if (tx_tail < TX_START || tx_tail >= TX_END) { - printk("%s: transmit error: next pointer = %04X\n", dev->name, tx_tail); - tx_tail = TX_START; - priv->tx_head = TX_START; - priv->tx_tail = TX_END; - } - } while (1); + tx_tail = (tx_tail + 1) & 15; + } while (--max_work); if (priv->tx_tail != tx_tail) { priv->tx_tail = tx_tail; - if (priv->tx_used <= MAX_TX_BUFFERED) { - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ - } + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ } } #ifdef MODULE -char ethernames[MAX_ECARDS][9]; - -static struct device *my_ethers[MAX_ECARDS]; -static struct expansion_card *ec[MAX_ECARDS]; +static struct ether_dev { + struct expansion_card *ec; + char name[9]; + struct device dev; +} ether_devs[MAX_ECARDS]; int init_module(void) { - int i; + struct expansion_card *ec; + int i, ret = -ENODEV; - for(i = 0; i < MAX_ECARDS; i++) { - my_ethers[i] = NULL; - ec[i] = NULL; - strcpy(ethernames[i], " "); - } + memset(ether_devs, 0, sizeof(ether_devs)); + ecard_startfind (); + ec = ecard_find(0, ether3_cids); i = 0; - ecard_startfind(); + while (ec && i < MAX_ECARDS) { + ecard_claim(ec); - do { - if ((ec[i] = ecard_find(0, ether3_cids)) == NULL) - break; - - my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL); - memset(my_ethers[i], 0, sizeof(struct device)); + ether_devs[i].ec = ec; + ether_devs[i].dev.init = ether3_probe1; + ether_devs[i].dev.name = ether_devs[i].name; + ether3_get_dev(ðer_devs[i].dev, ec); + + ret = register_netdev(ðer_devs[i].dev); + + if (ret) { + ecard_release(ec); + ether_devs[i].ec = NULL; + } else + i += 1; - my_ethers[i]->irq = ec[i]->irq; - my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0); - my_ethers[i]->init = ether3_probe1; - my_ethers[i]->name = ethernames[i]; - - ether3_addr(my_ethers[i]->dev_addr, ec[i]); - - ecard_claim(ec[i]); - - if(register_netdev(my_ethers[i]) != 0) { - for (i = 0; i < 4; i++) { - if(my_ethers[i]) { - kfree(my_ethers[i]); - my_ethers[i] = NULL; - } - if(ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; - } - } - return -EIO; - } - i++; + ec = ecard_find(0, ether3_cids); } - while(i < MAX_ECARDS); - return i != 0 ? 0 : -ENODEV; + return i != 0 ? 0 : ret; } void cleanup_module(void) { int i; + for (i = 0; i < MAX_ECARDS; i++) { - if (my_ethers[i]) { - release_region(my_ethers[i]->base_addr, 128); - unregister_netdev(my_ethers[i]); - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; + if (ether_devs[i].ec) { + unregister_netdev(ðer_devs[i].dev); + + release_region(ether_devs[i].dev.base_addr, 128); + + ecard_release(ether_devs[i].ec); + + ether_devs[i].ec = NULL; } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/net/ether3.h linux/drivers/acorn/net/ether3.h --- v2.2.17/drivers/acorn/net/ether3.h Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/net/ether3.h Fri Sep 15 23:31:12 2000 @@ -151,9 +151,8 @@ unsigned int config1; unsigned int config2; } regs; - unsigned int tx_head; /* address to insert next packet */ - unsigned int tx_tail; /* address of transmitting packet */ - unsigned int tx_used; /* number of 'slots' used */ + unsigned char tx_head; /* buffer nr to insert next packet */ + unsigned char tx_tail; /* buffer nr of transmitting packet */ unsigned int rx_head; /* address to fetch next packet from */ struct enet_statistics stats; struct timer_list timer; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c --- v2.2.17/drivers/acorn/net/etherh.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/net/etherh.c Fri Sep 15 23:31:12 2000 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -50,13 +51,16 @@ #define DEBUG_INIT 2 static unsigned int net_debug = NET_DEBUG; -static const card_ids etherh_cids[] = { +static const card_ids __init etherh_cids[] = { { MANU_I3, PROD_I3_ETHERLAN500 }, { MANU_I3, PROD_I3_ETHERLAN600 }, { MANU_I3, PROD_I3_ETHERLAN600A }, { 0xffff, 0xffff } }; +MODULE_AUTHOR("Russell King"); +MODULE_DESCRIPTION("i3 EtherH driver"); + static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ @@ -80,8 +84,8 @@ * Read the ethernet address string from the on board rom. * This is an ascii string... */ -static int -etherh_addr(char *addr, struct expansion_card *ec) +__initfunc(static int +etherh_addr(char *addr, struct expansion_card *ec)) { struct in_chunk_dir cd; char *s; @@ -216,10 +220,8 @@ if (ei_status.word16) outsw (dma_addr, buf, count >> 1); -#ifdef BIT8 else outsb (dma_addr, buf, count); -#endif dma_start = jiffies; @@ -268,11 +270,8 @@ insw (dma_addr, buf, count >> 1); if (count & 1) buf[count - 1] = inb (dma_addr); - } -#ifdef BIT8 - else + } else insb (dma_addr, buf, count); -#endif outb (ENISR_RDC, addr + EN0_ISR); ei_status.dmaing &= ~1; @@ -307,10 +306,8 @@ if (ei_status.word16) insw (dma_addr, hdr, sizeof (*hdr) >> 1); -#ifdef BIT8 else insb (dma_addr, hdr, sizeof (*hdr)); -#endif outb (ENISR_RDC, addr + EN0_ISR); ei_status.dmaing &= ~1; @@ -355,8 +352,8 @@ /* * This is the real probe routine. */ -static int -etherh_probe1(struct device *dev) +__initfunc(static int +etherh_probe1(struct device *dev)) { static int version_printed; unsigned int addr, i, reg0, tmp; @@ -461,10 +458,13 @@ etherh_irq_enable, etherh_irq_disable, NULL, + NULL, + NULL, NULL }; -static void etherh_initdev (ecard_t *ec, struct device *dev) +__initfunc(static void +etherh_initdev(ecard_t *ec, struct device *dev)) { ecard_claim (ec); @@ -492,27 +492,27 @@ } ec->ops = ðerh_ops; - etherh_addr (dev->dev_addr, ec); + etherh_addr(dev->dev_addr, ec); } #ifndef MODULE -int -etherh_probe(struct device *dev) +__initfunc(int +etherh_probe(struct device *dev)) { if (!dev) return ENODEV; - ecard_startfind (); - - if (!dev->base_addr) { + if (!dev->base_addr || dev->base_addr == 0xffe0) { struct expansion_card *ec; + ecard_startfind(); + if ((ec = ecard_find (0, etherh_cids)) == NULL) return ENODEV; - etherh_initdev (ec, dev); + etherh_initdev(ec, dev); } - return etherh_probe1 (dev); + return etherh_probe1(dev); } #endif @@ -529,12 +529,10 @@ init_all_cards(void) { struct device *dev = NULL; - struct expansion_card *boguscards[MAX_ETHERH_CARDS]; int i, found = 0; for (i = 0; i < MAX_ETHERH_CARDS; i++) { my_ethers[i] = NULL; - boguscards[i] = NULL; ec[i] = NULL; strcpy (ethernames[i], " "); } @@ -571,7 +569,7 @@ if (register_netdev(dev) != 0) { printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr); if (ec[i]) { - boguscards[i] = ec[i]; + ecard_release(ec[i]); ec[i] = NULL; } continue; @@ -582,12 +580,6 @@ if (dev) kfree (dev); - - for (i = 0; i < MAX_ETHERH_CARDS; i++) - if (boguscards[i]) { - boguscards[i]->ops = NULL; - ecard_release (boguscards[i]); - } return found ? 0 : -ENODEV; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/Config.in linux/drivers/acorn/scsi/Config.in --- v2.2.17/drivers/acorn/scsi/Config.in Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/Config.in Fri Sep 15 23:31:12 2000 @@ -7,11 +7,12 @@ 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 - comment 'The following drives are not fully supported' + comment 'The following drivers are not fully supported' dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/Makefile linux/drivers/acorn/scsi/Makefile --- v2.2.17/drivers/acorn/scsi/Makefile Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/Makefile Fri Sep 15 23:31:12 2000 @@ -24,6 +24,16 @@ endif endif +ifeq ($(CONFIG_SCSI_ARXESCSI),y) + L_OBJS += arxescsi.o + CONFIG_FAS216_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_ARXESCSI),m) + M_OBJS += arxescsi.o + CONFIG_FAS216_MODULE=y + endif +endif + ifeq ($(CONFIG_SCSI_CUMANA_1),y) L_OBJS += cumana_1.o else @@ -34,12 +44,10 @@ ifeq ($(CONFIG_SCSI_CUMANA_2),y) L_OBJS += cumana_2.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_CUMANA_2),m) M_OBJS += cumana_2.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif @@ -62,41 +70,39 @@ ifeq ($(CONFIG_SCSI_POWERTECSCSI),y) L_OBJS += powertec.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_POWERTECSCSI),m) M_OBJS += powertec.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif ifeq ($(CONFIG_SCSI_EESOXSCSI),y) L_OBJS += eesox.o - CONFIG_QUEUE_BUILTIN=y CONFIG_FAS216_BUILTIN=y else ifeq ($(CONFIG_SCSI_EESOXSCSI),m) M_OBJS += eesox.o - CONFIG_QUEUE_MODULE=y CONFIG_FAS216_MODULE=y endif endif -ifeq ($(CONFIG_QUEUE_BUILTIN),y) - LX_OBJS += queue.o msgqueue.o -else - ifeq ($(CONFIG_QUEUE_MODULE),y) - MX_OBJS += queue.o msgqueue.o - endif -endif - ifeq ($(CONFIG_FAS216_BUILTIN),y) LX_OBJS += fas216.o + CONFIG_QUEUE_BUILTIN=y else ifeq ($(CONFIG_FAS216_MODULE),y) MX_OBJS += fas216.o + CONFIG_QUEUE_MODULE=y + endif +endif + +ifeq ($(CONFIG_QUEUE_BUILTIN),y) + LX_OBJS += queue.o msgqueue.o +else + ifeq ($(CONFIG_QUEUE_MODULE),y) + MX_OBJS += queue.o msgqueue.o endif endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c --- v2.2.17/drivers/acorn/scsi/acornscsi.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/acornscsi.c Fri Sep 15 23:31:12 2000 @@ -21,6 +21,8 @@ * 12-Oct-1997 RMK Added catch for re-entering interrupt routine. * 15-Oct-1997 RMK Improved handling of commands. * 27-Jun-1998 RMK Changed asm/delay.h to linux/delay.h. + * 13-Dec-1998 RMK Better abort code and command handling. Extra state + * transitions added to allow dodgy devices to work. */ #define DEBUG_NO_WRITE 1 #define DEBUG_QUEUES 2 @@ -35,7 +37,7 @@ #define DEBUG_RESET 1024 #define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\ DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\ - DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE) + DEBUG_DMA|DEBUG_QUEUES) /* DRIVER CONFIGURATION * @@ -123,8 +125,8 @@ #ifndef STRINGIFY #define STRINGIFY(x) #x #endif -#define STR(x) STRINGIFY(x) -#define NO_WRITE_STR STR(NO_WRITE) +#define STRx(x) STRINGIFY(x) +#define NO_WRITE_STR STRx(NO_WRITE) #include #include @@ -142,6 +144,7 @@ #include #include #include +#include #include #include "../../scsi/scsi.h" @@ -160,10 +163,6 @@ #error "Yippee! ABORT TAG is now defined! Remove this error!" #endif -#ifndef NO_IRQ -#define NO_IRQ 255 -#endif - #ifdef CONFIG_SCSI_ACORNSCSI_LINK #error SCSI2 LINKed commands not supported (yet)! #endif @@ -186,26 +185,7 @@ #define DMAC_BUFFER_SIZE 65536 #endif -/* - * This is used to dump the previous states of the SBIC - */ -static struct status_entry { - unsigned long when; - unsigned char ssr; - unsigned char ph; - unsigned char irq; - unsigned char unused; -} status[9][16]; -static unsigned char status_ptr[9]; - -#define ADD_STATUS(_q,_ssr,_ph,_irq) \ -({ \ - status[(_q)][status_ptr[(_q)]].when = jiffies; \ - status[(_q)][status_ptr[(_q)]].ssr = (_ssr); \ - status[(_q)][status_ptr[(_q)]].ph = (_ph); \ - status[(_q)][status_ptr[(_q)]].irq = (_irq); \ - status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \ -}) +#define STATUS_BUFFER_TO_PRINT 24 unsigned int sdtr_period = SDTR_PERIOD; unsigned int sdtr_size = SDTR_SIZE; @@ -214,31 +194,31 @@ PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); -static int acornscsi_reconnect_finish (AS_Host *host); -static void acornscsi_dma_cleanup (AS_Host *host); -static void acornscsi_abortcmd (AS_Host *host, unsigned char tag); +static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); +static int acornscsi_reconnect_finish(AS_Host *host); +static void acornscsi_dma_cleanup(AS_Host *host); +static void acornscsi_abortcmd(AS_Host *host, unsigned char tag); /* ==================================================================================== * Miscellaneous */ static inline void -sbic_arm_write (unsigned int io_port, int reg, int value) +sbic_arm_write(unsigned int io_port, int reg, int value) { - outb_t (reg, io_port); - outb_t (value, io_port + 4); + outb_t(reg, io_port); + outb_t(value, io_port + 4); } #define sbic_arm_writenext(io,val) \ - outb_t ((val), (io) + 4) + outb_t((val), (io) + 4) static inline -int sbic_arm_read (unsigned int io_port, int reg) +int sbic_arm_read(unsigned int io_port, int reg) { if(reg == ASR) return inl_t(io_port) & 255; - outb_t (reg, io_port); + outb_t(reg, io_port); return inl_t(io_port + 4) & 255; } @@ -247,129 +227,165 @@ #ifdef USE_DMAC #define dmac_read(io_port,reg) \ - inb ((io_port) + (reg)) + inb((io_port) + (reg)) #define dmac_write(io_port,reg,value) \ - ({ outb ((value), (io_port) + (reg)); }) + ({ outb((value), (io_port) + (reg)); }) #define dmac_clearintr(io_port) \ - ({ outb (0, (io_port)); }) + ({ outb(0, (io_port)); }) static inline -unsigned int dmac_address (unsigned int io_port) +unsigned int dmac_address(unsigned int io_port) { - return dmac_read (io_port, TXADRHI) << 16 | - dmac_read (io_port, TXADRMD) << 8 | - dmac_read (io_port, TXADRLO); + return dmac_read(io_port, TXADRHI) << 16 | + dmac_read(io_port, TXADRMD) << 8 | + dmac_read(io_port, TXADRLO); } static -void acornscsi_dumpdma (AS_Host *host, char *where) +void acornscsi_dumpdma(AS_Host *host, char *where) { unsigned int mode, addr, len; - mode = dmac_read (host->dma.io_port, MODECON); - addr = dmac_address (host->dma.io_port); - len = dmac_read (host->dma.io_port, TXCNTHI) << 8 | - dmac_read (host->dma.io_port, TXCNTLO); + mode = dmac_read(host->dma.io_port, MODECON); + addr = dmac_address(host->dma.io_port); + len = dmac_read(host->dma.io_port, TXCNTHI) << 8 | + dmac_read(host->dma.io_port, TXCNTLO); - printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", + printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", host->host->host_no, where, mode, addr, (len + 1) & 0xffff, - dmac_read (host->dma.io_port, MASKREG)); + dmac_read(host->dma.io_port, MASKREG)); - printk ("DMA @%06x, ", host->dma.start_addr); - printk ("BH @%p +%04x, ", host->scsi.SCp.ptr, + printk("DMA @%06x, ", host->dma.start_addr); + printk("BH @%p +%04x, ", host->scsi.SCp.ptr, host->scsi.SCp.this_residual); - printk ("DT @+%04x ST @+%04x", host->dma.transferred, + printk("DT @+%04x ST @+%04x", host->dma.transferred, host->scsi.SCp.scsi_xferred); - printk ("\n"); + printk("\n"); } #endif static -unsigned long acornscsi_sbic_xfcount (AS_Host *host) +unsigned long acornscsi_sbic_xfcount(AS_Host *host) { unsigned long length; - length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16; - length |= sbic_arm_readnext (host->scsi.io_port) << 8; - length |= sbic_arm_readnext (host->scsi.io_port); + length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16; + length |= sbic_arm_readnext(host->scsi.io_port) << 8; + length |= sbic_arm_readnext(host->scsi.io_port); return length; } -static -int acornscsi_sbic_issuecmd (AS_Host *host, int command) +static int +acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg) { - int asr; + int asr; - do { - asr = sbic_arm_read (host->scsi.io_port, ASR); - } while (asr & ASR_CIP); + do { + asr = sbic_arm_read(host->scsi.io_port, ASR); + + if ((asr & stat_mask) == stat) + return 0; + + udelay(1); + } while (--timeout); + + printk("scsi%d: timeout while %s\n", host->host->host_no, msg); + + return -1; +} - sbic_arm_write (host->scsi.io_port, CMND, command); +static +int acornscsi_sbic_issuecmd(AS_Host *host, int command) +{ + if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command")) + return -1; + + sbic_arm_write(host->scsi.io_port, CMND, command); return 0; } static void -acornscsi_csdelay (unsigned int cs) +acornscsi_csdelay(unsigned int cs) { unsigned long target_jiffies, flags; target_jiffies = jiffies + 1 + cs * HZ / 100; - save_flags (flags); - sti (); + save_flags(flags); + sti(); while (time_before(jiffies, target_jiffies)) barrier(); - restore_flags (flags); + restore_flags(flags); } static -void acornscsi_resetcard (AS_Host *host) +void acornscsi_resetcard(AS_Host *host) { - unsigned int i; + unsigned int i, timeout; /* assert reset line */ host->card.page_reg = 0x80; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* wait 3 cs. SCSI standard says 25ms. */ - acornscsi_csdelay (3); + acornscsi_csdelay(3); host->card.page_reg = 0; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* * Should get a reset from the card */ - while (!(inb (host->card.io_intr) & 8)); - sbic_arm_read (host->scsi.io_port, ASR); - sbic_arm_read (host->scsi.io_port, SSR); + timeout = 1000; + do { + if (inb(host->card.io_intr) & 8) + break; + udelay(1); + } while (--timeout); + + if (timeout == 0) + printk("scsi%d: timeout while resetting card\n", + host->host->host_no); + + sbic_arm_read(host->scsi.io_port, ASR); + sbic_arm_read(host->scsi.io_port, SSR); /* setup sbic - WD33C93A */ - sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET); /* * Command should cause a reset interrupt */ - while (!(inb (host->card.io_intr) & 8)); - sbic_arm_read (host->scsi.io_port, ASR); - if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01) - printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + timeout = 1000; + do { + if (inb(host->card.io_intr) & 8) + break; + udelay(1); + } while (--timeout); + + if (timeout == 0) + printk("scsi%d: timeout while resetting card\n", host->host->host_no); - sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + sbic_arm_read(host->scsi.io_port, ASR); + if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01) + printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + host->host->host_no); + + sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); host->card.page_reg = 0x40; - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); /* setup dmac - uPC71071 */ dmac_write(host->dma.io_port, INIT, 0); @@ -391,7 +407,7 @@ } /* wait 25 cs. SCSI standard says 250ms. */ - acornscsi_csdelay (25); + acornscsi_csdelay(25); } /*============================================================================================= @@ -461,80 +477,101 @@ }; static -void print_scsi_status (unsigned int ssr) +void print_scsi_status(unsigned int ssr) { if (acornscsi_map[ssr] != -1) - printk ("%s:%s", + printk("%s:%s", acornscsi_interrupttype[(ssr >> 4)], acornscsi_interruptcode[acornscsi_map[ssr]]); else - printk ("%X:%X", ssr >> 4, ssr & 0x0f); + printk("%X:%X", ssr >> 4, ssr & 0x0f); } #endif static -void print_sbic_status (int asr, int ssr, int cmdphase) +void print_sbic_status(int asr, int ssr, int cmdphase) { #ifdef CONFIG_ACORNSCSI_CONSTANTS - printk ("sbic: %c%c%c%c%c%c ", + printk("sbic: %c%c%c%c%c%c ", asr & ASR_INT ? 'I' : 'i', asr & ASR_LCI ? 'L' : 'l', asr & ASR_BSY ? 'B' : 'b', asr & ASR_CIP ? 'C' : 'c', asr & ASR_PE ? 'P' : 'p', asr & ASR_DBR ? 'D' : 'd'); - printk ("scsi: "); - print_scsi_status (ssr); - printk (" ph %02X\n", cmdphase); + printk("scsi: "); + print_scsi_status(ssr); + printk(" ph %02X\n", cmdphase); #else - printk ("sbic: %02X scsi: %X:%X ph: %02X\n", + printk("sbic: %02X scsi: %X:%X ph: %02X\n", asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase); #endif } -static -void acornscsi_dumplog (AS_Host *host, int target) +static void +acornscsi_dumplogline(AS_Host *host, int target, int line) { - unsigned int prev; - do { - signed int statptr; + unsigned long prev; + signed int ptr; - printk ("%c:", target == 8 ? 'H' : ('0' + target)); - statptr = status_ptr[target] - 10; + ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT; + if (ptr < 0) + ptr += STATUS_BUFFER_SIZE; - if (statptr < 0) - statptr += 16; + printk("%c: %3s:", target == 8 ? 'H' : '0' + target, + line == 0 ? "ph" : line == 1 ? "ssr" : "int"); - prev = status[target][statptr].when; + prev = host->status[target][ptr].when; - for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) { - if (status[target][statptr].when) { -#ifdef CONFIG_ACORNSCSI_CONSTANTS - printk ("%c%02X:S=", - status[target][statptr].irq ? '-' : ' ', - status[target][statptr].ph); - print_scsi_status (status[target][statptr].ssr); -#else - printk ("%c%02X:%02X", - status[target][statptr].irq ? '-' : ' ', - status[target][statptr].ph, - status[target][statptr].ssr); -#endif - printk ("+%02ld", - (status[target][statptr].when - prev) < 100 ? - (status[target][statptr].when - prev) : 99); - prev = status[target][statptr].when; - } + for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) { + unsigned long time_diff; + + if (!host->status[target][ptr].when) + continue; + + switch (line) { + case 0: + printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ', + host->status[target][ptr].ph); + break; + + case 1: + printk(" %02X", host->status[target][ptr].ssr); + break; + + case 2: + time_diff = host->status[target][ptr].when - prev; + prev = host->status[target][ptr].when; + if (time_diff == 0) + printk("==^"); + else if (time_diff >= 100) + printk(" "); + else + printk(" %02ld", time_diff); + break; + } } - printk ("\n"); + + printk("\n"); +} + +static +void acornscsi_dumplog(AS_Host *host, int target) +{ + do { + acornscsi_dumplogline(host, target, 0); + acornscsi_dumplogline(host, target, 1); + acornscsi_dumplogline(host, target, 2); + if (target == 8) break; + target = 8; } while (1); } static -char acornscsi_target (AS_Host *host) +char acornscsi_target(AS_Host *host) { if (host->SCpnt) return '0' + host->SCpnt->target; @@ -542,7 +579,7 @@ } /* - * Prototype: cmdtype_t acornscsi_cmdtype (int command) + * Prototype: cmdtype_t acornscsi_cmdtype(int command) * Purpose : differentiate READ from WRITE from other commands * Params : command - command to interpret * Returns : CMD_READ - command reads data, @@ -550,7 +587,7 @@ * CMD_MISC - everything else */ static inline -cmdtype_t acornscsi_cmdtype (int command) +cmdtype_t acornscsi_cmdtype(int command) { switch (command) { case WRITE_6: case WRITE_10: case WRITE_12: @@ -563,7 +600,7 @@ } /* - * Prototype: int acornscsi_datadirection (int command) + * Prototype: int acornscsi_datadirection(int command) * Purpose : differentiate between commands that have a DATA IN phase * and a DATA OUT phase * Params : command - command to interpret @@ -571,7 +608,7 @@ * DATADIR_IN - data in phase expected */ static -datadir_t acornscsi_datadirection (int command) +datadir_t acornscsi_datadirection(int command) { switch (command) { case CHANGE_DEFINITION: case COMPARE: case COPY: @@ -605,13 +642,13 @@ }; /* - * Prototype: int acornscsi_getperiod (unsigned char syncxfer) + * Prototype: int acornscsi_getperiod(unsigned char syncxfer) * Purpose : period for the synchronous transfer setting * Params : syncxfer SYNCXFER register value * Returns : period in ns. */ static -int acornscsi_getperiod (unsigned char syncxfer) +int acornscsi_getperiod(unsigned char syncxfer) { int i; @@ -626,14 +663,14 @@ } /* - * Prototype: int round_period (unsigned int period) + * Prototype: int round_period(unsigned int period) * Purpose : return index into above table for a required REQ period * Params : period - time (ns) for REQ * Returns : table index * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */ static inline -int round_period (unsigned int period) +int round_period(unsigned int period) { int i; @@ -646,7 +683,7 @@ } /* - * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) + * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) * Purpose : calculate value for 33c93s SYNC register * Params : period - time (ns) for REQ * offset - offset in bytes between REQ/ACK @@ -654,7 +691,7 @@ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting */ static -unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) +unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) { return sync_xfer_table[round_period(period)].reg_value | ((offset < SDTR_SIZE) ? offset : SDTR_SIZE); @@ -664,14 +701,14 @@ * Command functions */ /* - * Function: acornscsi_kick (AS_Host *host) + * Function: acornscsi_kick(AS_Host *host) * Purpose : kick next command to interface * Params : host - host to send command to * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING * Notes : interrupts are always disabled! */ static -intr_ret_t acornscsi_kick (AS_Host *host) +intr_ret_t acornscsi_kick(AS_Host *host) { int from_queue = 0; Scsi_Cmnd *SCpnt; @@ -682,7 +719,7 @@ /* retrieve next command */ if (!SCpnt) { - SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns); + SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns); if (!SCpnt) return INTR_IDLE; @@ -690,11 +727,11 @@ } if (host->scsi.disconnectable && host->SCpnt) { - queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); host->scsi.disconnectable = 0; #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n", + host->host->host_no, acornscsi_target(host))); #endif host->SCpnt = NULL; } @@ -703,9 +740,9 @@ * If we have an interrupt pending, then we may have been reselected. * In this case, we don't want to write to the registers */ - if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { - sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target); - sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN); + if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { + sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->target); + sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN); } /* @@ -717,9 +754,10 @@ host->scsi.SCp = SCpnt->SCp; host->dma.xfer_setup = 0; host->dma.xfer_required = 0; + host->dma.xfer_done = 0; #if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT)) - DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n", + DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n", host->host->host_no, '0' + SCpnt->target, SCpnt->cmnd[0])); #endif @@ -736,11 +774,11 @@ SCpnt->tag = SCpnt->device->current_tag; } else #endif - set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + set_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); host->stats.removes += 1; - switch (acornscsi_cmdtype (SCpnt->cmnd[0])) { + switch (acornscsi_cmdtype(SCpnt->cmnd[0])) { case CMD_WRITE: host->stats.writes += 1; break; @@ -757,25 +795,25 @@ } /* - * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) + * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) * Purpose : complete processing for command * Params : host - interface that completed * result - driver byte of result */ static -void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) +void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) { Scsi_Cmnd *SCpnt = *SCpntp; /* clean up */ - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); host->stats.fins += 1; if (SCpnt) { *SCpntp = NULL; - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status; @@ -787,35 +825,63 @@ * It doesn't appear to be set to something meaningful by the higher * levels all the time. */ - if (host->scsi.SCp.ptr && result == DID_OK && - acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) { - switch (status_byte (SCpnt->result)) { - case CHECK_CONDITION: - case COMMAND_TERMINATED: - case BUSY: - case QUEUE_FULL: - case RESERVATION_CONFLICT: - break; + if (result == DID_OK) { + int xfer_warn = 0; - default: - printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", - host->host->host_no, SCpnt->result); - print_command (SCpnt->cmnd); - acornscsi_dumpdma (host, "done"); - acornscsi_dumplog (host, SCpnt->target); - SCpnt->result &= 0xffff; - SCpnt->result |= DID_ERROR << 16; - } + if (SCpnt->underflow == 0) { + if (host->scsi.SCp.ptr && + acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC) + xfer_warn = 1; + } else { + if (host->scsi.SCp.scsi_xferred < SCpnt->underflow || + host->scsi.SCp.scsi_xferred != host->dma.transferred) + xfer_warn = 1; + } + + /* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6) + * Targets which break data transfers into multiple + * connections shall end each successful connection + * (except possibly the last) with a SAVE DATA + * POINTER - DISCONNECT message sequence. + * + * This makes it difficult to ensure that a transfer has + * completed. If we reach the end of a transfer during + * the command, then we can only have finished the transfer. + * therefore, if we seem to have some data remaining, this + * is not a problem. + */ + if (host->dma.xfer_done) + xfer_warn = 0; + + if (xfer_warn) { + switch (status_byte(SCpnt->result)) { + case CHECK_CONDITION: + case COMMAND_TERMINATED: + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + break; + + default: + printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", + host->host->host_no, SCpnt->result); + print_command(SCpnt->cmnd); + acornscsi_dumpdma(host, "done"); + acornscsi_dumplog(host, SCpnt->target); + SCpnt->result &= 0xffff; + SCpnt->result |= DID_ERROR << 16; + } + } } if (!SCpnt->scsi_done) - panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); + panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); - clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } else - printk ("scsi%d: null command in acornscsi_done", host->host->host_no); + printk("scsi%d: null command in acornscsi_done", host->host->host_no); host->scsi.phase = PHASE_IDLE; } @@ -828,7 +894,7 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length) +void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length) { SCp->ptr += length; SCp->this_residual -= length; @@ -839,13 +905,15 @@ SCp->buffers_residual--; SCp->ptr = (char *)SCp->buffer->address; SCp->this_residual = SCp->buffer->length; - } else + } else { SCp->ptr = NULL; + host->dma.xfer_done = 1; + } } } /* - * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr, + * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr, * unsigned int start_addr, unsigned int length) * Purpose : read data from DMA RAM * Params : host - host to transfer from @@ -855,16 +923,16 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_read (AS_Host *host, char *ptr, +void acornscsi_data_read(AS_Host *host, char *ptr, unsigned int start_addr, unsigned int length) { - extern void __acornscsi_in (int port, char *buf, int len); + extern void __acornscsi_in(int port, char *buf, int len); unsigned int page, offset, len = length; page = (start_addr >> 12); offset = start_addr & ((1 << 12) - 1); - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); while (len > 0) { unsigned int this_len; @@ -874,7 +942,7 @@ else this_len = len; - __acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len); + __acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len); offset += this_len; ptr += this_len; @@ -883,14 +951,14 @@ if (offset == (1 << 12)) { offset = 0; page ++; - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); } } - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); } /* - * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr, + * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr, * unsigned int start_addr, unsigned int length) * Purpose : write data to DMA RAM * Params : host - host to transfer from @@ -900,16 +968,16 @@ * Notes : this will only be one SG entry or less */ static -void acornscsi_data_write (AS_Host *host, char *ptr, +void acornscsi_data_write(AS_Host *host, char *ptr, unsigned int start_addr, unsigned int length) { - extern void __acornscsi_out (int port, char *buf, int len); + extern void __acornscsi_out(int port, char *buf, int len); unsigned int page, offset, len = length; page = (start_addr >> 12); offset = start_addr & ((1 << 12) - 1); - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); while (len > 0) { unsigned int this_len; @@ -919,7 +987,7 @@ else this_len = len; - __acornscsi_out (host->card.io_ram + (offset << 1), ptr, this_len); + __acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len); offset += this_len; ptr += this_len; @@ -928,10 +996,10 @@ if (offset == (1 << 12)) { offset = 0; page ++; - outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + outb((page & 0x3f) | host->card.page_reg, host->card.io_page); } } - outb (host->card.page_reg, host->card.io_page); + outb(host->card.page_reg, host->card.io_page); } /* ========================================================================================= @@ -939,25 +1007,25 @@ */ #ifdef USE_DMAC /* - * Prototype: void acornscsi_dmastop (AS_Host *host) + * Prototype: void acornscsi_dmastop(AS_Host *host) * Purpose : stop all DMA * Params : host - host on which to stop DMA * Notes : This is called when leaving DATA IN/OUT phase, * or when interface is RESET */ static inline -void acornscsi_dma_stop (AS_Host *host) +void acornscsi_dma_stop(AS_Host *host) { - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "stop")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "stop")); #endif } /* - * Function: void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) + * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) * Purpose : setup DMA controller for data transfer * Params : host - host to setup * direction - data transfer direction @@ -965,19 +1033,19 @@ * while we're in a DATA I/O phase */ static -void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) +void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) { unsigned int address, length, mode; host->dma.direction = direction; - dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); if (direction == DMA_OUT) { #if (DEBUG & DEBUG_NO_WRITE) if (NO_WRITE & (1 << host->SCpnt->target)) { - printk (KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", + host->host->host_no, acornscsi_target(host)); return; } #endif @@ -988,7 +1056,7 @@ /* * Allocate some buffer space, limited to half the buffer size */ - length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); if (length) { host->dma.start_addr = address = host->dma.free_addr; host->dma.free_addr = (host->dma.free_addr + length) & @@ -998,27 +1066,27 @@ * Transfer data to DMA memory */ if (direction == DMA_OUT) - acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, length); length -= 1; - dmac_write (host->dma.io_port, TXCNTLO, length); - dmac_write (host->dma.io_port, TXCNTHI, length >> 8); - dmac_write (host->dma.io_port, TXADRLO, address); - dmac_write (host->dma.io_port, TXADRMD, address >> 8); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MODECON, mode); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, length); + dmac_write(host->dma.io_port, TXCNTHI, length >> 8); + dmac_write(host->dma.io_port, TXADRLO, address); + dmac_write(host->dma.io_port, TXADRMD, address >> 8); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MODECON, mode); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "strt")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "strt")); #endif host->dma.xfer_setup = 1; } } /* - * Function: void acornscsi_dma_cleanup (AS_Host *host) + * Function: void acornscsi_dma_cleanup(AS_Host *host) * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct * Params : host - host to finish * Notes : This is called when a command is: @@ -1026,10 +1094,10 @@ * : This must not return until all transfers are completed. */ static -void acornscsi_dma_cleanup (AS_Host *host) +void acornscsi_dma_cleanup(AS_Host *host) { - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); /* * Check for a pending transfer @@ -1037,7 +1105,7 @@ if (host->dma.xfer_required) { host->dma.xfer_required = 0; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->dma.xfer_ptr, + acornscsi_data_read(host, host->dma.xfer_ptr, host->dma.xfer_start, host->dma.xfer_length); } @@ -1056,17 +1124,17 @@ /* * Calculate number of bytes transferred from DMA. */ - transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + transferred = dmac_address(host->dma.io_port) - host->dma.start_addr; host->dma.transferred += transferred; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->scsi.SCp.ptr, + acornscsi_data_read(host, host->scsi.SCp.ptr, host->dma.start_addr, transferred); /* * Update SCSI pointers */ - acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); #if (DEBUG & DEBUG_DMA) DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo")); #endif @@ -1074,7 +1142,7 @@ } /* - * Function: void acornscsi_dmacintr (AS_Host *host) + * Function: void acornscsi_dmacintr(AS_Host *host) * Purpose : handle interrupts from DMAC device * Params : host - host to process * Notes : If reading, we schedule the read to main memory & @@ -1084,21 +1152,21 @@ * : Called whenever DMAC finished it's current transfer. */ static -void acornscsi_dma_intr (AS_Host *host) +void acornscsi_dma_intr(AS_Host *host) { unsigned int address, length, transferred; #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "inti")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "inti")); #endif - dmac_write (host->dma.io_port, MASKREG, MASK_ON); - dmac_clearintr (host->dma.io_intr_clear); + dmac_write(host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr(host->dma.io_intr_clear); /* * Calculate amount transferred via DMA */ - transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + transferred = dmac_address(host->dma.io_port) - host->dma.start_addr; host->dma.transferred += transferred; /* @@ -1111,12 +1179,12 @@ host->dma.xfer_required = 1; } - acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); /* * Allocate some buffer space, limited to half the on-board RAM size */ - length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); if (length) { host->dma.start_addr = address = host->dma.free_addr; host->dma.free_addr = (host->dma.free_addr + length) & @@ -1126,19 +1194,19 @@ * Transfer data to DMA memory */ if (host->dma.direction == DMA_OUT) - acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, length); length -= 1; - dmac_write (host->dma.io_port, TXCNTLO, length); - dmac_write (host->dma.io_port, TXCNTHI, length >> 8); - dmac_write (host->dma.io_port, TXADRLO, address); - dmac_write (host->dma.io_port, TXADRMD, address >> 8); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, length); + dmac_write(host->dma.io_port, TXCNTHI, length >> 8); + dmac_write(host->dma.io_port, TXADRLO, address); + dmac_write(host->dma.io_port, TXADRMD, address >> 8); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); #if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma (host, "into")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "into")); #endif } else { host->dma.xfer_setup = 0; @@ -1149,48 +1217,48 @@ * attention condition. We continue giving one byte until * the device recognises the attention. */ - if (dmac_read (host->dma.io_port, STATUS) & STATUS_RQ0) { - acornscsi_abortcmd (host, host->SCpnt->tag); + if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) { + acornscsi_abortcmd(host, host->SCpnt->tag); - dmac_write (host->dma.io_port, TXCNTLO, 0); - dmac_write (host->dma.io_port, TXCNTHI, 0); - dmac_write (host->dma.io_port, TXADRLO, 0); - dmac_write (host->dma.io_port, TXADRMD, 0); - dmac_write (host->dma.io_port, TXADRHI, 0); - dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + dmac_write(host->dma.io_port, TXCNTLO, 0); + dmac_write(host->dma.io_port, TXCNTHI, 0); + dmac_write(host->dma.io_port, TXADRLO, 0); + dmac_write(host->dma.io_port, TXADRMD, 0); + dmac_write(host->dma.io_port, TXADRHI, 0); + dmac_write(host->dma.io_port, MASKREG, MASK_OFF); } #endif } } /* - * Function: void acornscsi_dma_xfer (AS_Host *host) + * Function: void acornscsi_dma_xfer(AS_Host *host) * Purpose : transfer data between AcornSCSI and memory * Params : host - host to process */ static -void acornscsi_dma_xfer (AS_Host *host) +void acornscsi_dma_xfer(AS_Host *host) { host->dma.xfer_required = 0; if (host->dma.direction == DMA_IN) - acornscsi_data_read (host, host->dma.xfer_ptr, + acornscsi_data_read(host, host->dma.xfer_ptr, host->dma.xfer_start, host->dma.xfer_length); } /* - * Function: void acornscsi_dma_adjust (AS_Host *host) + * Function: void acornscsi_dma_adjust(AS_Host *host) * Purpose : adjust DMA pointers & count for bytes transfered to * SBIC but not SCSI bus. * Params : host - host to adjust DMA count for */ static -void acornscsi_dma_adjust (AS_Host *host) +void acornscsi_dma_adjust(AS_Host *host) { if (host->dma.xfer_setup) { signed long transferred; #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma (host, "adji")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "adji")); #endif /* * Calculate correct DMA address - DMA is ahead of SCSI bus while @@ -1205,17 +1273,17 @@ */ transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred; if (transferred < 0) - printk ("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", - host->host->host_no, acornscsi_target (host), transferred); + printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", + host->host->host_no, acornscsi_target(host), transferred); else if (transferred == 0) host->dma.xfer_setup = 0; else { transferred += host->dma.start_addr; - dmac_write (host->dma.io_port, TXADRLO, transferred); - dmac_write (host->dma.io_port, TXADRMD, transferred >> 8); - dmac_write (host->dma.io_port, TXADRHI, transferred >> 16); + dmac_write(host->dma.io_port, TXADRLO, transferred); + dmac_write(host->dma.io_port, TXADRMD, transferred >> 8); + dmac_write(host->dma.io_port, TXADRHI, transferred >> 16); #if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo")); + DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo")); #endif } } @@ -1225,66 +1293,88 @@ /* ========================================================================================= * Data I/O */ +static int +acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout) +{ + unsigned int asr, timeout = max_timeout; + int my_ptr = *ptr; + + while (my_ptr < len) { + asr = sbic_arm_read(host->scsi.io_port, ASR); + + if (asr & ASR_DBR) { + timeout = max_timeout; + + sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]); + } else if (asr & ASR_INT) + break; + else if (--timeout == 0) + break; + udelay(1); + } + + *ptr = my_ptr; + + return (timeout == 0) ? -1 : 0; +} + /* - * Function: void acornscsi_sendcommand (AS_Host *host) + * Function: void acornscsi_sendcommand(AS_Host *host) * Purpose : send a command to a target * Params : host - host which is connected to target */ -static -void acornscsi_sendcommand (AS_Host *host) +static void +acornscsi_sendcommand(AS_Host *host) { Scsi_Cmnd *SCpnt = host->SCpnt; - unsigned int asr; - unsigned char *cmdptr, *cmdend; - sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); - sbic_arm_writenext (host->scsi.io_port, 0); - sbic_arm_writenext (host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); - - cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command; - cmdend = SCpnt->cmnd + SCpnt->cmd_len; - - while (cmdptr < cmdend) { - asr = sbic_arm_read (host->scsi.io_port, ASR); - if (asr & ASR_DBR) - sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++); - else if (asr & ASR_INT) - break; - } - if (cmdptr >= cmdend) - host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd; + sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext(host->scsi.io_port, 0); + sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); + + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); + + if (acornscsi_write_pio(host, SCpnt->cmnd, + (int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000)) + printk("scsi%d: timeout while sending command\n", host->host->host_no); + host->scsi.phase = PHASE_COMMAND; } static -void acornscsi_sendmessage (AS_Host *host) +void acornscsi_sendmessage(AS_Host *host) { - unsigned int message_length = msgqueue_msglength (&host->scsi.msgs); - int msgnr; + unsigned int message_length = msgqueue_msglength(&host->scsi.msgs); + unsigned int msgnr; struct message *msg; #if (DEBUG & DEBUG_MESSAGES) - printk ("scsi%d.%c: sending message ", - host->host->host_no, acornscsi_target (host)); + printk("scsi%d.%c: sending message ", + host->host->host_no, acornscsi_target(host)); #endif switch (message_length) { case 0: - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - sbic_arm_write (host->scsi.io_port, DATA, NOP); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1"); + + sbic_arm_write(host->scsi.io_port, DATA, NOP); + host->scsi.last_message = NOP; #if (DEBUG & DEBUG_MESSAGES) - printk ("NOP"); + printk("NOP"); #endif break; case 1: - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); msg = msgqueue_getmsg(&host->scsi.msgs, 0); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - sbic_arm_write (host->scsi.io_port, DATA, msg->msg[0]); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2"); + + sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]); + host->scsi.last_message = msg->msg[0]; #if (DEBUG & DEBUG_MESSAGES) print_msg(msg->msg); @@ -1300,86 +1390,85 @@ * initiator. This provides an interlock so that the * initiator can determine which message byte is rejected. */ - sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); - sbic_arm_writenext (host->scsi.io_port, 0); - sbic_arm_writenext (host->scsi.io_port, message_length); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext(host->scsi.io_port, 0); + sbic_arm_writenext(host->scsi.io_port, message_length); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); msgnr = 0; while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) { - unsigned int asr, i; + unsigned int i; #if (DEBUG & DEBUG_MESSAGES) - print_msg (msg); + print_msg(msg); #endif - for (i = 0; i < msg->length;) { - asr = sbic_arm_read (host->scsi.io_port, ASR); - if (asr & ASR_DBR) - sbic_arm_write (host->scsi.io_port, DATA, msg->msg[i++]); - if (asr & ASR_INT) - break; - } + i = 0; + if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000)) + printk("scsi%d: timeout while sending message\n", host->host->host_no); + host->scsi.last_message = msg->msg[0]; if (msg->msg[0] == EXTENDED_MESSAGE) host->scsi.last_message |= msg->msg[2] << 8; - if (asr & ASR_INT) + + if (i != msg->length) break; } break; } #if (DEBUG & DEBUG_MESSAGES) - printk ("\n"); + printk("\n"); #endif } /* - * Function: void acornscsi_readstatusbyte (AS_Host *host) + * Function: void acornscsi_readstatusbyte(AS_Host *host) * Purpose : Read status byte from connected target * Params : host - host connected to target */ static -void acornscsi_readstatusbyte (AS_Host *host) +void acornscsi_readstatusbyte(AS_Host *host) { - acornscsi_sbic_issuecmd (host, CMND_XFERINFO|CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); - - host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT); + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte"); + host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA); } /* - * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host) + * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host) * Purpose : Read one message byte from connected target * Params : host - host connected to target */ static -unsigned char acornscsi_readmessagebyte (AS_Host *host) +unsigned char acornscsi_readmessagebyte(AS_Host *host) { unsigned char message; - acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); + + acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte"); - message = sbic_arm_read (host->scsi.io_port, DATA); + message = sbic_arm_read(host->scsi.io_port, DATA); /* wait for MSGIN-XFER-PAUSED */ - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); - sbic_arm_read (host->scsi.io_port, SSR); + acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte"); + + sbic_arm_read(host->scsi.io_port, SSR); return message; } /* - * Function: void acornscsi_message (AS_Host *host) + * Function: void acornscsi_message(AS_Host *host) * Purpose : Read complete message from connected target & action message * Params : host - host connected to target */ static -void acornscsi_message (AS_Host *host) +void acornscsi_message(AS_Host *host) { unsigned char message[16]; unsigned int msgidx = 0, msglen = 1; do { - message[msgidx] = acornscsi_readmessagebyte (host); + message[msgidx] = acornscsi_readmessagebyte(host); switch (msgidx) { case 0: @@ -1395,17 +1484,17 @@ } msgidx += 1; if (msgidx < msglen) { - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); /* wait for next msg-in */ - while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); - sbic_arm_read (host->scsi.io_port, SSR); + acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack"); + sbic_arm_read(host->scsi.io_port, SSR); } } while (msgidx < msglen); #if (DEBUG & DEBUG_MESSAGES) printk("scsi%d.%c: message in: ", - host->host->host_no, acornscsi_target (host)); + host->host->host_no, acornscsi_target(host)); print_msg(message); printk("\n"); #endif @@ -1419,7 +1508,7 @@ */ if (message[0] == SIMPLE_QUEUE_TAG) host->scsi.reconnected.tag = message[1]; - if (acornscsi_reconnect_finish (host)) + if (acornscsi_reconnect_finish(host)) host->scsi.phase = PHASE_MSGIN; } @@ -1429,7 +1518,7 @@ case COMMAND_COMPLETE: if (host->scsi.phase != PHASE_STATUSIN) { printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n", - host->host->host_no, acornscsi_target (host)); + host->host->host_no, acornscsi_target(host)); acornscsi_dumplog(host, host->SCpnt->target); } host->scsi.phase = PHASE_DONE; @@ -1443,7 +1532,7 @@ * direct the initiator to copy the active data pointer to * the saved data pointer for the current I/O process. */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->SCpnt->SCp = host->scsi.SCp; host->SCpnt->SCp.sent_command = 0; host->scsi.phase = PHASE_MSGIN; @@ -1459,7 +1548,7 @@ * status pointers shall be restored to the beginning of * the present command and status areas.' */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->scsi.SCp = host->SCpnt->SCp; host->scsi.phase = PHASE_MSGIN; break; @@ -1474,7 +1563,7 @@ * message. When reconnection is completed, the most recent * saved pointer values are restored.' */ - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->scsi.phase = PHASE_DISCONNECT; break; @@ -1493,8 +1582,8 @@ /* * If we have any messages waiting to go out, then assert ATN now */ - if (msgqueue_msglength (&host->scsi.msgs)) - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + if (msgqueue_msglength(&host->scsi.msgs)) + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); switch (host->scsi.last_message) { #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE @@ -1507,21 +1596,21 @@ * message is received, it shall respond with a MESSAGE REJECT * message and accept the I/O process as if it were untagged. */ - printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", + host->host->host_no, acornscsi_target(host)); host->SCpnt->device->tagged_queue = 0; - set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); + set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); break; #endif case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): /* * Target can't handle synchronous transfers */ - printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", + host->host->host_no, acornscsi_target(host)); host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA; host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS; - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break; default: @@ -1535,8 +1624,8 @@ case SIMPLE_QUEUE_TAG: /* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */ - printk ("scsi%d.%c: reconnect queue tag %02X\n", - host->host->host_no, acornscsi_target (host), + printk("scsi%d.%c: reconnect queue tag %02X\n", + host->host->host_no, acornscsi_target(host), message[1]); break; @@ -1552,26 +1641,26 @@ * and the target retries fail, then we fallback to asynchronous mode */ host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED; - printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", + printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", host->host->host_no, acornscsi_target(host), message[4], message[3] * 4); host->device[host->SCpnt->target].sync_xfer = - calc_sync_xfer (message[3] * 4, message[4]); + calc_sync_xfer(message[3] * 4, message[4]); } else { unsigned char period, length; /* * Target requested synchronous transfers. The agreement is only * to be in operation AFTER the target leaves message out phase. */ - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - period = max (message[3], sdtr_period / 4); - length = min (message[4], sdtr_size); - msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + period = max(message[3], sdtr_period / 4); + length = min(message[4], sdtr_size); + msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, period, length); host->device[host->SCpnt->target].sync_xfer = - calc_sync_xfer (period * 4, length); + calc_sync_xfer(period * 4, length); } - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); break; #else /* We do not accept synchronous transfers. Respond with a @@ -1584,9 +1673,9 @@ * to a wide data transfer request. */ default: - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); - msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_flush(&host->scsi.msgs); + msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); break; } break; @@ -1607,19 +1696,19 @@ * if there are more linked commands available. */ if (!host->SCpnt->next_link) { - printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", - instance->host_no, acornscsi_target (host), host->SCpnt->tag); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", + instance->host_no, acornscsi_target(host), host->SCpnt->tag); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); } else { Scsi_Cmnd *SCpnt = host->SCpnt; - acornscsi_dma_cleanup (host); + acornscsi_dma_cleanup(host); host->SCpnt = host->SCpnt->next_link; host->SCpnt->tag = SCpnt->tag; SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status; - SCpnt->done (SCpnt); + SCpnt->done(SCpnt); /* initialise host->SCpnt->SCp */ } @@ -1628,42 +1717,42 @@ #endif default: /* reject message */ - printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", - host->host->host_no, acornscsi_target (host), + printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", + host->host->host_no, acornscsi_target(host), message[0]); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); - msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); + msgqueue_flush(&host->scsi.msgs); + msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); host->scsi.phase = PHASE_MSGIN; break; } - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); } /* - * Function: int acornscsi_buildmessages (AS_Host *host) + * Function: int acornscsi_buildmessages(AS_Host *host) * Purpose : build the connection messages for a host * Params : host - host to add messages to */ static -void acornscsi_buildmessages (AS_Host *host) +void acornscsi_buildmessages(AS_Host *host) { #if 0 /* does the device need resetting? */ if (cmd_reset) { - msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET); + msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET); return; } #endif - msgqueue_addmsg (&host->scsi.msgs, 1, + msgqueue_addmsg(&host->scsi.msgs, 1, IDENTIFY(host->device[host->SCpnt->target].disconnect_ok, host->SCpnt->lun)); #if 0 /* does the device need the current command aborted */ if (cmd_aborted) { - acornscsi_abortcmd (host->SCpnt->tag); + acornscsi_abortcmd(host->SCpnt->tag); return; } #endif @@ -1678,14 +1767,14 @@ tag_type = HEAD_OF_QUEUE_TAG; else tag_type = SIMPLE_QUEUE_TAG; - msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); + msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); } #endif #ifdef CONFIG_SCSI_ACORNSCSI_SYNC if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) { host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST; - msgqueue_addmsg (&host->scsi.msgs, 5, + msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, sdtr_period / 4, sdtr_size); } @@ -1693,29 +1782,29 @@ } /* - * Function: int acornscsi_starttransfer (AS_Host *host) + * Function: int acornscsi_starttransfer(AS_Host *host) * Purpose : transfer data to/from connected target * Params : host - host to which target is connected * Returns : 0 if failure */ static -int acornscsi_starttransfer (AS_Host *host) +int acornscsi_starttransfer(AS_Host *host) { int residual; if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) { - printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", + host->host->host_no, acornscsi_target(host)); return 0; } residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred; - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); - sbic_arm_writenext (host->scsi.io_port, residual >> 16); - sbic_arm_writenext (host->scsi.io_port, residual >> 8); - sbic_arm_writenext (host->scsi.io_port, residual); - acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_writenext(host->scsi.io_port, residual >> 16); + sbic_arm_writenext(host->scsi.io_port, residual >> 8); + sbic_arm_writenext(host->scsi.io_port, residual); + acornscsi_sbic_issuecmd(host, CMND_XFERINFO); return 1; } @@ -1723,7 +1812,7 @@ * Connection & Disconnection */ /* - * Function : acornscsi_reconnect (AS_Host *host) + * Function : acornscsi_reconnect(AS_Host *host) * Purpose : reconnect a previously disconnected command * Params : host - host specific data * Remarks : SCSI spec says: @@ -1731,27 +1820,27 @@ * of saved pointers upon reconnection of the I/O process' */ static -int acornscsi_reconnect (AS_Host *host) +int acornscsi_reconnect(AS_Host *host) { unsigned int target, lun, ok = 0; - target = sbic_arm_read (host->scsi.io_port, SOURCEID); + target = sbic_arm_read(host->scsi.io_port, SOURCEID); if (!(target & 8)) - printk (KERN_ERR "scsi%d: invalid source id after reselection " + printk(KERN_ERR "scsi%d: invalid source id after reselection " "- device fault?\n", host->host->host_no); target &= 7; if (host->SCpnt && !host->scsi.disconnectable) { - printk (KERN_ERR "scsi%d.%d: reconnected while command in " + printk(KERN_ERR "scsi%d.%d: reconnected while command in " "progress to target %d?\n", host->host->host_no, target, host->SCpnt->target); host->SCpnt = NULL; } - lun = sbic_arm_read (host->scsi.io_port, DATA) & 7; + lun = sbic_arm_read(host->scsi.io_port, DATA) & 7; host->scsi.reconnected.target = target; host->scsi.reconnected.lun = lun; @@ -1761,7 +1850,7 @@ host->SCpnt->target == target && host->SCpnt->lun == lun) ok = 1; - if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun)) + if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun)) ok = 1; ADD_STATUS(target, 0x81, host->scsi.phase, 0); @@ -1770,26 +1859,28 @@ host->scsi.phase = PHASE_RECONNECTED; } else { /* this doesn't seem to work */ - printk (KERN_ERR "scsi%d.%c: reselected with no command " + printk(KERN_ERR "scsi%d.%c: reselected with no command " "to reconnect with\n", host->host->host_no, '0' + target); - acornscsi_dumplog (host, target); - acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); - host->scsi.phase = PHASE_ABORTED; + acornscsi_dumplog(host, target); + acornscsi_abortcmd(host, 0); + if (host->SCpnt) { + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); + host->SCpnt = NULL; + } } - acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); return !ok; } /* - * Function: int acornscsi_reconect_finish (AS_Host *host) + * Function: int acornscsi_reconect_finish(AS_Host *host) * Purpose : finish reconnecting a command * Params : host - host to complete * Returns : 0 if failed */ static -int acornscsi_reconnect_finish (AS_Host *host) +int acornscsi_reconnect_finish(AS_Host *host) { if (host->scsi.disconnectable && host->SCpnt) { host->scsi.disconnectable = 0; @@ -1797,45 +1888,44 @@ host->SCpnt->lun == host->scsi.reconnected.lun && host->SCpnt->tag == host->scsi.reconnected.tag) { #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: reconnected", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: reconnected", + host->host->host_no, acornscsi_target(host))); #endif } else { - queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: had to move command " + DBG(host->SCpnt, printk("scsi%d.%c: had to move command " "to disconnected queue\n", - host->host->host_no, acornscsi_target (host))); + host->host->host_no, acornscsi_target(host))); #endif host->SCpnt = NULL; } } if (!host->SCpnt) { - host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected, + host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected, host->scsi.reconnected.target, host->scsi.reconnected.lun, host->scsi.reconnected.tag); #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk ("scsi%d.%c: had to get command", - host->host->host_no, acornscsi_target (host))); + DBG(host->SCpnt, printk("scsi%d.%c: had to get command", + host->host->host_no, acornscsi_target(host))); #endif } - if (!host->SCpnt) { - acornscsi_abortcmd (host, host->scsi.reconnected.tag); - host->scsi.phase = PHASE_ABORTED; - } else { + if (!host->SCpnt) + acornscsi_abortcmd(host, host->scsi.reconnected.tag); + else { /* * Restore data pointer from SAVED pointers. */ host->scsi.SCp = host->SCpnt->SCp; #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk (", data pointers: [%p, %X]", + printk(", data pointers: [%p, %X]", host->scsi.SCp.ptr, host->scsi.SCp.this_residual); #endif } #if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk ("\n"); + printk("\n"); #endif host->dma.transferred = host->scsi.SCp.scsi_xferred; @@ -1844,47 +1934,48 @@ } /* - * Function: void acornscsi_disconnect_unexpected (AS_Host *host) + * Function: void acornscsi_disconnect_unexpected(AS_Host *host) * Purpose : handle an unexpected disconnect * Params : host - host on which disconnect occurred */ static -void acornscsi_disconnect_unexpected (AS_Host *host) +void acornscsi_disconnect_unexpected(AS_Host *host) { - printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n", - host->host->host_no, acornscsi_target (host)); + printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n", + host->host->host_no, acornscsi_target(host)); #if (DEBUG & DEBUG_ABORT) - acornscsi_dumplog (host, 8); + acornscsi_dumplog(host, 8); #endif - acornscsi_done (host, &host->SCpnt, DID_ABORT); + acornscsi_done(host, &host->SCpnt, DID_ERROR); } /* - * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag) + * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag) * Purpose : abort a currently executing command * Params : host - host with connected command to abort * tag - tag to abort */ static -void acornscsi_abortcmd (AS_Host *host, unsigned char tag) +void acornscsi_abortcmd(AS_Host *host, unsigned char tag) { - sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN); + host->scsi.phase = PHASE_ABORTED; + sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN); - msgqueue_flush (&host->scsi.msgs); + msgqueue_flush(&host->scsi.msgs); #ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE if (tag) - msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag); + msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag); else #endif - msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); } /* ========================================================================================== * Interrupt routines. */ /* - * Function: int acornscsi_sbicintr (AS_Host *host) + * Function: int acornscsi_sbicintr(AS_Host *host) * Purpose : handle interrupts from SCSI device * Params : host - host to process * Returns : INTR_PROCESS if expecting another SBIC interrupt @@ -1892,15 +1983,15 @@ * INTR_NEXT_COMMAND if we have finished processing the command */ static -intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq) +intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) { unsigned int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); + asr = sbic_arm_read(host->scsi.io_port, ASR); if (!(asr & ASR_INT)) return INTR_IDLE; - ssr = sbic_arm_read (host->scsi.io_port, SSR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); #if (DEBUG & DEBUG_PHASES) print_sbic_status(asr, ssr, host->scsi.phase); @@ -1913,23 +2004,23 @@ switch (ssr) { case 0x00: /* reset state - not advanced */ - printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", + printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", host->host->host_no); /* setup sbic - WD33C93A */ - sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET); return INTR_IDLE; case 0x01: /* reset state - advanced */ - sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); - sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); - msgqueue_flush (&host->scsi.msgs); + sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + msgqueue_flush(&host->scsi.msgs); return INTR_IDLE; case 0x41: /* unexpected disconnect aborted command */ - acornscsi_disconnect_unexpected (host); + acornscsi_disconnect_unexpected(host); return INTR_NEXT_COMMAND; } @@ -1939,35 +2030,35 @@ case 0x11: /* -> PHASE_CONNECTED */ /* BUS FREE -> SELECTION */ host->scsi.phase = PHASE_CONNECTED; - msgqueue_flush (&host->scsi.msgs); + msgqueue_flush(&host->scsi.msgs); host->dma.transferred = host->scsi.SCp.scsi_xferred; /* 33C93 gives next interrupt indicating bus phase */ - asr = sbic_arm_read (host->scsi.io_port, ASR); + asr = sbic_arm_read(host->scsi.io_port, ASR); if (!(asr & ASR_INT)) break; - ssr = sbic_arm_read (host->scsi.io_port, SSR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); ADD_STATUS(8, ssr, host->scsi.phase, 1); ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1); goto connected; case 0x42: /* select timed out */ /* -> PHASE_IDLE */ - acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT); + acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT); return INTR_NEXT_COMMAND; case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */ /* BUS FREE -> RESELECTION */ host->origSCpnt = host->SCpnt; host->SCpnt = NULL; - msgqueue_flush (&host->scsi.msgs); - acornscsi_reconnect (host); + msgqueue_flush(&host->scsi.msgs); + acornscsi_reconnect(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); - acornscsi_abortcmd (host, host->SCpnt->tag); + printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd(host, host->SCpnt->tag); } return INTR_PROCESSING; @@ -1977,12 +2068,12 @@ #ifdef NONSTANDARD case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* SELECTION -> COMMAND */ - acornscsi_sendcommand (host); + acornscsi_sendcommand(host); break; case 0x8b: /* -> PHASE_STATUS */ /* SELECTION -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; #endif @@ -1990,55 +2081,57 @@ case 0x8e: /* -> PHASE_MSGOUT */ /* SELECTION ->MESSAGE OUT */ host->scsi.phase = PHASE_MSGOUT; - acornscsi_buildmessages (host); - acornscsi_sendmessage (host); + acornscsi_buildmessages(host); + acornscsi_sendmessage(host); break; /* these should not happen */ case 0x85: /* target disconnected */ - acornscsi_done (host, &host->SCpnt, DID_ERROR); + acornscsi_done(host, &host->SCpnt, DID_ERROR); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); - acornscsi_abortcmd (host, host->SCpnt->tag); + printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd(host, host->SCpnt->tag); } return INTR_PROCESSING; case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */ /* - * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase + * SCSI standard says that MESSAGE OUT phases can be followed by a + * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase */ switch (ssr) { - case 0x8a: + case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ /* MESSAGE OUT -> COMMAND */ - acornscsi_sendcommand (host); + acornscsi_sendcommand(host); break; + case 0x8b: /* -> PHASE_STATUS */ case 0x1b: /* -> PHASE_STATUS */ /* MESSAGE OUT -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x8e: /* -> PHASE_MSGOUT */ /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; - case 0x4f: + case 0x4f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* MESSAGE OUT -> MESSAGE IN */ - acornscsi_message (host); + acornscsi_message(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2047,43 +2140,43 @@ case 0x18: /* -> PHASE_DATAOUT */ /* COMMAND -> DATA OUT */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd (host, host->SCpnt->tag); - acornscsi_dma_setup (host, DMA_OUT); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_abortcmd(host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_OUT); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x19: /* -> PHASE_DATAIN */ /* COMMAND -> DATA IN */ if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd (host, host->SCpnt->tag); - acornscsi_dma_setup (host, DMA_IN); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_abortcmd(host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_IN); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x1b: /* -> PHASE_STATUS */ /* COMMAND -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ /* COMMAND -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ /* COMMAND -> MESSAGE IN */ - acornscsi_message (host); + acornscsi_message(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2094,19 +2187,19 @@ host->scsi.phase = PHASE_IDLE; host->stats.disconnects += 1; } else { - printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_NEXT_COMMAND; case PHASE_IDLE: /* STATE: disconnected */ if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */ - acornscsi_reconnect (host); + acornscsi_reconnect(host); else { - printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2119,54 +2212,54 @@ * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY, * reconnect I_T_L command */ - if (ssr != 0x8f && !acornscsi_reconnect_finish (host)) + if (ssr != 0x8f && !acornscsi_reconnect_finish(host)) return INTR_IDLE; ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); switch (ssr) { case 0x88: /* data out phase */ /* -> PHASE_DATAOUT */ /* MESSAGE IN -> DATA OUT */ - acornscsi_dma_setup (host, DMA_OUT); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_OUT); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAOUT; return INTR_IDLE; case 0x89: /* data in phase */ /* -> PHASE_DATAIN */ /* MESSAGE IN -> DATA IN */ - acornscsi_dma_setup (host, DMA_IN); - if (!acornscsi_starttransfer (host)) - acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup(host, DMA_IN); + if (!acornscsi_starttransfer(host)) + acornscsi_abortcmd(host, host->SCpnt->tag); host->scsi.phase = PHASE_DATAIN; return INTR_IDLE; case 0x8a: /* command out */ /* MESSAGE IN -> COMMAND */ - acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ break; case 0x8b: /* status in */ /* -> PHASE_STATUSIN */ /* MESSAGE IN -> STATUS */ - acornscsi_readstatusbyte (host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x8e: /* message out */ /* -> PHASE_MSGOUT */ /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x8f: /* message in */ - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2177,41 +2270,45 @@ */ switch (ssr) { case 0x19: /* -> PHASE_DATAIN */ - acornscsi_abortcmd (host, host->SCpnt->tag); + case 0x89: /* -> PHASE_DATAIN */ + acornscsi_abortcmd(host, host->SCpnt->tag); return INTR_IDLE; - case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x8b: /* -> PHASE_STATUSIN */ /* DATA IN -> STATUS */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_readstatusbyte (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* DATA IN -> MESSAGE OUT */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_sendmessage (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_sendmessage(host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ + case 0x8f: /* message in */ /* DATA IN -> MESSAGE IN */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2222,58 +2319,69 @@ */ switch (ssr) { case 0x18: /* -> PHASE_DATAOUT */ - acornscsi_abortcmd (host, host->SCpnt->tag); + case 0x88: /* -> PHASE_DATAOUT */ + acornscsi_abortcmd(host, host->SCpnt->tag); return INTR_IDLE; - case 0x4b: /* -> PHASE_STATUSIN */ case 0x1b: /* -> PHASE_STATUSIN */ + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x8b: /* -> PHASE_STATUSIN */ /* DATA OUT -> STATUS */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_readstatusbyte (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_readstatusbyte(host); host->scsi.phase = PHASE_STATUSIN; break; case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* DATA OUT -> MESSAGE OUT */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_sendmessage (host); + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_sendmessage(host); break; case 0x1f: /* message in */ case 0x4f: /* message in */ + case 0x8f: /* message in */ /* DATA OUT -> MESSAGE IN */ host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen - - acornscsi_sbic_xfcount (host); - acornscsi_dma_stop (host); - acornscsi_dma_adjust (host); - acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + acornscsi_sbic_xfcount(host); + acornscsi_dma_stop(host); + acornscsi_dma_adjust(host); + acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_STATUSIN: /* STATE: status in complete */ - if (ssr == 0x1f) /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + switch (ssr) { + case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + case 0x8f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ /* STATUS -> MESSAGE IN */ - acornscsi_message (host); - else if (ssr == 0x1e) /* -> PHASE_MSGOUT */ + acornscsi_message(host); + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* STATUS -> MESSAGE OUT */ - acornscsi_sendmessage (host); - else { - printk (KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_sendmessage(host); + break; + + default: + printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; @@ -2281,78 +2389,93 @@ switch (ssr) { case 0x1e: /* -> PHASE_MSGOUT */ case 0x4e: /* -> PHASE_MSGOUT */ + case 0x8e: /* -> PHASE_MSGOUT */ /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ case 0x2f: case 0x4f: case 0x8f: - acornscsi_message (host); + acornscsi_message(host); + break; + + case 0x85: + printk("scsi%d.%c: strange message in disconnection\n", + host->host->host_no, acornscsi_target(host)); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_done(host, &host->SCpnt, DID_ERROR); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_DONE: /* STATE: received status & message */ switch (ssr) { case 0x85: /* -> PHASE_IDLE */ - acornscsi_done (host, &host->SCpnt, DID_OK); + acornscsi_done(host, &host->SCpnt, DID_OK); return INTR_NEXT_COMMAND; + case 0x1e: case 0x8e: - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; case PHASE_ABORTED: switch (ssr) { case 0x85: - acornscsi_done (host, &host->SCpnt, DID_ABORT); + if (host->SCpnt) + acornscsi_done(host, &host->SCpnt, DID_ABORT); + else { + clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun, + host->busyluns); + host->scsi.phase = PHASE_IDLE; + } return INTR_NEXT_COMMAND; case 0x1e: case 0x2e: case 0x4e: case 0x8e: - acornscsi_sendmessage (host); + acornscsi_sendmessage(host); break; default: - printk (KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; default: - printk (KERN_ERR "scsi%d.%c: unknown driver phase %d\n", - host->host->host_no, acornscsi_target (host), ssr); - acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n", + host->host->host_no, acornscsi_target(host), ssr); + acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8); } return INTR_PROCESSING; } /* - * Prototype: void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) + * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) * Purpose : handle interrupts from Acorn SCSI card * Params : irq - interrupt number * dev_id - device specific data (AS_Host structure) * regs - processor registers when interrupt occurred */ static -void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) +void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs) { AS_Host *host = (AS_Host *)dev_id; intr_ret_t ret; @@ -2360,21 +2483,21 @@ int in_irq = 0; if (host->scsi.interrupt) - printk ("scsi%d: interrupt re-entered\n", host->host->host_no); + printk("scsi%d: interrupt re-entered\n", host->host->host_no); host->scsi.interrupt = 1; do { ret = INTR_IDLE; - iostatus = inb (host->card.io_intr); + iostatus = inb(host->card.io_intr); if (iostatus & 2) { - acornscsi_dma_intr (host); - iostatus = inb (host->card.io_intr); + acornscsi_dma_intr(host); + iostatus = inb(host->card.io_intr); } if (iostatus & 8) - ret = acornscsi_sbicintr (host, in_irq); + ret = acornscsi_sbicintr(host, in_irq); /* * If we have a transfer pending, start it. @@ -2382,10 +2505,10 @@ * it's data */ if (host->dma.xfer_required) - acornscsi_dma_xfer (host); + acornscsi_dma_xfer(host); if (ret == INTR_NEXT_COMMAND) - ret = acornscsi_kick (host); + ret = acornscsi_kick(host); in_irq = 1; } while (ret != INTR_IDLE); @@ -2398,29 +2521,29 @@ */ /* - * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * Purpose : queues a SCSI command * Params : cmd - SCSI command * done - function called on completion, with pointer to command descriptor * Returns : 0, or < 0 on error. */ -int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { AS_Host *host = (AS_Host *)SCpnt->host->hostdata; if (!done) { /* there should be some way of rejecting errors like this without panicing... */ - panic ("scsi%d: queuecommand called with NULL done function [cmd=%p]", + panic("scsi%d: queuecommand called with NULL done function [cmd=%p]", SCpnt->host->host_no, SCpnt); return -EINVAL; } #if (DEBUG & DEBUG_NO_WRITE) - if (acornscsi_cmdtype (SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { - printk (KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", + if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { + printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", SCpnt->host->host_no, '0' + SCpnt->target); SCpnt->result = DID_NO_CONNECT << 16; - done (SCpnt); + done(SCpnt); return 0; } #endif @@ -2429,7 +2552,7 @@ SCpnt->host_scribble = NULL; SCpnt->result = 0; SCpnt->tag = 0; - SCpnt->SCp.phase = (int)acornscsi_datadirection (SCpnt->cmnd[0]); + SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]); SCpnt->SCp.sent_command = 0; SCpnt->SCp.scsi_xferred = 0; SCpnt->SCp.Status = 0; @@ -2452,21 +2575,21 @@ { unsigned long flags; - if (!queue_add_cmd_ordered (&host->queues.issue, SCpnt)) { + if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) { SCpnt->result = DID_ERROR << 16; - done (SCpnt); + done(SCpnt); return 0; } - save_flags_cli (flags); + save_flags_cli(flags); if (host->scsi.phase == PHASE_IDLE) - acornscsi_kick (host); - restore_flags (flags); + acornscsi_kick(host); + restore_flags(flags); } return 0; } /* - * Prototype: void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) + * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 * Params : SCpntp1 - pointer to command to return * SCpntp2 - pointer to command to check @@ -2474,7 +2597,7 @@ * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2. */ static inline -void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) +void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) { Scsi_Cmnd *SCpnt = *SCpntp1; @@ -2482,80 +2605,203 @@ *SCpntp1 = NULL; SCpnt->result = result; - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } if (SCpnt == *SCpntp2) *SCpntp2 = NULL; } +enum res_abort { res_not_running, res_success, res_success_clear, res_snooze }; + +/* + * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt) + * Purpose : abort a command on this host + * Params : SCpnt - command to abort + * Returns : our abort status + */ +static enum res_abort +acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt) +{ + enum res_abort res = res_not_running; + + if (queue_removecmd(&host->queues.issue, SCpnt)) { + /* + * The command was on the issue queue, and has not been + * issued yet. We can remove the command from the queue, + * and acknowledge the abort. Neither the devices nor the + * interface know about the command. + */ +//#if (DEBUG & DEBUG_ABORT) + printk("on issue queue "); +//#endif + res = res_success; + } else if (queue_removecmd(&host->queues.disconnected, SCpnt)) { + /* + * The command was on the disconnected queue. Simply + * acknowledge the abort condition, and when the target + * reconnects, we will give it an ABORT message. The + * target should then disconnect, and we will clear + * the busylun bit. + */ +//#if (DEBUG & DEBUG_ABORT) + printk("on disconnected queue "); +//#endif + res = res_success; + } else if (host->SCpnt == SCpnt) { + unsigned long flags; + +//#if (DEBUG & DEBUG_ABORT) + printk("executing "); +//#endif + + save_flags(flags); + cli(); + switch (host->scsi.phase) { + /* + * If the interface is idle, and the command is 'disconnectable', + * then it is the same as on the disconnected queue. We simply + * remove all traces of the command. When the target reconnects, + * we will give it an ABORT message since the command could not + * be found. When the target finally disconnects, we will clear + * the busylun bit. + */ + case PHASE_IDLE: + if (host->scsi.disconnectable) { + host->scsi.disconnectable = 0; + host->SCpnt = NULL; + res = res_success; + } + break; + + /* + * If the command has connected and done nothing further, + * simply force a disconnect. We also need to clear the + * busylun bit. + */ + case PHASE_CONNECTED: + sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT); + host->SCpnt = NULL; + res = res_success_clear; + break; + + default: + acornscsi_abortcmd(host, host->SCpnt->tag); + res = res_snooze; + } + restore_flags(flags); + } else if (host->origSCpnt == SCpnt) { + /* + * The command will be executed next, but a command + * is currently using the interface. This is similar to + * being on the issue queue, except the busylun bit has + * been set. + */ + host->origSCpnt = NULL; +//#if (DEBUG & DEBUG_ABORT) + printk("waiting for execution "); +//#endif + res = res_success_clear; + } else + printk("unknown "); + + return res; +} + /* - * Prototype: int acornscsi_abort (Scsi_Cmnd *SCpnt) + * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt) * Purpose : abort a command on this host * Params : SCpnt - command to abort * Returns : one of SCSI_ABORT_ macros */ -int acornscsi_abort (Scsi_Cmnd *SCpnt) +int acornscsi_abort(Scsi_Cmnd *SCpnt) { - AS_Host *host = (AS_Host *) SCpnt->host->hostdata; - int result = SCSI_ABORT_NOT_RUNNING; + AS_Host *host = (AS_Host *) SCpnt->host->hostdata; + int result; - host->stats.aborts += 1; + host->stats.aborts += 1; #if (DEBUG & DEBUG_ABORT) - { - int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); - ssr = sbic_arm_read (host->scsi.io_port, SSR); + { + int asr, ssr; + asr = sbic_arm_read(host->scsi.io_port, ASR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); - printk (KERN_WARNING "acornscsi_abort: "); - print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog (host, SCpnt->target); - } + printk(KERN_WARNING "acornscsi_abort: "); + print_sbic_status(asr, ssr, host->scsi.phase); + acornscsi_dumplog(host, SCpnt->target); + } #endif - if (queue_removecmd (&host->queues.issue, SCpnt)) { - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done (SCpnt); -#if (DEBUG & DEBUG_ABORT) - printk ("scsi%d: command on issue queue\n", host->host->host_no); -#endif - result = SCSI_ABORT_SUCCESS; - } else if (queue_cmdonqueue (&host->queues.disconnected, SCpnt)) { - printk ("scsi%d: command on disconnected queue\n", host->host->host_no); - result = SCSI_ABORT_SNOOZE; - } else if (host->SCpnt == SCpnt) { - acornscsi_abortcmd (host, host->SCpnt->tag); - printk ("scsi%d: command executing\n", host->host->host_no); - result = SCSI_ABORT_SNOOZE; - } else if (host->origSCpnt == SCpnt) { - host->origSCpnt = NULL; - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done (SCpnt); -#if (DEBUG & DEBUG_ABORT) - printk ("scsi%d: command waiting for execution\n", host->host->host_no); -#endif - result = SCSI_ABORT_SUCCESS; - } + printk("scsi%d: ", host->host->host_no); + + switch (acornscsi_do_abort(host, SCpnt)) { + /* + * We managed to find the command and cleared it out. + * We do not expect the command to be executing on the + * target, but we have set the busylun bit. + */ + case res_success_clear: +//#if (DEBUG & DEBUG_ABORT) + printk("clear "); +//#endif + clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns); + + /* + * We found the command, and cleared it out. Either + * the command is still known to be executing on the + * target, or the busylun bit is not set. + */ + case res_success: +//#if (DEBUG & DEBUG_ABORT) + printk("success\n"); +//#endif + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done(SCpnt); + result = SCSI_ABORT_SUCCESS; + break; - if (result == SCSI_ABORT_NOT_RUNNING) { - printk ("scsi%d: abort(): command not running\n", host->host->host_no); - acornscsi_dumplog (host, SCpnt->target); + /* + * We did find the command, but unfortunately we couldn't + * unhook it from ourselves. Wait some more, and if it + * still doesn't complete, reset the interface. + */ + case res_snooze: +//#if (DEBUG & DEBUG_ABORT) + printk("snooze\n"); +//#endif + result = SCSI_ABORT_SNOOZE; + break; + + /* + * The command could not be found (either because it completed, + * or it got dropped. + */ + default: + case res_not_running: + acornscsi_dumplog(host, SCpnt->target); #if (DEBUG & DEBUG_ABORT) - result = SCSI_ABORT_SNOOZE; + result = SCSI_ABORT_SNOOZE; +#else + result = SCSI_ABORT_NOT_RUNNING; #endif - } - return result; +//#if (DEBUG & DEBUG_ABORT) + printk("not running\n"); +//#endif + break; + } + + return result; } /* - * Prototype: int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) * Purpose : reset a command on this host/reset this host * Params : SCpnt - command causing reset * result - what type of reset to perform * Returns : one of SCSI_RESET_ macros */ -int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) { AS_Host *host = (AS_Host *)SCpnt->host->hostdata; Scsi_Cmnd *SCptr; @@ -2566,16 +2812,16 @@ { int asr, ssr; - asr = sbic_arm_read (host->scsi.io_port, ASR); - ssr = sbic_arm_read (host->scsi.io_port, SSR); + asr = sbic_arm_read(host->scsi.io_port, ASR); + ssr = sbic_arm_read(host->scsi.io_port, SSR); - printk (KERN_WARNING "acornscsi_reset: "); + printk(KERN_WARNING "acornscsi_reset: "); print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog (host, SCpnt->target); + acornscsi_dumplog(host, SCpnt->target); } #endif - acornscsi_dma_stop (host); + acornscsi_dma_stop(host); SCptr = host->SCpnt; @@ -2583,19 +2829,19 @@ * do hard reset. This resets all devices on this host, and so we * must set the reset status on all commands. */ - acornscsi_resetcard (host); + acornscsi_resetcard(host); /* * report reset on commands current connected/disconnected */ - acornscsi_reportstatus (&host->SCpnt, &SCptr, DID_RESET); + acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET); - while ((SCptr = queue_remove (&host->queues.disconnected)) != NULL) - acornscsi_reportstatus (&SCptr, &SCpnt, DID_RESET); + while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL) + acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET); if (SCpnt) { SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done (SCpnt); + SCpnt->scsi_done(SCpnt); } return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS; @@ -2607,19 +2853,19 @@ static struct expansion_card *ecs[MAX_ECARDS]; /* - * Prototype: void acornscsi_init (AS_Host *host) + * Prototype: void acornscsi_init(AS_Host *host) * Purpose : initialise the AS_Host structure for one interface & setup hardware * Params : host - host to setup */ static -void acornscsi_init (AS_Host *host) +void acornscsi_init(AS_Host *host) { - memset (&host->stats, 0, sizeof (host->stats)); - queue_initialise (&host->queues.issue); - queue_initialise (&host->queues.disconnected); - msgqueue_initialise (&host->scsi.msgs); + memset(&host->stats, 0, sizeof (host->stats)); + queue_initialise(&host->queues.issue); + queue_initialise(&host->queues.disconnected); + msgqueue_initialise(&host->scsi.msgs); - acornscsi_resetcard (host); + acornscsi_resetcard(host); } int acornscsi_detect(Scsi_Host_Template * tpnt) @@ -2634,7 +2880,7 @@ for (i = 0; i < MAX_ECARDS; i++) ecs[i] = NULL; - ecard_startfind (); + ecard_startfind(); while(1) { ecs[count] = ecard_find(0, acornscsi_cids); @@ -2642,37 +2888,37 @@ break; if (ecs[count]->irq == 0xff) { - printk ("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); + printk("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); continue; } ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */ - instance = scsi_register (tpnt, sizeof(AS_Host)); + instance = scsi_register(tpnt, sizeof(AS_Host)); host = (AS_Host *)instance->hostdata; - instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0); + instance->io_port = ecard_address(ecs[count], ECARD_MEMC, 0); instance->irq = ecs[count]->irq; host->host = instance; - host->scsi.io_port = ioaddr (instance->io_port + 0x800); + host->scsi.io_port = ioaddr(instance->io_port + 0x800); host->scsi.irq = instance->irq; host->card.io_intr = POD_SPACE(instance->io_port) + 0x800; host->card.io_page = POD_SPACE(instance->io_port) + 0xc00; - host->card.io_ram = ioaddr (instance->io_port); + host->card.io_ram = ioaddr(instance->io_port); host->dma.io_port = instance->io_port + 0xc00; host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800; ecs[count]->irqaddr = (char *)ioaddr(host->card.io_intr); ecs[count]->irqmask = 0x0a; - request_region (instance->io_port + 0x800, 2, "acornscsi(sbic)"); - request_region (host->card.io_intr, 1, "acornscsi(intr)"); - request_region (host->card.io_page, 1, "acornscsi(page)"); + request_region(instance->io_port + 0x800, 2, "acornscsi(sbic)"); + request_region(host->card.io_intr, 1, "acornscsi(intr)"); + request_region(host->card.io_page, 1, "acornscsi(page)"); #ifdef USE_DMAC - request_region (host->dma.io_port, 256, "acornscsi(dmac)"); + request_region(host->dma.io_port, 256, "acornscsi(dmac)"); #endif - request_region (instance->io_port, 2048, "acornscsi(ram)"); + request_region(instance->io_port, 2048, "acornscsi(ram)"); if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) { printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n", @@ -2680,7 +2926,7 @@ host->scsi.irq = NO_IRQ; } - acornscsi_init (host); + acornscsi_init(host); ++count; } @@ -2688,12 +2934,12 @@ } /* - * Function: int acornscsi_release (struct Scsi_Host *host) + * Function: int acornscsi_release(struct Scsi_Host *host) * Purpose : release all resources used by this adapter * Params : host - driver structure to release * Returns : nothing of any consequence */ -int acornscsi_release (struct Scsi_Host *instance) +int acornscsi_release(struct Scsi_Host *instance) { AS_Host *host = (AS_Host *)instance->hostdata; int i; @@ -2701,30 +2947,30 @@ /* * Put card into RESET state */ - outb (0x80, host->card.io_page); + outb(0x80, host->card.io_page); if (host->scsi.irq != NO_IRQ) - free_irq (host->scsi.irq, host); + free_irq(host->scsi.irq, host); - release_region (instance->io_port + 0x800, 2); - release_region (host->card.io_intr, 1); - release_region (host->card.io_page, 1); - release_region (host->dma.io_port, 256); - release_region (instance->io_port, 2048); + release_region(instance->io_port + 0x800, 2); + release_region(host->card.io_intr, 1); + release_region(host->card.io_page, 1); + release_region(host->dma.io_port, 256); + release_region(instance->io_port, 2048); for (i = 0; i < MAX_ECARDS; i++) - if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0)) - ecard_release (ecs[i]); + if (ecs[i] && instance->io_port == ecard_address(ecs[i], ECARD_MEMC, 0)) + ecard_release(ecs[i]); - msgqueue_free (&host->scsi.msgs); - queue_free (&host->queues.disconnected); - queue_free (&host->queues.issue); + msgqueue_free(&host->scsi.msgs); + queue_free(&host->queues.disconnected); + queue_free(&host->queues.issue); return 0; } /* - * Function: char *acornscsi_info (struct Scsi_Host *host) + * Function: char *acornscsi_info(struct Scsi_Host *host) * Purpose : return a string describing this interface * Params : host - host to give information on * Returns : a constant string @@ -2736,7 +2982,7 @@ p = string; - p += sprintf (string, "%s at port %lX irq %d v%d.%d.%d" + p += sprintf(string, "%s at port %lX irq %d v%d.%d.%d" #ifdef CONFIG_SCSI_ACORNSCSI_SYNC " SYNC" #endif @@ -2772,7 +3018,7 @@ host = (AS_Host *)instance->hostdata; - p += sprintf (p, "AcornSCSI driver v%d.%d.%d" + p += sprintf(p, "AcornSCSI driver v%d.%d.%d" #ifdef CONFIG_SCSI_ACORNSCSI_SYNC " SYNC" #endif @@ -2787,14 +3033,14 @@ #endif "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH); - p += sprintf (p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", + p += sprintf(p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", host->scsi.io_port, host->scsi.irq); #ifdef USE_DMAC - p += sprintf (p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", + p += sprintf(p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", host->dma.io_port, host->scsi.irq); #endif - p += sprintf (p, "Statistics:\n" + p += sprintf(p, "Statistics:\n" "Queued commands: %-10u Issued commands: %-10u\n" "Done commands : %-10u Reads : %-10u\n" "Writes : %-10u Others : %-10u\n" @@ -2809,47 +3055,47 @@ for (devidx = 0; devidx < 9; devidx ++) { unsigned int statptr, prev; - p += sprintf (p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); - statptr = status_ptr[devidx] - 10; + p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); + statptr = host->status_ptr[devidx] - 10; if ((signed int)statptr < 0) - statptr += 16; + statptr += STATUS_BUFFER_SIZE; - prev = status[devidx][statptr].when; + prev = host->status[devidx][statptr].when; - for (; statptr != status_ptr[devidx]; statptr = (statptr + 1) & 15) { - if (status[devidx][statptr].when) { - p += sprintf (p, "%c%02X:%02X+%2ld", - status[devidx][statptr].irq ? '-' : ' ', - status[devidx][statptr].ph, - status[devidx][statptr].ssr, - (status[devidx][statptr].when - prev) < 100 ? - (status[devidx][statptr].when - prev) : 99); - prev = status[devidx][statptr].when; + for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) { + if (host->status[devidx][statptr].when) { + p += sprintf(p, "%c%02X:%02X+%2ld", + host->status[devidx][statptr].irq ? '-' : ' ', + host->status[devidx][statptr].ph, + host->status[devidx][statptr].ssr, + (host->status[devidx][statptr].when - prev) < 100 ? + (host->status[devidx][statptr].when - prev) : 99); + prev = host->status[devidx][statptr].when; } } } - p += sprintf (p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); + p += sprintf(p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); for (scd = instance->host_queue; scd; scd = scd->next) { int len; - proc_print_scsidevice (scd, p, &len, 0); + proc_print_scsidevice(scd, p, &len, 0); p += len; - p += sprintf (p, "Extensions: "); + p += sprintf(p, "Extensions: "); if (scd->tagged_supported) - p += sprintf (p, "TAG %sabled [%d] ", + p += sprintf(p, "TAG %sabled [%d] ", scd->tagged_queue ? "en" : "dis", scd->current_tag); - p += sprintf (p, "\nTransfers: "); + p += sprintf(p, "\nTransfers: "); if (host->device[scd->id].sync_xfer & 15) - p += sprintf (p, "sync, offset %d, %d ns\n", + p += sprintf(p, "sync, offset %d, %d ns\n", host->device[scd->id].sync_xfer & 15, - acornscsi_getperiod (host->device[scd->id].sync_xfer)); + acornscsi_getperiod(host->device[scd->id].sync_xfer)); else - p += sprintf (p, "async\n"); + p += sprintf(p, "async\n"); pos = p - buffer; if (pos + begin < offset) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/acornscsi.h linux/drivers/acorn/scsi/acornscsi.h --- v2.2.17/drivers/acorn/scsi/acornscsi.h Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/acornscsi.h Fri Sep 15 23:31:12 2000 @@ -291,6 +291,27 @@ #include "queue.h" #include "msgqueue.h" +#define STATUS_BUFFER_SIZE 32 +/* + * This is used to dump the previous states of the SBIC + */ +struct status_entry { + unsigned long when; + unsigned char ssr; + unsigned char ph; + unsigned char irq; + unsigned char unused; +}; + +#define ADD_STATUS(_q,_ssr,_ph,_irq) \ +({ \ + host->status[(_q)][host->status_ptr[(_q)]].when = jiffies; \ + host->status[(_q)][host->status_ptr[(_q)]].ssr = (_ssr); \ + host->status[(_q)][host->status_ptr[(_q)]].ph = (_ph); \ + host->status[(_q)][host->status_ptr[(_q)]].irq = (_irq); \ + host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \ +}) + /* * AcornSCSI host specific data */ @@ -303,7 +324,7 @@ /* driver information */ struct { unsigned int io_port; /* base address of WD33C93 */ - unsigned char irq; /* interrupt */ + unsigned int irq; /* interrupt */ phase_t phase; /* current phase */ struct { @@ -361,6 +382,7 @@ char *xfer_ptr; /* pointer to area */ unsigned char xfer_required:1; /* set if we need to transfer something */ unsigned char xfer_setup:1; /* set if DMA is setup */ + unsigned char xfer_done:1; /* set if DMA reached end of BH list */ } dma; /* card info */ @@ -370,6 +392,9 @@ unsigned int io_ram; /* base address of RAM access */ unsigned char page_reg; /* current setting of page reg */ } card; + + unsigned char status_ptr[9]; + struct status_entry status[9][STATUS_BUFFER_SIZE]; } AS_Host; #endif /* ndef HOSTS_C */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/arxescsi.c linux/drivers/acorn/scsi/arxescsi.c --- v2.2.17/drivers/acorn/scsi/arxescsi.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/acorn/scsi/arxescsi.c Fri Sep 15 23:31:12 2000 @@ -0,0 +1,395 @@ +/* + * linux/arch/arm/drivers/scsi/cumana_2.c + * + * Copyright (C) 1997,1998 Russell King + * + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 30-08-1997 RMK 0.0.0 Created, READONLY version as cumana_2.c + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. + * 11-06-1998 0.0.2 Changed to support ARXE 16-bit SCSI card, enabled writing + * by Stefan Hanske + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../../scsi/sd.h" +#include "../../scsi/hosts.h" +#include "arxescsi.h" +#include "fas216.h" + +/* Hmm - this should go somewhere else */ +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) + +/* Configuration */ +#define ARXESCSI_XTALFREQ 24 +#define ARXESCSI_ASYNC_PERIOD 200 +#define ARXESCSI_SYNC_DEPTH 0 + +/* + * List of devices that the driver will recognise + */ +#define ARXESCSI_LIST { MANU_ARXE, PROD_ARXE_SCSI } + +/* + * Version + */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 2 + +static struct expansion_card *ecs[MAX_ECARDS]; + +static struct proc_dir_entry proc_scsi_arxescsi = { + PROC_SCSI_QLOGICFAS, 6, "arxescsi", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +/* + * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type) + * Purpose : initialises DMA/PIO + * Params : host - host + * SCpnt - command + * direction - DMA on to/off of card + * min_type - minimum DMA support that we must have for this transfer + * Returns : 0 if we should not set CMD_WITHDMA for transfer info command + */ +static fasdmatype_t +arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t direction, fasdmatype_t min_type) +{ + /* + * We don't do real DMA + */ + return fasdma_pseudo; +} + + + +/* Faster transfer routines, written by SH to speed up the loops */ + +static __inline__ unsigned char getb(unsigned int address, unsigned int reg) +{ + unsigned char value; + + __asm__ __volatile__( + "ldrb %0, [%1, %2, lsl #5]" + : "=r" (value) + : "r" (address), "r" (reg) ); + return value; +} + +static __inline__ unsigned int getw(unsigned int address, unsigned int reg) +{ + unsigned int value; + + __asm__ __volatile__( + "ldr %0, [%1, %2, lsl #5]\n\t" + "mov %0, %0, lsl #16\n\t" + "mov %0, %0, lsr #16" + : "=r" (value) + : "r" (address), "r" (reg) ); + return value; +} + +static __inline__ void putw(unsigned int address, unsigned int reg, unsigned long value) +{ + __asm__ __volatile__( + "mov %0, %0, lsl #16\n\t" + "str %0, [%1, %2, lsl #5]" + : + : "r" (value), "r" (address), "r" (reg) ); +} + + +/* + * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer) + * Purpose : handles pseudo DMA + * Params : host - host + * SCpnt - command + * direction - DMA on to/off of card + * transfer - minimum number of bytes we expect to transfer + */ +void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t direction, int transfer) +{ + ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata; + unsigned int length, io, error=0; + unsigned char *addr; + + length = SCp->this_residual; + addr = SCp->ptr; + io = __ioaddr(host->io_port); + + if (direction == DMA_OUT) { + while (length > 0) { + unsigned long word; + + + word = *addr | *(addr + 1) << 8; + if (getb(io, 4) & STAT_INT) + break; + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + putw(io, 16, word); + if (length > 1) { + addr += 2; + length -= 2; + } else { + addr += 1; + length -= 1; + } + } + } + else { + if (transfer && (transfer & 255)) { + while (length >= 256) { + if (getb(io, 4) & STAT_INT) { + error=1; + break; + } + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + insw(info->dmaarea, addr, 256 >> 1); + addr += 256; + length -= 256; + } + } + + if (!(error)) + while (length > 0) { + unsigned long word; + + if (getb(io, 4) & STAT_INT) + break; + + if (!(getb(io, 48) & CSTATUS_IRQ)) + continue; + + word = getw(io, 16); + *addr++ = word; + if (--length > 0) { + *addr++ = word >> 8; + length --; + } + } + } +} + +/* + * Function: int arxescsi_dma_stop(host, SCpnt) + * Purpose : stops DMA/PIO + * Params : host - host + * SCpnt - command + */ +static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) +{ + /* + * no DMA to stop + */ +} + +/* + * Function: int arxescsi_detect(Scsi_Host_Template * tpnt) + * Purpose : initialises ARXE SCSI driver + * Params : tpnt - template for this SCSI adapter + * Returns : >0 if host found, 0 otherwise. + */ +int arxescsi_detect(Scsi_Host_Template *tpnt) +{ + static const card_ids arxescsi_cids[] = { ARXESCSI_LIST, { 0xffff, 0xffff} }; + int count = 0; + struct Scsi_Host *host; + + tpnt->proc_dir = &proc_scsi_arxescsi; + memset(ecs, 0, sizeof (ecs)); + + ecard_startfind(); + + while (1) { + ARXEScsi_Info *info; + + ecs[count] = ecard_find(0, arxescsi_cids); + if (!ecs[count]) + break; + + ecard_claim(ecs[count]); + + host = scsi_register(tpnt, sizeof (ARXEScsi_Info)); + if (!host) { + ecard_release(ecs[count]); + break; + } + + host->io_port = ecard_address(ecs[count], ECARD_MEMC, 0) + 0x0800; + host->irq = NO_IRQ; + host->dma_channel = NO_DMA; + host->can_queue = 0; /* no command queueing */ + info = (ARXEScsi_Info *)host->hostdata; + + info->info.scsi.io_port = host->io_port; + info->info.scsi.irq = host->irq; + info->info.scsi.io_shift = 3; + info->info.ifcfg.clockrate = ARXESCSI_XTALFREQ; + info->info.ifcfg.select_timeout = 255; + info->info.ifcfg.asyncperiod = ARXESCSI_ASYNC_PERIOD; + info->info.ifcfg.sync_max_depth = ARXESCSI_SYNC_DEPTH; + info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->info.ifcfg.disconnect_ok = 0; + info->info.ifcfg.wide_max_size = 0; + info->info.dma.setup = arxescsi_dma_setup; + info->info.dma.pseudo = arxescsi_dma_pseudo; + info->info.dma.stop = arxescsi_dma_stop; + info->dmaarea = host->io_port + 128; + info->cstatus = host->io_port + 384; + + ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(host->io_port); + ecs[count]->irqmask = CSTATUS_IRQ; + + request_region(host->io_port , 120, "arxescsi-fas"); + request_region(host->io_port + 128, 384, "arxescsi-dma"); + + printk("scsi%d: Has no interrupts - using polling mode\n", + host->host_no); + + fas216_init(host); + ++count; + } + return count; +} + +/* + * Function: int arxescsi_release(struct Scsi_Host * host) + * Purpose : releases all resources used by this adapter + * Params : host - driver host structure to return info for. + * Returns : nothing + */ +int arxescsi_release(struct Scsi_Host *host) +{ + int i; + + fas216_release(host); + + release_region(host->io_port, 120); + release_region(host->io_port + 128, 384); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && host->io_port == (ecard_address(ecs[i], ECARD_MEMC, 0) + 0x0800)) + ecard_release(ecs[i]); + return 0; +} + +/* + * Function: const char *arxescsi_info(struct Scsi_Host * host) + * Purpose : returns a descriptive string about this interface, + * Params : host - driver host structure to return info for. + * Returns : pointer to a static buffer containing null terminated string. + */ +const char *arxescsi_info(struct Scsi_Host *host) +{ + ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata; + static char string[100], *p; + + p = string; + p += sprintf(string, "%s at port %lX irq %d v%d.%d.%d scsi %s", + host->hostt->name, host->io_port, host->irq, + VER_MAJOR, VER_MINOR, VER_PATCH, + info->info.scsi.type); + + return string; +} + +/* + * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset, + * int length, int host_no, int inout) + * Purpose : Return information about the driver to a user process accessing + * the /proc filesystem. + * Params : buffer - a buffer to write information to + * start - a pointer into this buffer set by this routine to the start + * of the required information. + * offset - offset into information that we have read upto. + * length - length of buffer + * host_no - host number to return information for + * inout - 0 for reading, 1 for writing. + * Returns : length of data written to buffer. + */ +int arxescsi_proc_info(char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin; + struct Scsi_Host *host = scsi_hostlist; + ARXEScsi_Info *info; + Scsi_Device *scd; + + while (host) { + if (host->host_no == host_no) + break; + host = host->next; + } + if (!host) + return 0; + + info = (ARXEScsi_Info *)host->hostdata; + if (inout == 1) + return -EINVAL; + + begin = 0; + pos = sprintf(buffer, + "ARXE 16-bit SCSI driver version %d.%d.%d\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + pos += sprintf(buffer + pos, + "Address: %08lX IRQ : %d\n" + "FAS : %s\n\n" + "Statistics:\n", + host->io_port, host->irq, info->info.scsi.type); + + pos += fas216_print_stats(&info->info, buffer + pos); + + pos += sprintf (buffer+pos, "\nAttached devices:\n"); + + for (scd = host->host_queue; scd; scd = scd->next) { + pos += fas216_print_device(&info->info, scd, buffer + pos); + + if (pos + begin < offset) { + begin += pos; + pos = 0; + } + if (pos + begin > offset + length) + break; + } + + *start = buffer + (offset - begin); + pos -= offset - begin; + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = ARXEScsi; + +#include "../../scsi/scsi_module.c" +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/arxescsi.h linux/drivers/acorn/scsi/arxescsi.h --- v2.2.17/drivers/acorn/scsi/arxescsi.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/acorn/scsi/arxescsi.h Fri Sep 15 23:31:12 2000 @@ -0,0 +1,80 @@ +/* + * ARXE SCSI card driver + * + * Copyright (C) 1997 Russell King + * Changes to support ARXE 16-bit SCSI card by Stefan Hanske + */ +#ifndef ARXE_SCSI_H +#define ARXE_SCSI_H + +#define MANU_ARXE 0x0041 +#define PROD_ARXE_SCSI 0x00be + +extern int arxescsi_detect (Scsi_Host_Template *); +extern int arxescsi_release (struct Scsi_Host *); +extern const char *arxescsi_info (struct Scsi_Host *); +extern int arxescsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef CAN_QUEUE +/* + * Default queue size + */ +#define CAN_QUEUE 1 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 1 +#endif + +#ifndef SCSI_ID +/* + * Default SCSI host ID + */ +#define SCSI_ID 7 +#endif + +#include + +#ifndef HOSTS_C +#include "fas216.h" +#endif + +#define ARXEScsi { \ +proc_info: arxescsi_proc_info, \ +name: "ARXE SCSI card", \ +detect: arxescsi_detect, /* detect */ \ +release: arxescsi_release, /* release */ \ +info: arxescsi_info, /* info */ \ +command: fas216_command, /* command */ \ +queuecommand: fas216_queue_command, /* queuecommand */ \ +abort: fas216_abort, /* abort */ \ +reset: fas216_reset, /* reset */ \ +bios_param: scsicam_bios_param, /* biosparam */ \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: SCSI_ID, /* scsi host id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +typedef struct { + FAS216_Info info; + + /* other info... */ + unsigned int cstatus; /* card status register */ + unsigned int dmaarea; /* Pseudo DMA area */ +} ARXEScsi_Info; + +#define CSTATUS_IRQ (1 << 0) +#define CSTATUS_DRQ (1 << 0) + +#endif /* HOSTS_C */ + +#endif /* ARXE_SCSI_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c --- v2.2.17/drivers/acorn/scsi/cumana_2.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/cumana_2.c Fri Sep 15 23:31:12 2000 @@ -4,12 +4,12 @@ * Copyright (C) 1997-1998 Russell King * * Changelog: - * 30-08-1997 RMK 0.0.0 Created, READONLY version - * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + * 30-08-1997 RMK 0.0.0 Created, READONLY version. + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. - * 02-05-1998 RMK 0.0.2 Updated & added DMA support + * 02-05-1998 RMK 0.0.2 Updated & added DMA support. * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth + * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth. */ #include @@ -117,6 +117,8 @@ cumanascsi_2_irqenable, cumanascsi_2_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -364,6 +366,7 @@ info->info.ifcfg.sync_max_depth = CUMANASCSI2_SYNC_DEPTH; 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 = cumanascsi_2_dma_setup; info->info.dma.pseudo = cumanascsi_2_dma_pseudo; info->info.dma.stop = cumanascsi_2_dma_stop; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c --- v2.2.17/drivers/acorn/scsi/eesox.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/eesox.c Fri Sep 15 23:31:12 2000 @@ -38,9 +38,6 @@ #include "../../scsi/hosts.h" #include "eesox.h" -#define NO_IRQ 255 -#define NO_DMA 255 - /* Configuration */ #define EESOX_XTALFREQ 40 #define EESOX_ASYNC_PERIOD 200 @@ -123,6 +120,8 @@ eesoxscsi_irqenable, eesoxscsi_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -379,6 +378,7 @@ info->info.ifcfg.sync_max_depth = EESOX_SYNC_DEPTH; 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 = eesoxscsi_dma_setup; info->info.dma.pseudo = eesoxscsi_dma_pseudo; info->info.dma.stop = eesoxscsi_dma_stop; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c --- v2.2.17/drivers/acorn/scsi/fas216.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/fas216.c Fri Sep 15 23:31:12 2000 @@ -24,9 +24,10 @@ * 02-05-1998 RMK Added extra checks in fas216_reset * 24-05-1998 RMK Fixed synchronous transfers with period >= 200ns * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h + * 26-08-1998 RMK Improved message support wrt MESSAGE_REJECT + * 17-01-2000 RMK Added Command->Message In transition * * Todo: - * - tighten up the MESSAGE_REJECT support. * - allow individual devices to enable sync xfers. */ @@ -57,7 +58,7 @@ #define VER_MAJOR 0 #define VER_MINOR 0 -#define VER_PATCH 4 +#define VER_PATCH 6 #define SCSI2_TAG @@ -86,6 +87,8 @@ */ #define SCSI2_SYNC +#define SCSI2_WIDE + #undef DEBUG_CONNECT #undef DEBUG_BUSSERVICE #undef DEBUG_FUNCTIONDONE @@ -98,11 +101,16 @@ static void fas216_dumpstate(FAS216_Info *info) { + unsigned char is, stat, inst; + + is = inb(REG_IS(info)); + stat = inb(REG_STAT(info)); + inst = inb(REG_INST(info)); + printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X" " INST=%02X IS=%02X CFIS=%02X", inb(REG_CTCL(info)), inb(REG_CTCM(info)), - inb(REG_CMD(info)), inb(REG_STAT(info)), - inb(REG_INST(info)), inb(REG_IS(info)), + inb(REG_CMD(info)), stat, inst, is, inb(REG_CFIS(info))); printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n", inb(REG_CNTL1(info)), inb(REG_CNTL2(info)), @@ -117,43 +125,27 @@ if (used++) return; - printk("FAS216_Info=\n"); - printk(" { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n", - info->magic_start, info->host, info->SCpnt, - info->origSCpnt); - printk(" scsi={ io_port=%X io_shift=%X irq=%X cfg={ %X %X %X %X }\n", - info->scsi.io_port, info->scsi.io_shift, info->scsi.irq, - info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2], - info->scsi.cfg[3]); - printk(" type=%p phase=%X reconnected={ target=%d lun=%d tag=%d }\n", - info->scsi.type, info->scsi.phase, - info->scsi.reconnected.target, + printk("FAS216 Info (%s) =\n", info->scsi.type); + printk(" SCpnt=%p origSCpnt=%p\n", info->SCpnt, info->origSCpnt); + printk(" phase=%X reconnected={ target=%d lun=%d tag=%d }\n", + info->scsi.phase, info->scsi.reconnected.target, info->scsi.reconnected.lun, info->scsi.reconnected.tag); - printk(" SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n", + printk(" SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n", info->scsi.SCp.ptr, info->scsi.SCp.this_residual, info->scsi.SCp.buffer, info->scsi.SCp.buffers_residual); - printk(" msgs async_stp=%X last_message=%X disconnectable=%d aborting=%d }\n", - info->scsi.async_stp, info->scsi.last_message, + printk(" async_stp=%X disconnectable=%d aborting=%d\n", + info->scsi.async_stp, info->scsi.disconnectable, info->scsi.aborting); - printk(" stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n" - " disconnects=%X aborts=%X resets=%X }\n", - info->stats.queues, info->stats.removes, info->stats.fins, - info->stats.reads, info->stats.writes, info->stats.miscs, - info->stats.disconnects, info->stats.aborts, info->stats.resets); - printk(" ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n", - info->ifcfg.clockrate, info->ifcfg.select_timeout, - info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth); for (i = 0; i < 8; i++) { - printk(" busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X negstate=%X }\n", - i, info->busyluns[i], i, + printk(" dev[%d]={ busy=%d disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n", + i, info->busyluns[i], info->device[i].disconnect_ok, info->device[i].stp, - info->device[i].sof, info->device[i].negstate); + info->device[i].sof, info->device[i].sync_state); } - printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n", + printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n", info->dma.transfer_type, info->dma.setup, info->dma.pseudo, info->dma.stop); - printk(" internal_done=%X magic_end=%lX }\n", - info->internal_done, info->magic_end); + printk(" internal_done=%X\n", info->internal_done); } #ifdef CHECK_STRUCTURE @@ -192,19 +184,19 @@ static const char *fas216_drv_phase(FAS216_Info *info) { switch (info->scsi.phase) { - case PHASE_IDLE: return "idle"; - case PHASE_SELECTION: return "selection"; - case PHASE_MESSAGESENT: return "message sent"; - case PHASE_RECONNECTED: return "reconnected"; - case PHASE_DATAOUT: return "data out"; - case PHASE_DATAIN: return "data in"; - case PHASE_MSGOUT: return "message out"; - case PHASE_MSGIN: return "message in"; - case PHASE_AFTERMSGOUT: return "after message out"; - case PHASE_STATUS: return "status"; - case PHASE_DISCONNECT: return "disconnect"; - case PHASE_DONE: return "done"; - default: return "???"; + case PHASE_IDLE: return "idle"; + case PHASE_SELECTION: return "selection"; + case PHASE_COMMAND: return "command"; + case PHASE_RECONNECTED: return "reconnected"; + case PHASE_DATAOUT: return "data out"; + case PHASE_DATAIN: return "data in"; + case PHASE_MSGIN: return "message in"; + case PHASE_MSGIN_DISCONNECT: return "disconnect"; + case PHASE_MSGOUT_EXPECT: return "expect message out"; + case PHASE_MSGOUT: return "message out"; + case PHASE_STATUS: return "status"; + case PHASE_DONE: return "done"; + default: return "???"; } } @@ -262,6 +254,37 @@ return clock; } +/* Function: unsigned short fas216_get_last_msg(FAS216_Info *info, int pos) + * Purpose : retrieve a last message from the list, using position in fifo + * Params : info - interface to search + * : pos - current fifo position + */ +static inline unsigned short +fas216_get_last_msg(FAS216_Info *info, int pos) +{ + unsigned short packed_msg = NOP; + struct message *msg; + int msgnr = 0; + + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + if (pos >= msg->fifo) + break; + } + + if (msg) { + if (msg->msg[0] == EXTENDED_MESSAGE) + packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8; + else + packed_msg = msg->msg[0]; + } + +#ifdef DEBUG_MESSAGES + printk("Message: %04X found at position %02X\n", + packed_msg, pos); +#endif + return packed_msg; +} + /* Function: int fas216_syncperiod(FAS216_Info *info, int ns) * Purpose : Calculate value to be loaded into the STP register * for a given period in ns @@ -303,6 +326,252 @@ outb(info->scsi.cfg[2], REG_CNTL3(info)); } +typedef enum { + mstat_accept, + mstat_reject, + mstat_unrecognised +} msgin_stat_t; + +/* Synchronous transfer support + * + * Note: The SCSI II r10 spec says (5.6.12): + * + * (2) Due to historical problems with early host adapters that could + * not accept an SDTR message, some targets may not initiate synchronous + * negotiation after a power cycle as required by this standard. Host + * adapters that support synchronous mode may avoid the ensuing failure + * modes when the target is independently power cycled by initiating a + * synchronous negotiation on each REQUEST SENSE and INQUIRY command. + * This approach increases the SCSI bus overhead and is not recommended + * for new implementations. The correct method is to respond to an + * SDTR message with a MESSAGE REJECT message if the either the + * initiator or target devices does not support synchronous transfers + * or does not want to negotiate for synchronous transfers at the time. + * Using the correct method assures compatibility with wide data + * transfers and future enhancements. + * + * We will always initiate a synchronous transfer negociation request on + * every INQUIRY or REQUEST SENSE message, unless the target itself has + * at some point performed a synchronous transfer negociation request, or + * we have synchronous transfers disabled for this device. + */ + +/* Function: void fas216_handlesync(FAS216_Info *info, char *msg) + * Purpose : Handle a synchronous transfer message from the target + * Params : info - state structure for interface + * : msg - message from target + */ +static msgin_stat_t +fas216_handlesync(FAS216_Info *info, char *msg) +{ + struct fas216_device *dev = &info->device[info->SCpnt->target]; + enum { sync, async, none, reject } res = none; + msgin_stat_t mstat; + +#ifdef SCSI2_SYNC + switch (msg[0]) { + case MESSAGE_REJECT: + /* Synchronous transfer request failed. + * Note: SCSI II r10: + * + * SCSI devices that are capable of synchronous + * data transfers shall not respond to an SDTR + * message with a MESSAGE REJECT message. + * + * Hence, if we get this condition, we disable + * negociation for this device. + */ + if (dev->sync_state == neg_inprogress) { + dev->sync_state = neg_invalid; + res = async; + } + break; + + case EXTENDED_MESSAGE: + switch (dev->sync_state) { + /* We don't accept synchronous transfer requests. + * Respond with a MESSAGE_REJECT to prevent a + * synchronous transfer agreement from being reached. + */ + case neg_invalid: + res = reject; + break; + + /* We were not negociating a synchronous transfer, + * but the device sent us a negociation request. + * Honour the request by sending back a SDTR + * message containing our capability, limited by + * the targets capability. + */ + default: + outb(CMD_SETATN, REG_CMD(info)); + if (msg[4] > info->ifcfg.sync_max_depth) + msg[4] = info->ifcfg.sync_max_depth; + if (msg[3] < 1000 / info->ifcfg.clockrate) + msg[3] = 1000 / info->ifcfg.clockrate; + + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 5, + EXTENDED_MESSAGE, 3, EXTENDED_SDTR, + msg[3], msg[4]); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + + /* This is wrong. The agreement is not in effect + * until this message is accepted by the device + */ + dev->sync_state = neg_targcomplete; + res = sync; + break; + + /* We initiated the synchronous transfer negociation, + * and have successfully received a response from the + * target. The synchronous transfer agreement has been + * reached. Note: if the values returned are out of our + * bounds, we must reject the message. + */ + case neg_inprogress: + res = reject; + if (msg[4] <= info->ifcfg.sync_max_depth && + msg[3] >= 1000 / info->ifcfg.clockrate) { + dev->sync_state = neg_complete; + res = sync; + } + break; + } + } +#else + res = reject; +#endif + + mstat = mstat_accept; + + switch (res) { + case sync: + dev->period = msg[3]; + dev->sof = msg[4]; + dev->stp = fas216_syncperiod(info, msg[3] * 4); + fas216_set_sync(info, info->SCpnt->target); + break; + + case reject: + mstat = mstat_reject; + + case async: + dev->period = info->ifcfg.asyncperiod / 4; + dev->sof = 0; + dev->stp = info->scsi.async_stp; + fas216_set_sync(info, info->SCpnt->target); + break; + + case none: + mstat = mstat_unrecognised; + break; + } + + return mstat; +} + +/* Function: void fas216_handlewide(FAS216_Info *info, char *msg) + * Purpose : Handle a wide transfer message from the target + * Params : info - state structure for interface + * : msg - message from target + */ +static msgin_stat_t +fas216_handlewide(FAS216_Info *info, char *msg) +{ + struct fas216_device *dev = &info->device[info->SCpnt->target]; + enum { wide, bit8, none, reject } res = none; + msgin_stat_t mstat; + +#ifdef SCSI2_WIDE + switch (msg[0]) { + case MESSAGE_REJECT: + /* Wide transfer request failed. + * Note: SCSI II r10: + * + * SCSI devices that are capable of wide + * data transfers shall not respond to a + * WDTR message with a MESSAGE REJECT message. + * + * Hence, if we get this condition, we never + * reattempt negociation for this device. + */ + if (dev->wide_state == neg_inprogress) { + dev->wide_state = neg_invalid; + res = bit8; + } + break; + + case EXTENDED_MESSAGE: + switch (dev->wide_state) { + /* We don't accept wide data transfer requests. + * Respond with a MESSAGE REJECT to prevent a + * wide data transfer agreement from being reached. + */ + case neg_invalid: + res = reject; + break; + + /* We were not negociating a wide data transfer, + * but the device sent is a negociation request. + * Honour the request by sending back a WDTR + * message containing our capability, limited by + * the targets capability. + */ + default: + outb(CMD_SETATN, REG_CMD(info)); + if (msg[3] > info->ifcfg.wide_max_size) + msg[3] = info->ifcfg.wide_max_size; + + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 4, + EXTENDED_MESSAGE, 2, EXTENDED_WDTR, + msg[3]); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + res = wide; + break; + + /* We initiated the wide data transfer negociation, + * and have successfully received a response from the + * target. The synchronous transfer agreement has been + * reached. Note: if the values returned are out of our + * bounds, we must reject the message. + */ + case neg_inprogress: + res = reject; + if (msg[3] <= info->ifcfg.wide_max_size) { + dev->wide_state = neg_complete; + res = wide; + } + break; + } + } +#else + res = reject; +#endif + + mstat = mstat_accept; + + switch (res) { + case wide: + dev->wide_xfer = msg[3]; + break; + + case reject: + mstat = mstat_reject; + + case bit8: + dev->wide_xfer = 0; + break; + + case none: + mstat = mstat_unrecognised; + break; + } + + return mstat; +} + /* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * Purpose : update data pointers after transfer suspended/paused * Params : info - interface's local pointer to update @@ -338,6 +607,9 @@ residual -= bytes_transferred; ptr += bytes_transferred; + if (residual == 0) + ptr = NULL; + info->scsi.SCp.ptr = ptr; info->scsi.SCp.this_residual = residual; } @@ -353,35 +625,18 @@ { unsigned int residual; char *ptr; - int correction; fas216_checkmagic(info, "fas216_pio"); residual = info->scsi.SCp.this_residual; ptr = info->scsi.SCp.ptr; - if (direction == DMA_OUT) { - while (residual > 0) { - if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) { - outb(*ptr++, REG_FF(info)); - residual -= 1; - } else if (inb(REG_STAT(info)) & STAT_INT) - break; - } - correction = inb(REG_CFIS(info)) & CFIS_CF; - } else { - while (residual > 0) { - if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) { - *ptr++ = inb(REG_FF(info)); - residual -= 1; - } else if (inb(REG_STAT(info)) & STAT_INT) - break; - } - correction = 0; - } + if (direction == DMA_OUT) + outb(*ptr++, REG_FF(info)); + else + *ptr++ = inb(REG_FF(info)); - ptr -= correction; - residual += correction; + residual -= 1; if (residual == 0) { if (info->scsi.SCp.buffers_residual) { @@ -549,10 +804,11 @@ switch (info->scsi.phase) { case PHASE_SELECTION: /* while selecting - no target */ + case PHASE_SELSTEPS: fas216_done(info, DID_NO_CONNECT); break; - case PHASE_DISCONNECT: /* message in - disconnecting */ + case PHASE_MSGIN_DISCONNECT: /* message in - disconnecting */ outb(CMD_ENABLESEL, REG_CMD(info)); info->scsi.disconnectable = 1; info->scsi.reconnected.tag = 0; @@ -564,8 +820,8 @@ fas216_done(info, DID_OK); break; - case PHASE_AFTERMSGOUT: /* message out - possible ABORT message */ - if (info->scsi.last_message == ABORT) { + case PHASE_MSGOUT: /* message out - possible ABORT message */ + if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) { info->scsi.aborting = 0; fas216_done(info, DID_ABORT); break; @@ -592,14 +848,17 @@ fas216_checkmagic(info, "fas216_reselected_intr"); - if (info->scsi.phase == PHASE_SELECTION && info->SCpnt) { + if ((info->scsi.phase == PHASE_SELECTION || + info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) { Scsi_Cmnd *SCpnt = info->SCpnt; info->origSCpnt = SCpnt; info->SCpnt = NULL; - if (info->device[SCpnt->target].negstate == syncneg_sent) - info->device[SCpnt->target].negstate = syncneg_start; + if (info->device[SCpnt->target].wide_state == neg_inprogress) + info->device[SCpnt->target].wide_state = neg_wait; + if (info->device[SCpnt->target].sync_state == neg_inprogress) + info->device[SCpnt->target].sync_state = neg_wait; } #ifdef DEBUG_CONNECT @@ -607,15 +866,14 @@ fas216_target(info), info->scsi.phase); #endif - msgqueue_flush(&info->scsi.msgs); - if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) { printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", info->host->host_no); outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } @@ -636,13 +894,14 @@ if (!ok) { /* - * Something went wrong - abort the command on - * the target. Should this be INITIATOR_ERROR ? + * Something went wrong - send an initiator error to + * the target. */ outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; outb(CMD_MSGACCEPTED, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; return; } @@ -672,17 +931,20 @@ if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg)) ok = 1; + msgqueue_flush(&info->scsi.msgs); if (ok) { info->scsi.phase = PHASE_RECONNECTED; outb(target, REG_SDID(info)); } else { /* - * Our command structure not found - abort the command on the target - * Should this be INITIATOR_ERROR ? + * Our command structure not found - abort the + * command on the target. Since we have no + * record of this command, we can't send + * an INITIATOR DETECTED ERROR message. */ outb(CMD_SETATN, REG_CMD(info)); msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; + info->scsi.phase = PHASE_MSGOUT_EXPECT; } outb(CMD_MSGACCEPTED, REG_CMD(info)); } @@ -733,8 +995,14 @@ } if (!info->SCpnt) { outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT; + msgqueue_flush(&info->scsi.msgs); +#if 0 + if (info->scsi.reconnected.tag) + msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag); + else +#endif + msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT_EXPECT; info->scsi.aborting = 1; } else { /* @@ -751,50 +1019,91 @@ #endif } -/* Function: void fas216_message(FAS216_Info *info) - * Purpose : handle a function done interrupt from FAS216 chip - * Params : info - interface which caused function done interrupt - */ -static void fas216_message(FAS216_Info *info) +static int fas216_wait_cmd(FAS216_Info *info, int cmd) { - unsigned char message[16]; + int tout; + int stat; + + outb(cmd, REG_CMD(info)); + + for (tout = 1000; tout; tout -= 1) { + stat = inb(REG_STAT(info)); + if (stat & STAT_INT) + break; + udelay(1); + } + + return stat; +} + +static int fas216_get_msg_byte(FAS216_Info *info) +{ + int stat; + + stat = fas216_wait_cmd(info, CMD_MSGACCEPTED); + + if ((stat & STAT_INT) == 0) + goto timedout; + + if ((stat & STAT_BUSMASK) != STAT_MESGIN) + goto unexpected_phase_change; + + inb(REG_INST(info)); + + stat = fas216_wait_cmd(info, CMD_TRANSFERINFO); + + if ((stat & STAT_INT) == 0) + goto timedout; + + if ((stat & STAT_BUSMASK) != STAT_MESGIN) + goto unexpected_phase_change; + + inb(REG_INST(info)); + + return inb(REG_FF(info)); + +timedout: + printk("scsi%d.%c: timed out waiting for message byte\n", + info->host->host_no, fas216_target(info)); + return -1; + +unexpected_phase_change: + printk("scsi%d.%c: unexpected phase change: status = %02X\n", + info->host->host_no, fas216_target(info), stat); + + return -2; +} + +static msgin_stat_t fas216___message(FAS216_Info *info) +{ + unsigned char *message = info->scsi.message; unsigned int msglen = 1; + msgin_stat_t mstat = mstat_unrecognised; + signed int msgbyte = 0; fas216_checkmagic(info, "fas216_message"); message[0] = inb(REG_FF(info)); if (message[0] == EXTENDED_MESSAGE) { - int tout; - outb(CMD_MSGACCEPTED, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); + msgbyte = fas216_get_msg_byte(info); - message[1] = inb(REG_FF(info)); + if (msgbyte >= 0) { + message[1] = msgbyte; - for (msglen = 2; msglen < message[1] + 2; msglen++) { - outb(CMD_MSGACCEPTED, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - for (tout = 1000000; tout; tout--) - if (inb(REG_STAT(info)) & STAT_INT) - break; - inb(REG_INST(info)); + for (msglen = 2; msglen < message[1] + 2; msglen++) { + msgbyte = fas216_get_msg_byte(info); - message[msglen] = inb(REG_FF(info)); + if (msgbyte >= 0) + message[msglen] = msgbyte; + else + break; + } } } + info->scsi.msglen = msglen; + #ifdef DEBUG_MESSAGES { int i; @@ -806,6 +1115,19 @@ printk("\n"); } #endif + + /* + * check the length of the message. + * messages 0x00, 0x02-0x1f, 0x80-0xff are one-byte + * messages 0x20-0x30 are two-byte + * check extended messages below... + */ + if ((((message[0] < 0x20 && message[0] != EXTENDED_MESSAGE) || + (message[0] >= 0x80)) && msglen != 1) || + ((message[0] >= 0x20 && message[0] < 0x30) && msglen != 2)) + return mstat_unrecognised; + + if (info->scsi.phase == PHASE_RECONNECTED) { if (message[0] == SIMPLE_QUEUE_TAG) info->scsi.reconnected.tag = message[1]; @@ -815,19 +1137,29 @@ switch (message[0]) { case COMMAND_COMPLETE: - printk("fas216: command complete with no status in MESSAGE_IN?\n"); + printk(KERN_ERR "scsi%d.%c: command complete with no " + "status in MESSAGE_IN?\n", + info->host->host_no, fas216_target(info)); + mstat = mstat_accept; break; case SAVE_POINTERS: /* * Save current data pointer to SAVED data pointer + * SCSI II standard says that we must not acknowledge + * this until we have really saved pointers. + * NOTE: we DO NOT save the command nor status pointers + * as required by the SCSI II standard. These always + * point to the start of their respective areas. */ info->SCpnt->SCp = info->scsi.SCp; + info->SCpnt->SCp.sent_command = 0; #if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) printk("scsi%d.%c: save data pointers: [%p, %X]\n", info->host->host_no, fas216_target(info), info->scsi.SCp.ptr, info->scsi.SCp.this_residual); #endif + mstat = mstat_accept; break; case RESTORE_POINTERS: @@ -840,85 +1172,103 @@ info->host->host_no, fas216_target(info), info->scsi.SCp.ptr, info->scsi.SCp.this_residual); #endif + mstat = mstat_accept; break; case DISCONNECT: - info->scsi.phase = PHASE_DISCONNECT; + info->scsi.phase = PHASE_MSGIN_DISCONNECT; + mstat = mstat_accept; break; case MESSAGE_REJECT: - printk("scsi%d.%c: reject, last message %04X\n", - info->host->host_no, fas216_target(info), - info->scsi.last_message); + mstat = mstat_accept; + switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) { + case EXTENDED_MESSAGE | EXTENDED_SDTR << 8: + mstat = fas216_handlesync(info, message); + break; + + case EXTENDED_MESSAGE | EXTENDED_WDTR << 8: + mstat = fas216_handlewide(info, message); + break; + + default: + printk("scsi%d.%c: reject, last message %04X\n", + info->host->host_no, fas216_target(info), + fas216_get_last_msg(info, info->scsi.msgin_fifo)); + } + break; + + case NOP: + mstat = mstat_accept; break; case SIMPLE_QUEUE_TAG: - /* handled above */ + /* handled above - print a warning since this is untested */ printk("scsi%d.%c: reconnect queue tag %02X\n", info->host->host_no, fas216_target(info), message[1]); + mstat = mstat_accept; break; case EXTENDED_MESSAGE: - switch (message[2]) { - case EXTENDED_SDTR: /* Sync transfer negociation request/reply */ - switch (info->device[info->SCpnt->target].negstate) { - case syncneg_invalid: - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; + if (msglen >= 3) { + switch (message[2]) { + case EXTENDED_SDTR: /* Sync transfer negociation request/reply */ + mstat = fas216_handlesync(info, message); + break; + + case EXTENDED_WDTR: /* Wide transfer negociation request/reply */ + mstat = fas216_handlewide(info, message); break; default: - if (message[4] > info->ifcfg.sync_max_depth) - message[4] = info->ifcfg.sync_max_depth; - if (message[3] < 1000 / info->ifcfg.clockrate) - message[3] = 1000 / info->ifcfg.clockrate; - - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 5, - EXTENDED_MESSAGE, 3, EXTENDED_SDTR, - message[3], message[4]); - info->scsi.phase = PHASE_MSGOUT; - case syncneg_sent: - info->device[info->SCpnt->target].negstate = syncneg_complete; - info->device[info->SCpnt->target].period = message[3]; - info->device[info->SCpnt->target].sof = message[4]; - info->device[info->SCpnt->target].stp = - fas216_syncperiod(info, message[3] * 4); - printk(KERN_NOTICE "scsi%d.%c: using synchronous transfer, offset %d, %d ns\n", - info->host->host_no, fas216_target(info), message[4], message[3] * 4); - fas216_set_sync(info, info->SCpnt->target); break; } - break; - - case EXTENDED_WDTR: /* Wide transfer negociation request/reply */ - /* We don't do wide transfers - reject message */ - default: - printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n", - info->host->host_no, fas216_target(info), - message[2]); - msgqueue_flush(&info->scsi.msgs); - outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; } break; default: - printk("scsi%d.%c: unrecognised message %02X, rejecting\n", - info->host->host_no, fas216_target(info), - message[0]); - msgqueue_flush(&info->scsi.msgs); + break; + } + return mstat; +} + +/* Function: void fas216_message(FAS216_Info *info) + * Purpose : handle a function done interrupt from FAS216 chip + * Params : info - interface which caused function done interrupt + */ +static void fas216_message(FAS216_Info *info) +{ + int i; + + switch (fas216___message(info)) { + case mstat_unrecognised: + printk("scsi%d.%c: unrecognised message, rejecting\n", + info->host->host_no, fas216_target(info)); + printk("scsi%d.%c: message was", info->host->host_no, + fas216_target(info)); + for (i = 0; i < info->scsi.msglen; i++) + printk("%s%02X", i & 31 ? " " : "\n ", + info->scsi.message[i]); + printk("\n"); + + case mstat_reject: + /* + * Something strange seems to be happening here - + * I can't use SETATN since the chip gives me an + * invalid command interrupt when I do. Weird. + */ +outb(CMD_NOP, REG_CMD(info)); +fas216_dumpstate(info); outb(CMD_SETATN, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT; - break; + info->scsi.phase = PHASE_MSGOUT_EXPECT; +fas216_dumpstate(info); + + case mstat_accept: + outb(CMD_MSGACCEPTED, REG_CMD(info)); } - outb(CMD_MSGACCEPTED, REG_CMD(info)); } /* Function: void fas216_send_command(FAS216_Info *info) @@ -935,308 +1285,266 @@ outb(CMD_FLUSHFIFO, REG_CMD(info)); /* load command */ - for (i = 0; i < info->SCpnt->cmd_len; i++) + for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++) outb(info->SCpnt->cmnd[i], REG_FF(info)); outb(CMD_TRANSFERINFO, REG_CMD(info)); + + info->scsi.phase = PHASE_COMMAND; } -/* Function: int fas216_busservice_selection(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in selection phase +/* Function: void fas216_send_messageout(FAS216_Info *info, int start) + * Purpose : handle bus service to send a message * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt + * Note : We do not allow the device to change the data direction! */ -static int fas216_busservice_selection(FAS216_Info *info, unsigned int stat) +static void fas216_send_messageout(FAS216_Info *info, int start) { - fas216_checkmagic(info, "fas216_busservice_selection"); - - switch (stat & STAT_BUSMASK) { - case STAT_DATAOUT: /* data out phase */ - fas216_starttransfer(info, DMA_OUT, 1); - return 1; - - case STAT_DATAIN: /* data in phase */ - fas216_starttransfer(info, DMA_IN, 0); - return 1; + unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs); - case STAT_STATUS: /* status phase */ - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; + fas216_checkmagic(info, "fas216_send_messageout"); - case STAT_MESGIN: /* message in phase */ - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; - - case STAT_MESGOUT:{ /* message out phase */ - char *msg; - int start = 1, msglen; + outb(CMD_FLUSHFIFO, REG_CMD(info)); - /* load message bytes, but don't forget to miss the first - * byte! - */ - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { + if (tot_msglen) { + struct message *msg; + int msgnr = 0; +#ifdef DEBUG_MESSAGES + printk("scsi%d.%c: message out: ", + info->host->host_no, fas216_target(info)); +#endif + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { int i; +#ifdef DEBUG_MESSAGES + printk("{ "); +#endif + for (i = start; i < msg->length; i++) { +#ifdef DEBUG_MESSAGES + printk("%02X ", msg->msg[i]); +#endif + outb(msg->msg[i], REG_FF(info)); + } +#ifdef DEBUG_MESSAGES + printk("} "); +#endif - for (i = start; i < msglen; i++) - outb(msg[i], REG_FF(info)); + msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); start = 0; } - outb(CMD_TRANSFERINFO, REG_CMD(info)); - info->scsi.phase = PHASE_MESSAGESENT; - return 1; - } - default: - return 0; - } -} - -/* Function: int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service after the IDENTIFY message has been sent - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - */ -static int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_messagesent"); - - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: /* message in phase */ - info->scsi.phase = PHASE_MSGIN; - outb(CMD_FLUSHFIFO, REG_CMD(info)); - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; +#ifdef DEBUG_MESSAGES + printk("\n"); +#endif + } else + outb(NOP, REG_FF(info)); - case STAT_COMMAND: /* command phase */ - fas216_send_command(info); - return 1; + outb(CMD_TRANSFERINFO, REG_CMD(info)); - default: - return 0; - } + info->scsi.phase = PHASE_MSGOUT; } -/* Function: int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in a data in/out phase. - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - * Note : We do not allow the device to change the data direction! +/* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) + * Purpose : handle a bus service interrupt from FAS216 chip + * Params : info - interface which caused bus service interrupt + * stat - Status register contents + * ssr - SCSI Status register contents */ -static int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat) +static void +fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) { - fas216_checkmagic(info, "fas216_busservice_dataphase"); + fas216_checkmagic(info, "fas216_busservice_intr"); - switch (stat & STAT_BUSMASK) { - case STAT_DATAIN: /* continue data in phase */ - if (info->scsi.phase == PHASE_DATAIN) { - fas216_starttransfer(info, DMA_IN, 0); - return 1; - } else - return 0; +#ifdef DEBUG_BUSSERVICE + printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n", + info->host->host_no, fas216_target(info), stat, ssr, + info->scsi.phase); +#endif - case STAT_DATAOUT: /* continue data out phase */ - if (info->scsi.phase == PHASE_DATAOUT) { - fas216_starttransfer(info, DMA_OUT, 0); - return 1; - } else - return 0; + switch (info->scsi.phase) { + case PHASE_SELECTION: + if ((ssr & IS_BITS) != 1) + goto bad_is; + break; - case STAT_STATUS: /* status in phase */ - fas216_stoptransfer(info); - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; + case PHASE_SELSTEPS: + switch (ssr & IS_BITS) { + case IS_SELARB: + case IS_MSGBYTESENT: + goto bad_is; + + case IS_NOTCOMMAND: + case IS_EARLYPHASE: + if ((stat & STAT_BUSMASK) == STAT_MESGIN) + break; + goto bad_is; - case STAT_MESGIN: /* message in phase */ - fas216_stoptransfer(info); - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; + case IS_COMPLETE: + break; + } default: - return 0; + break; } -} -/* Function: int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service in after a reconnection - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - * Note : We do not allow the device to change the data direction! - */ -static int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_reconnected"); + outb(CMD_NOP, REG_CMD(info)); - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: - outb(CMD_TRANSFERINFO, REG_CMD(info)); - return 1; + /* + * s2r10 5.1.9.2 para 5 + * If the target accepts the messages sent during a message out + * phase, it will change to a new phase. + */ + if (info->scsi.phase == PHASE_MSGOUT && + (stat & STAT_BUSMASK) != STAT_MESGOUT) + msgqueue_flush(&info->scsi.msgs); - case STAT_STATUS: +#define STATE(st,ph) ((ph) << 3 | (st)) + /* + * This table describes the legal SCSI state transitions, + * as described by the SCSI II spec. + */ + switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) { + /* Reselmsgin -> Data In */ + case STATE(STAT_DATAIN, PHASE_RECONNECTED): fas216_finish_reconnect(info); - info->scsi.phase = PHASE_STATUS; - outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); - return 1; + case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In */ + case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ + case STATE(STAT_DATAIN, PHASE_MSGOUT): /* Message Out -> Data In */ + case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command -> Data In */ + case STATE(STAT_DATAIN, PHASE_MSGIN): /* Message In -> Data In */ + fas216_starttransfer(info, DMA_IN, 0); + return; + + case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */ + fas216_starttransfer(info, DMA_OUT, 0); + return; - case STAT_DATAOUT: /* data out phase */ + /* Reselmsgin -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_RECONNECTED): fas216_finish_reconnect(info); + case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out */ + case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command -> Data Out */ + case STATE(STAT_DATAOUT, PHASE_MSGIN): /* Message In -> Data Out */ fas216_starttransfer(info, DMA_OUT, 1); - return 1; + return; - case STAT_DATAIN: /* data in phase */ + /* Reselmsgin -> Status */ + case STATE(STAT_STATUS, PHASE_RECONNECTED): fas216_finish_reconnect(info); - fas216_starttransfer(info, DMA_IN, 0); - return 1; - - default: - return 0; - } -} - -/* Function: int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat) - * Purpose : handle bus service to send a message - * Params : info - interface which caused bus service - * Returns : 0 if unable to service this interrupt - * Note : We do not allow the device to change the data direction! - */ -static int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat) -{ - fas216_checkmagic(info, "fas216_busservice_messageout"); - - if ((stat & STAT_BUSMASK) != STAT_MESGOUT) { - printk("scsi%d.%c: didn't manage MESSAGE OUT phase\n", - info->host->host_no, fas216_target(info)); - return 0; - } else { - unsigned int msglen = msgqueue_msglength(&info->scsi.msgs); + goto status; + case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out -> Status */ + case STATE(STAT_STATUS, PHASE_DATAIN): /* Data In -> Status */ + fas216_stoptransfer(info); + case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status */ + case STATE(STAT_STATUS, PHASE_MSGOUT): /* Message Out -> Status */ + case STATE(STAT_STATUS, PHASE_COMMAND): /* Command -> Status */ + case STATE(STAT_STATUS, PHASE_MSGIN): /* Message In -> Status */ + status: + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + info->scsi.phase = PHASE_STATUS; + return; + case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */ + case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */ + fas216_stoptransfer(info); + case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command -> Message In */ + case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ + case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; outb(CMD_FLUSHFIFO, REG_CMD(info)); - - if (msglen == 0) - outb(NOP, REG_FF(info)); - else { - char *msg; - - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - int i; - - for (i = 0; i < msglen; i++) - outb(msg[i], REG_FF(info)); - } - } outb(CMD_TRANSFERINFO, REG_CMD(info)); - info->scsi.phase = PHASE_AFTERMSGOUT; - return 1; - } -} - -/* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) - * Purpose : handle a bus service interrupt from FAS216 chip - * Params : info - interface which caused bus service interrupt - * stat - Status register contents - * ssr - SCSI Status register contents - */ -static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) -{ - fas216_checkmagic(info, "fas216_busservice_intr"); - -#ifdef DEBUG_BUSSERVICE - printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n", - info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase); -#endif - switch (ssr & IS_BITS) { - case IS_MSGBYTESENT: /* select with ATN and stop steps completed */ - case IS_COMPLETE: /* last action completed */ - outb(CMD_NOP, REG_CMD(info)); - - switch (info->scsi.phase) { - case PHASE_SELECTION: /* while selecting - selected target */ - if (!fas216_busservice_selection(info, stat)) - printk("scsi%d.%c: bus phase %s after connect?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; - - case PHASE_MESSAGESENT: - if (!fas216_busservice_messagesent(info, stat)) - printk("scsi%d.%c: bus phase %s after message sent?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; - - case PHASE_DATAIN: /* while transfering data in */ - case PHASE_DATAOUT: /* while transfering data out */ - if (!fas216_busservice_dataphase(info, stat)) - printk("scsi%d.%c: bus phase %s after %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat), fas216_drv_phase(info)); - break; - - case PHASE_RECONNECTED: /* newly reconnected device */ - /* - * Command reconnected - if MESGIN, get message - it may be - * the tag. If not, get command out of the disconnected queue - */ - if (!fas216_busservice_reconnected(info, stat)) - printk("scsi%d.%c: bus phase %s after reconnect?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; - - case PHASE_MSGIN: - case PHASE_AFTERMSGOUT: - switch (stat & STAT_BUSMASK) { - case STAT_MESGIN: - info->scsi.phase = PHASE_MSGIN; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - break; + info->scsi.phase = PHASE_MSGIN; + return; - case STAT_COMMAND: /* command phase */ - fas216_send_command(info); - info->scsi.phase = PHASE_SELECTION; - break; + /* Reselmsgin -> Message In */ + case STATE(STAT_MESGIN, PHASE_RECONNECTED): + case STATE(STAT_MESGIN, PHASE_MSGIN): + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + return; - default: - printk("scsi%d.%c: bus phase %s after %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat), - fas216_drv_phase(info)); - } - break; + /* Reselmsgin -> Command */ + case STATE(STAT_COMMAND, PHASE_RECONNECTED): + fas216_finish_reconnect(info); + case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out -> Command */ + case STATE(STAT_COMMAND, PHASE_MSGIN): /* Message In -> Command */ + fas216_send_command(info); + info->scsi.phase = PHASE_COMMAND; + return; + /* Selection -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_SELECTION): + fas216_send_messageout(info, 1); + return; + /* Any -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT): + fas216_send_messageout(info, 0); + return; - case PHASE_MSGOUT: - if (!fas216_busservice_messageout(info, stat)) - printk("scsi%d.%c: bus phase %s instead of message out?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - break; + /* Error recovery rules. + * These either attempt to abort or retry the operation. + * TODO: we need more of these + */ + case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command -> Command */ + /* error - we've sent out all the command bytes + * we have. + * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS + * to include the command bytes sent for this to work + * correctly. + */ + printk(KERN_ERR "scsi%d.%c: " + "target trying to receive more command bytes\n", + info->host->host_no, fas216_target(info)); + outb(CMD_SETATN, REG_CMD(info)); + outb(15, REG_STCL(info)); + outb(0, REG_STCM(info)); + outb(0, REG_STCH(info)); + outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info)); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + return; - case PHASE_DISCONNECT: - printk("scsi%d.%c: disconnect message received, but bus service %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); + /* Selection -> Message Out */ + case STATE(STAT_MESGOUT, PHASE_SELSTEPS): + case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out -> Message Out */ + /* If we get another message out phase, this + * usually means some parity error occurred. + * Resend complete set of messages. If we have + * more than 1 byte to send, we need to assert + * ATN again. + */ + if (msgqueue_msglength(&info->scsi.msgs) > 1) outb(CMD_SETATN, REG_CMD(info)); - msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT; - info->scsi.aborting = 1; - outb(CMD_TRANSFERINFO, REG_CMD(info)); - break; - default: - printk("scsi%d.%c: internal phase %s for bus service?" - " What do I do with this?\n", - info->host->host_no, fas216_target(info), - fas216_drv_phase(info)); - } - break; + fas216_send_messageout(info, 0); + return; + } - default: - printk("scsi%d.%c: bus service at step %d?\n", + if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) { + printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n", info->host->host_no, fas216_target(info), - ssr & IS_BITS); + fas216_bus_phase(stat)); + msgqueue_flush(&info->scsi.msgs); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + info->scsi.aborting = 1; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + return; } + printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n", + info->host->host_no, fas216_target(info), + fas216_bus_phase(stat), + fas216_drv_phase(info)); + print_debug_list(); + return; + +bad_is: + printk("scsi%d.%c: bus service at step %d?\n", + info->host->host_no, fas216_target(info), + ssr & IS_BITS); + print_debug_list(); + + fas216_done(info, DID_ERROR); } /* Function: void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) @@ -1269,6 +1577,7 @@ case PHASE_MSGIN: /* message in phase */ case PHASE_RECONNECTED: /* reconnected command */ if ((stat & STAT_BUSMASK) == STAT_MESGIN) { + info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; fas216_message(info); break; } @@ -1300,10 +1609,11 @@ if (stat & STAT_INT) { if (isr & INST_BUSRESET) - printk("scsi%d.H: fas216: bus reset detected\n", instance->host_no); - else if (isr & INST_ILLEGALCMD) + printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no); + else if (isr & INST_ILLEGALCMD) { printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no); - else if (isr & INST_DISCONNECT) + fas216_dumpstate(info); + } else if (isr & INST_DISCONNECT) fas216_disconnect_intr(info); else if (isr & INST_RESELECTED) /* reselected */ fas216_reselected_intr(info); @@ -1327,7 +1637,7 @@ static void fas216_kick(FAS216_Info *info) { Scsi_Cmnd *SCpnt; - int i, msglen, from_queue = 0; + int tot_msglen, from_queue = 0; fas216_checkmagic(info, "fas216_kick"); @@ -1380,7 +1690,8 @@ if (from_queue) { #ifdef SCSI2_TAG - if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) { + if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE && + SCpnt->cmnd[0] != INQUIRY) { SCpnt->device->current_tag += 1; if (SCpnt->device->current_tag == 0) SCpnt->device->current_tag = 1; @@ -1409,6 +1720,7 @@ /* build outgoing message bytes */ msgqueue_flush(&info->scsi.msgs); + if (info->device[SCpnt->target].disconnect_ok) msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun)); else @@ -1418,15 +1730,29 @@ if (SCpnt->tag) msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag); - /* add synchronous negociation */ - if (SCpnt->cmnd[0] == REQUEST_SENSE && - info->device[SCpnt->target].negstate == syncneg_start) { - info->device[SCpnt->target].negstate = syncneg_sent; +#ifdef SCSI2_WIDE + if (info->device[SCpnt->target].wide_state == neg_wait) { + info->device[SCpnt->target].wide_state = neg_inprogress; + msgqueue_addmsg(&info->scsi.msgs, 4, + EXTENDED_MESSAGE, 2, EXTENDED_WDTR, + info->ifcfg.wide_max_size); + } +#ifdef SCSI2_SYNC + else +#endif +#endif +#ifdef SCSI2_SYNC + if ((info->device[SCpnt->target].sync_state == neg_wait || + info->device[SCpnt->target].sync_state == neg_complete) && + (SCpnt->cmnd[0] == REQUEST_SENSE || + SCpnt->cmnd[0] == INQUIRY)) { + info->device[SCpnt->target].sync_state = neg_inprogress; msgqueue_addmsg(&info->scsi.msgs, 5, EXTENDED_MESSAGE, 3, EXTENDED_SDTR, 1000 / info->ifcfg.clockrate, info->ifcfg.sync_max_depth); } +#endif /* following what the ESP driver says */ outb(0, REG_STCL(info)); @@ -1444,25 +1770,29 @@ /* synchronous transfers */ fas216_set_sync(info, SCpnt->target); - msglen = msgqueue_msglength(&info->scsi.msgs); + tot_msglen = msgqueue_msglength(&info->scsi.msgs); - if (msglen == 1 || msglen == 3) { + if (tot_msglen == 1 || tot_msglen == 3) { /* * We have an easy message length to send... */ - char *msg; + struct message *msg; + int msgnr = 0, i; + + info->scsi.phase = PHASE_SELSTEPS; /* load message bytes */ - while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { - for (i = 0; i < msglen; i++) - outb(msg[i], REG_FF(info)); + while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { + for (i = 0; i < msg->length; i++) + outb(msg->msg[i], REG_FF(info)); + msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); } /* load command */ for (i = 0; i < SCpnt->cmd_len; i++) outb(SCpnt->cmnd[i], REG_FF(info)); - if (msglen == 1) + if (tot_msglen == 1) outb(CMD_SELECTATN, REG_CMD(info)); else outb(CMD_SELECTATN3, REG_CMD(info)); @@ -1471,17 +1801,11 @@ * We have an unusual number of message bytes to send. * Load first byte into fifo, and issue SELECT with ATN and * stop steps. - * Note: we only peek at t his message - we need the rest - * later on! */ - int thismsg; - char *msg = msgqueue_peeknextmsg(&info->scsi.msgs, &thismsg); + struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0); - if (!msg || thismsg < 1) - printk(KERN_CRIT "scsi%d.%c: no message to send, but %d bytes\n", - info->host->host_no, fas216_target(info), msglen); - else - outb(msg[0], REG_FF(info)); + outb(msg->msg[0], REG_FF(info)); + msg->fifo = 1; outb(CMD_SELECTATNSTOP, REG_CMD(info)); } @@ -1525,11 +1849,15 @@ /* * In theory, this should not happen, but just in case it does. */ - if (info->scsi.SCp.ptr && result == DID_OK) { + if (info->scsi.SCp.ptr && + info->scsi.SCp.this_residual && + result == DID_OK) { switch (SCpnt->cmnd[0]) { case INQUIRY: case START_STOP: case READ_CAPACITY: + case TEST_UNIT_READY: + case MODE_SENSE: break; default: @@ -1579,6 +1907,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + unsigned long flags; fas216_checkmagic(info, "fas216_queue_command"); @@ -1618,27 +1947,18 @@ info->stats.queues += 1; SCpnt->tag = 0; - if (info->scsi.irq != NO_IRQ) { - unsigned long flags; - - /* add command into execute queue and let it complete under - * the drivers interrupts. - */ - if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) { - SCpnt->result = DID_ERROR << 16; - done(SCpnt); - } - save_flags_cli(flags); - if (!info->SCpnt || info->scsi.disconnectable) - fas216_kick(info); - restore_flags(flags); - } else { - /* no interrupts to rely on - we'll have to handle the - * command ourselves. For now, we give up. - */ + /* add command into execute queue and let it complete under + * whatever scheme we're using. + */ + if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) { SCpnt->result = DID_ERROR << 16; done(SCpnt); } + save_flags_cli(flags); + if (!info->SCpnt || info->scsi.disconnectable) + fas216_kick(info); + restore_flags(flags); + return 0; } @@ -1672,15 +1992,28 @@ /* * This wastes time, since we can't return until the command is - * complete. We can't seep either since we may get re-entered! + * complete. We can't sleep either since we may get re-entered! * However, we must re-enable interrupts, or else we'll be * waiting forever. */ save_flags(flags); sti(); - while (!info->internal_done) - barrier(); + while (!info->internal_done) { + /* + * If we don't have an IRQ, then we must + * poll the card for it's interrupt, and + * use that to call this driver's interrupt + * routine. That way, we keep the command + * progressing. + */ + if (info->scsi.irq == NO_IRQ) { + sti(); + while (!(inb(REG_STAT(info)) & STAT_INT)); + cli(); + fas216_intr(info->host); + } + } restore_flags(flags); @@ -1688,7 +2021,7 @@ } /* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1, - * Scsi_Cmnd **SCpntp2, int result) + * Scsi_Cmnd **SCpntp2, int result, int no_report) * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 * Params : SCpntp1 - pointer to command to return * SCpntp2 - pointer to command to check @@ -1697,7 +2030,7 @@ * structure as *SCpntp2. */ static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, - int result) + int result, int no_report) { Scsi_Cmnd *SCpnt = *SCpntp1; @@ -1705,7 +2038,8 @@ *SCpntp1 = NULL; SCpnt->result = result; - SCpnt->scsi_done(SCpnt); + if (!no_report || SCpnt != *SCpntp2) + SCpnt->scsi_done(SCpnt); } if (SCpnt == *SCpntp2) @@ -1752,6 +2086,95 @@ return FAILED; } +enum res_abort { res_not_running, res_success, res_success_clear, res_snooze }; + +/* + * Prototype: enum res_abort fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt) + * Purpose : abort a command on this host + * Params : SCpnt - command to abort + * Returns : abort status + */ +static enum res_abort +fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt) +{ + enum res_abort res = res_not_running; + + if (queue_removecmd(&info->queues.issue, SCpnt)) { + /* + * The command was on the issue queue, and has not been + * issued yet. We can remove the command from the queue, + * and acknowledge the abort. Neither the devices nor the + * interface know about the command. + */ + printk("on issue queue "); + + res = res_success; + } else if (queue_removecmd(&info->queues.disconnected, SCpnt)) { + /* + * The command was on the disconnected queue. Simply + * acknowledge the abort condition, and when the target + * reconnects, we will give it an ABORT message. The + * target should then disconnect, and we will clear + * the busylun bit. + */ + printk("on disconnected queue "); + + res = res_success; + } else if (info->SCpnt == SCpnt) { + unsigned long flags; + + printk("executing "); + + save_flags(flags); + cli(); + switch (info->scsi.phase) { + /* + * If the interface is idle, and the command is 'disconnectable', + * then it is the same as on the disconnected queue. We simply + * remove all traces of the command. When the target reconnects, + * we will give it an ABORT message since the command could not + * be found. When the target finally disconnects, we will clear + * the busylun bit. + */ + case PHASE_IDLE: + if (info->scsi.disconnectable) { + info->scsi.disconnectable = 0; + info->SCpnt = NULL; + res = res_success; + } + break; + + /* + * If the command has connected and done nothing futher, + * simply force a disconnect. We also need to clear the + * busylun bit. + */ + case PHASE_SELECTION: +// info->SCpnt = NULL; +// res = res_success_clear; +// break; + + default: + res = res_snooze; + break; + } + restore_flags(flags); + } else if (info->origSCpnt == SCpnt) { + /* + * The command will be executed next, but a command + * is currently using the interface. This is similar to + * being on the issue queue, except the busylun bit has + * been set. + */ + info->origSCpnt = NULL; + printk("waiting for execution "); + res = res_success_clear; + } else + printk("unknown "); + + return res; +} + /* Function: int fas216_abort(Scsi_Cmnd *SCpnt) * Purpose : abort a command if something horrible happens. * Params : SCpnt - Command that is believed to be causing a problem. @@ -1769,46 +2192,51 @@ print_debug_list(); fas216_dumpstate(info); fas216_dumpinfo(info); - printk(KERN_WARNING "scsi%d: fas216_abort: ", info->host->host_no); - do { - /* If command is waiting in the issue queue, then we can - * simply remove the command and return abort status - */ - if (queue_removecmd(&info->queues.issue, SCpnt)) { - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done(SCpnt); - printk("command on issue queue"); - result = SCSI_ABORT_SUCCESS; - break; - } + printk(KERN_WARNING "scsi%d: abort ", info->host->host_no); - /* If the command is on the disconencted queue, we need to - * reconnect to the device - */ - if (queue_cmdonqueue(&info->queues.disconnected, SCpnt)) - printk("command on disconnected queue"); + switch (fas216_do_abort(info, SCpnt)) { + /* + * We managed to find the command and cleared it out. + * We do not expect the command to be executing on the + * target, but we have set the busylun bit. + */ + case res_success_clear: + printk("clear "); + clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns); - /* If the command is connected, we need to flag that the - * command needs to be aborted - */ - if (info->SCpnt == SCpnt) - printk("command executing"); + /* + * We found the command, and cleared it out. Either + * the command is still known to be executing on the + * target, or the busylun bit is not set. + */ + case res_success: + printk("success\n"); + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done(SCpnt); + result = SCSI_ABORT_SUCCESS; + break; - /* If the command is pending for execution, then again - * this is simple - we remove it and report abort status - */ - if (info->origSCpnt == SCpnt) { - info->origSCpnt = NULL; - SCpnt->result = DID_ABORT << 16; - SCpnt->scsi_done(SCpnt); - printk("command waiting for execution"); - result = SCSI_ABORT_SUCCESS; - break; - } - } while (0); + /* + * We did find the command, but unfortunately we couldn't + * unhook it from ourselves. Wait some more, and if it + * still doesn't complete, reset the interface. + */ + case res_snooze: + printk("snooze\n"); + result = SCSI_ABORT_SNOOZE; + break; - printk("\n"); + /* + * The command could not be found (either because it completed, + * or it got dropped. + */ + default: + case res_not_running: + result = SCSI_ABORT_SNOOZE; + printk("not running\n"); + break; + } return result; } @@ -1819,7 +2247,7 @@ */ static void fas216_reset_state(FAS216_Info *info) { - syncneg_t negstate; + neg_t sync_state, wide_state; int i; fas216_checkmagic(info, "fas216_reset_state"); @@ -1833,26 +2261,37 @@ info->scsi.reconnected.lun = 0; info->scsi.reconnected.tag = 0; info->scsi.disconnectable = 0; - info->scsi.last_message = 0; info->scsi.aborting = 0; info->scsi.phase = PHASE_IDLE; - info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod); + info->scsi.async_stp = + fas216_syncperiod(info, info->ifcfg.asyncperiod); + + if (info->ifcfg.wide_max_size == 0) + wide_state = neg_invalid; + else +#ifdef SCSI2_WIDE + wide_state = neg_wait; +#else + wide_state = neg_invalid; +#endif if (info->host->dma_channel == NO_DMA || !info->dma.setup) - negstate = syncneg_invalid; + sync_state = neg_invalid; else #ifdef SCSI2_SYNC - negstate = syncneg_start; + sync_state = neg_wait; #else - negstate = syncneg_invalid; + sync_state = neg_invalid; #endif for (i = 0; i < 8; i++) { - info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; - info->device[i].negstate = negstate; - info->device[i].period = info->ifcfg.asyncperiod / 4; - info->device[i].stp = info->scsi.async_stp; - info->device[i].sof = 0; + info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; + info->device[i].sync_state = sync_state; + info->device[i].wide_state = wide_state; + info->device[i].period = info->ifcfg.asyncperiod / 4; + info->device[i].stp = info->scsi.async_stp; + info->device[i].sof = 0; + info->device[i].wide_xfer = 0; } } @@ -1887,6 +2326,7 @@ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; Scsi_Cmnd *SCptr; int result = 0; + int synchronous = reset_flags & SCSI_RESET_SYNCHRONOUS; fas216_checkmagic(info, "fas216_reset"); @@ -1908,9 +2348,11 @@ info->stats.resets += 1; print_debug_list(); - printk(KERN_WARNING "scsi%d: fas216_reset: ", info->host->host_no); + printk(KERN_WARNING "scsi%d: reset ", info->host->host_no); if (SCpnt) - printk(" for target %d ", SCpnt->target); + printk("for target %d ", SCpnt->target); + + printk("\n"); outb(info->scsi.cfg[3], REG_CNTL3(info)); @@ -1944,10 +2386,10 @@ /* * Signal all commands in progress have been reset */ - fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16); + fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16, synchronous); while ((SCptr = queue_remove(&info->queues.disconnected)) != NULL) - fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16); + fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16, synchronous); if (SCpnt) { /* @@ -1960,11 +2402,10 @@ queue_removecmd(&info->queues.issue, SCpnt); SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done(SCpnt); + if (!synchronous) + SCpnt->scsi_done(SCpnt); } - printk("\n"); - return result | SCSI_RESET_SUCCESS; } @@ -2083,6 +2524,49 @@ return 0; } +int fas216_print_stats(FAS216_Info *info, char *buffer) +{ + return sprintf(buffer, + "Queued commands: %-10u Issued commands: %-10u\n" + "Done commands : %-10u Reads : %-10u\n" + "Writes : %-10u Others : %-10u\n" + "Disconnects : %-10u Aborts : %-10u\n" + "Resets : %-10u\n", + info->stats.queues, info->stats.removes, + info->stats.fins, info->stats.reads, + info->stats.writes, info->stats.miscs, + info->stats.disconnects, info->stats.aborts, + info->stats.resets); +} + +int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer) +{ + struct fas216_device *dev = &info->device[scd->id]; + int len = 0; + char *p; + + proc_print_scsidevice(scd, buffer, &len, 0); + p = buffer + len; + + p += sprintf(p, " Extensions: "); + + if (scd->tagged_supported) + p += sprintf(p, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + + p += sprintf(p, "\n Transfers : %d-bit ", + 8 << dev->wide_xfer); + + if (dev->sof) + p += sprintf(p, "sync offset %d, %d ns\n", + dev->sof, dev->period * 4); + else + p += sprintf(p, "async\n"); + + return p - buffer; +} + EXPORT_SYMBOL(fas216_init); EXPORT_SYMBOL(fas216_abort); EXPORT_SYMBOL(fas216_reset); @@ -2094,7 +2578,8 @@ EXPORT_SYMBOL(fas216_eh_device_reset); EXPORT_SYMBOL(fas216_eh_bus_reset); EXPORT_SYMBOL(fas216_eh_host_reset); - +EXPORT_SYMBOL(fas216_print_stats); +EXPORT_SYMBOL(fas216_print_device); #ifdef MODULE int init_module(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/fas216.h linux/drivers/acorn/scsi/fas216.h --- v2.2.17/drivers/acorn/scsi/fas216.h Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/fas216.h Fri Sep 15 23:31:12 2000 @@ -40,6 +40,7 @@ #define CMD_TRANSFERINFO 0x10 #define CMD_INITCMDCOMPLETE 0x11 #define CMD_MSGACCEPTED 0x12 +#define CMD_PADBYTES 0x18 #define CMD_SETATN 0x1a #define CMD_RSETATN 0x1b @@ -171,15 +172,17 @@ typedef enum { PHASE_IDLE, /* we're not planning on doing anything */ PHASE_SELECTION, /* selecting a device */ + PHASE_SELSTEPS, /* selection with command steps */ + PHASE_COMMAND, /* command sent */ PHASE_MESSAGESENT, /* selected, and we're sending cmd */ PHASE_RECONNECTED, /* reconnected */ PHASE_DATAOUT, /* data out to device */ PHASE_DATAIN, /* data in from device */ PHASE_MSGIN, /* message in from device */ - PHASE_MSGOUT, /* message out to device */ - PHASE_AFTERMSGOUT, /* after message out phase */ + PHASE_MSGIN_DISCONNECT, /* disconnecting from bus */ + PHASE_MSGOUT, /* after message out phase */ + PHASE_MSGOUT_EXPECT, /* expecting message out */ PHASE_STATUS, /* status from device */ - PHASE_DISCONNECT, /* disconnecting from bus */ PHASE_DONE /* Command complete */ } phase_t; @@ -197,13 +200,15 @@ } fasdmatype_t; typedef enum { - syncneg_start, /* Negociate with device for Sync xfers */ - syncneg_sent, /* Sync Xfer negociation sent */ - syncneg_complete, /* Sync Xfer complete */ - syncneg_invalid /* Sync Xfer not supported */ -} syncneg_t; + neg_wait, /* Negociate with device */ + neg_inprogress, /* Negociation sent */ + neg_complete, /* Negociation complete */ + neg_targcomplete, /* Target completed negociation */ + neg_invalid /* Negociation not supported */ +} neg_t; #define MAGIC 0x441296bdUL +#define NR_MSGS 8 typedef struct { unsigned long magic_start; @@ -231,7 +236,9 @@ MsgQueue_t msgs; /* message queue for connected device */ unsigned int async_stp; /* Async transfer STP value */ - unsigned short last_message; /* last message to be sent */ + unsigned char msgin_fifo; /* bytes in fifo at time of message in */ + unsigned char message[256]; /* last message received from device */ + unsigned int msglen; /* length of last message received */ unsigned char disconnectable:1; /* this command can be disconnected */ unsigned char aborting:1; /* aborting command */ @@ -255,6 +262,7 @@ unsigned char clockrate; /* clock rate of FAS device (MHz) */ unsigned char select_timeout; /* timeout (R5) */ unsigned char sync_max_depth; /* Synchronous xfer max fifo depth */ + unsigned char wide_max_size; /* Maximum wide transfer size */ unsigned char cntl3; /* Control Reg 3 */ unsigned int asyncperiod; /* Async transfer period (ns) */ unsigned int disconnect_ok:1; /* Disconnects allowed? */ @@ -267,12 +275,14 @@ } queues; /* per-device info */ - struct { + struct fas216_device { unsigned char disconnect_ok:1; /* device can disconnect */ - unsigned int period; /* sync xfer period (*4ns) */ + unsigned char period; /* sync xfer period in (*4ns) */ unsigned char stp; /* synchronous transfer period */ unsigned char sof; /* synchronous offset register */ - syncneg_t negstate; /* synchronous transfer mode */ + unsigned char wide_xfer; /* currently negociated wide transfer */ + neg_t sync_state; /* synchronous transfer mode */ + neg_t wide_state; /* wide transfer mode */ } device[8]; unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ @@ -339,6 +349,9 @@ * Returns : 0 on success */ extern int fas216_release (struct Scsi_Host *instance); + +extern int fas216_print_stats(FAS216_Info *info, char *buffer); +extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer); /* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt) * Purpose : abort this command diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/msgqueue.c linux/drivers/acorn/scsi/msgqueue.c --- v2.2.17/drivers/acorn/scsi/msgqueue.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/msgqueue.c Fri Sep 15 23:31:12 2000 @@ -83,45 +83,25 @@ int length = 0; for (mq = msgq->qe; mq; mq = mq->next) - length += mq->length; + length += mq->msg.length; return length; } /* - * Function: char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return a message & its length + * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) + * Purpose : return a message * Params : msgq - queue to obtain message from - * length - pointer to int for message length + * : msgno - message number * Returns : pointer to message string, or NULL */ -char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length) +struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) { struct msgqueue_entry *mq; - if ((mq = msgq->qe) != NULL) { - msgq->qe = mq->next; - mqe_free(msgq, mq); - *length = mq->length; - } - - return mq ? mq->msg : NULL; -} - -/* - * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return next message & length without removing it from the list - * Params : msgq - queue to obtain message from - * : length - pointer to int for message length - * Returns : pointer to message string, or NULL - */ -char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) -{ - struct msgqueue_entry *mq = msgq->qe; - - *length = mq ? mq->length : 0; + for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--); - return mq ? mq->msg : NULL; + return mq ? &mq->msg : NULL; } /* @@ -143,10 +123,11 @@ va_start(ap, length); for (i = 0; i < length; i++) - mq->msg[i] = va_arg(ap, unsigned char); + mq->msg.msg[i] = va_arg(ap, unsigned char); va_end(ap); - mq->length = length; + mq->msg.length = length; + mq->msg.fifo = 0; mq->next = NULL; mqp = &msgq->qe; @@ -178,8 +159,7 @@ EXPORT_SYMBOL(msgqueue_initialise); EXPORT_SYMBOL(msgqueue_free); EXPORT_SYMBOL(msgqueue_msglength); -EXPORT_SYMBOL(msgqueue_getnextmsg); -EXPORT_SYMBOL(msgqueue_peeknextmsg); +EXPORT_SYMBOL(msgqueue_getmsg); EXPORT_SYMBOL(msgqueue_addmsg); EXPORT_SYMBOL(msgqueue_flush); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/msgqueue.h linux/drivers/acorn/scsi/msgqueue.h --- v2.2.17/drivers/acorn/scsi/msgqueue.h Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/msgqueue.h Fri Sep 15 23:31:12 2000 @@ -6,9 +6,14 @@ #ifndef MSGQUEUE_H #define MSGQUEUE_H -struct msgqueue_entry { +struct message { char msg[8]; int length; + int fifo; +}; + +struct msgqueue_entry { + struct message msg; struct msgqueue_entry *next; }; @@ -21,60 +26,51 @@ } MsgQueue_t; /* - * Function: void msgqueue_initialise (MsgQueue_t *msgq) + * Function: void msgqueue_initialise(MsgQueue_t *msgq) * Purpose : initialise a message queue * Params : msgq - queue to initialise */ -extern void msgqueue_initialise (MsgQueue_t *msgq); +extern void msgqueue_initialise(MsgQueue_t *msgq); /* - * Function: void msgqueue_free (MsgQueue_t *msgq) + * Function: void msgqueue_free(MsgQueue_t *msgq) * Purpose : free a queue * Params : msgq - queue to free */ -extern void msgqueue_free (MsgQueue_t *msgq); +extern void msgqueue_free(MsgQueue_t *msgq); /* - * Function: int msgqueue_msglength (MsgQueue_t *msgq) + * Function: int msgqueue_msglength(MsgQueue_t *msgq) * Purpose : calculate the total length of all messages on the message queue * Params : msgq - queue to examine * Returns : number of bytes of messages in queue */ -extern int msgqueue_msglength (MsgQueue_t *msgq); +extern int msgqueue_msglength(MsgQueue_t *msgq); /* - * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) + * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) * Purpose : return a message & its length * Params : msgq - queue to obtain message from - * length - pointer to int for message length - * Returns : pointer to message string, or NULL - */ -extern char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length); - -/* - * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length) - * Purpose : return next message & length without removing it from the list - * Params : msgq - queue to obtain message from - * : length - pointer to int for message length + * : msgno - message number * Returns : pointer to message string, or NULL */ -extern char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length); +extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno); /* - * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) + * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...) * Purpose : add a message onto a message queue * Params : msgq - queue to add message on * length - length of message * ... - message bytes * Returns : != 0 if successful */ -extern int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...); +extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...); /* - * Function: void msgqueue_flush (MsgQueue_t *msgq) + * Function: void msgqueue_flush(MsgQueue_t *msgq) * Purpose : flush all messages from message queue * Params : msgq - queue to flush */ -extern void msgqueue_flush (MsgQueue_t *msgq); +extern void msgqueue_flush(MsgQueue_t *msgq); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c --- v2.2.17/drivers/acorn/scsi/powertec.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/powertec.c Fri Sep 15 23:31:12 2000 @@ -114,6 +114,8 @@ powertecscsi_irqenable, powertecscsi_irqdisable, NULL, + NULL, + NULL, NULL }; @@ -271,8 +273,9 @@ 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; info->info.dma.pseudo = NULL; info->info.dma.stop = powertecscsi_dma_stop; @@ -443,31 +446,12 @@ host->io_port, host->irq, host->dma_channel, info->info.scsi.type, info->control.terms ? "on" : "off"); - pos += sprintf(buffer+pos, - "Queued commands: %-10u Issued commands: %-10u\n" - "Done commands : %-10u Reads : %-10u\n" - "Writes : %-10u Others : %-10u\n" - "Disconnects : %-10u Aborts : %-10u\n" - "Resets : %-10u\n", - info->info.stats.queues, info->info.stats.removes, - info->info.stats.fins, info->info.stats.reads, - info->info.stats.writes, info->info.stats.miscs, - info->info.stats.disconnects, info->info.stats.aborts, - info->info.stats.resets); + pos += fas216_print_stats(&info->info, buffer + pos); - pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none"); + pos += sprintf (buffer+pos, "\nAttached devices:\n"); for (scd = host->host_queue; scd; scd = scd->next) { - int len; - - proc_print_scsidevice (scd, buffer, &len, pos); - pos += len; - pos += sprintf (buffer+pos, "Extensions: "); - if (scd->tagged_supported) - pos += sprintf (buffer+pos, "TAG %sabled [%d] ", - scd->tagged_queue ? "en" : "dis", - scd->current_tag); - pos += sprintf (buffer+pos, "\n"); + pos += fas216_print_device(&info->info, scd, buffer + pos); if (pos + begin < offset) { begin += pos; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/acorn/scsi/queue.c linux/drivers/acorn/scsi/queue.c --- v2.2.17/drivers/acorn/scsi/queue.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/acorn/scsi/queue.c Fri Sep 15 23:31:12 2000 @@ -55,6 +55,7 @@ q->magic = QUEUE_MAGIC_FREE; q->SCpnt = NULL; } + q -= 1; q->next = NULL; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/ap1000/ap.c linux/drivers/ap1000/ap.c --- v2.2.17/drivers/ap1000/ap.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/ap1000/ap.c Tue Sep 12 12:55:07 2000 @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c --- v2.2.17/drivers/ap1000/ddv.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/ap1000/ddv.c Tue Sep 12 12:55:07 2000 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/Config.in linux/drivers/block/Config.in --- v2.2.17/drivers/block/Config.in Sun Jun 11 21:44:11 2000 +++ linux/drivers/block/Config.in Wed Nov 8 23:00:34 2000 @@ -40,6 +40,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then + bool ' ALI 15X3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3 bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 @@ -52,7 +53,7 @@ bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 fi fi - if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then + if [ "$CONFIG_POWERMAC" = "y" ]; then bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC @@ -138,6 +139,10 @@ if [ "$CONFIG_PCI" = "y" ]; then tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA fi +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Compaq CISS Array support' CONFIG_BLK_CPQ_CISS_DA +fi + if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then define_bool CONFIG_BLK_DEV_HD y diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.2.17/drivers/block/DAC960.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/DAC960.c Sun Sep 10 14:46:08 2000 @@ -19,8 +19,8 @@ */ -#define DAC960_DriverVersion "2.2.8" -#define DAC960_DriverDate "19 August 2000" +#define DAC960_DriverVersion "2.2.9" +#define DAC960_DriverDate "7 September 2000" #include @@ -310,13 +310,8 @@ static void DAC960_WaitForCommand(DAC960_Controller_T *Controller) { - WaitQueue_T WaitQueueEntry = { current, NULL }; - add_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry); - current->state = TASK_UNINTERRUPTIBLE; - spin_unlock(&io_request_lock); - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry); + spin_unlock_irq(&io_request_lock); + __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands); spin_lock_irq(&io_request_lock); } @@ -5053,7 +5048,8 @@ } Geometry.start = Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].start_sect; - return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T)); + return (copy_to_user(UserGeometry, &Geometry, + sizeof(DiskGeometry_T)) ? -EFAULT : 0); case BLKGETSIZE: /* Get Device Size. */ if ((long *) Argument == NULL) return -EINVAL; @@ -5161,8 +5157,8 @@ ControllerInfo.PCI_Address = Controller->PCI_Address; strcpy(ControllerInfo.ModelName, Controller->ModelName); strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); - return copy_to_user(UserSpaceControllerInfo, &ControllerInfo, - sizeof(DAC960_ControllerInfo_T)); + return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo, + sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0); } case DAC960_IOCTL_V1_EXECUTE_COMMAND: { @@ -6484,7 +6480,7 @@ unsigned char CommandBuffer[80]; int Length; if (Count > sizeof(CommandBuffer)-1) return -EINVAL; - copy_from_user(CommandBuffer, Buffer, Count); + if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT; CommandBuffer[Count] = '\0'; Length = strlen(CommandBuffer); if (CommandBuffer[Length-1] == '\n') diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/Makefile linux/drivers/block/Makefile --- v2.2.17/drivers/block/Makefile Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/Makefile Mon Sep 11 18:06:33 2000 @@ -142,6 +142,10 @@ IDE_OBJS += pdc4030.o endif +ifeq ($(CONFIG_BLK_DEV_ALI15X3),y) +IDE_OBJS += alim15x3.o +endif + ifeq ($(CONFIG_BLK_DEV_TRM290),y) IDE_OBJS += trm290.o endif @@ -243,6 +247,14 @@ else ifeq ($(CONFIG_BLK_CPQ_DA),m) M_OBJS += cpqarray.o + endif +endif + +ifeq ($(CONFIG_BLK_CPQ_CISS_DA),y) +L_OBJS += cciss.o +else + ifeq ($(CONFIG_BLK_CPQ_CISS_DA),m) + M_OBJS += cciss.o endif endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.2.17/drivers/block/acsi.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/acsi.c Sat Oct 14 00:07:14 2000 @@ -252,17 +252,8 @@ static char *CurrentBuffer; -#define SET_TIMER() \ - do { \ - del_timer( &acsi_timer ); \ - acsi_timer.expires = jiffies + ACSI_TIMEOUT; \ - add_timer( &acsi_timer ); \ - } while(0) - -#define CLEAR_TIMER() \ - do { \ - del_timer( &acsi_timer ); \ - } while(0) +#define SET_TIMER() mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT) +#define CLEAR_TIMER() del_timer(&acsi_timer) static unsigned long STramMask; #define STRAM_ADDR(a) (((a) & STramMask) == 0) @@ -411,7 +402,7 @@ * 6), the timeout is based on the 'jiffies' variable to provide exact * timeouts for device probing etc. * If interrupts are disabled, the number of tries is based on the - * 'loops_per_sec' variable. A rough estimation is sufficient here... + * 'loops_per_jiffy' variable. A rough estimation is sufficient here... */ #define INT_LEVEL \ @@ -424,12 +415,12 @@ { if (INT_LEVEL < 6) { - unsigned long maxjif; - for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); ) + unsigned long maxjif = jiffies + timeout; + while (time_before(jiffies, maxjif)) if (!(mfp.par_dt_reg & 0x20)) return( 1 ); } else { - long tries = loops_per_sec / HZ / 8 * timeout; + long tries = loops_per_jiffy / 8 * timeout; while( --tries >= 0 ) if (!(mfp.par_dt_reg & 0x20)) return( 1 ); } @@ -441,12 +432,12 @@ { if (INT_LEVEL < 6) { - unsigned long maxjif; - for( maxjif = jiffies + timeout; time_before(jiffies, maxjif); ) + unsigned long maxjif = jiffies + timeout; + while (time_before(jiffies, maxjif)) if (mfp.par_dt_reg & 0x20) return( 1 ); } else { - long tries = loops_per_sec * timeout / HZ / 8; + long tries = loops_per_jiffy / 8 * timeout; while( tries-- >= 0 ) if (mfp.par_dt_reg & 0x20) return( 1 ); } @@ -501,7 +492,7 @@ #endif rwflag = rwflag ? 0x100 : 0; - paddr = VTOP( buffer ); + paddr = virt_to_phys( buffer ); acsi_delay_end(COMMAND_DELAY); DISABLE_IRQ(); @@ -609,7 +600,7 @@ if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); if (!acsi_wait_for_IRQ( 10 )) return( 0 ); acsi_getstatus(); - dma_cache_maintenance( VTOP(buffer), 16, 0 ); + dma_cache_maintenance( virt_to_phys(buffer), 16, 0 ); return( 1 ); } @@ -808,7 +799,7 @@ return; } - dma_cache_maintenance( VTOP(CurrentBuffer), CurrentNSect*512, 0 ); + dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 ); if (CurrentBuffer == acsi_buffer) copy_from_acsibuffer(); @@ -1029,7 +1020,7 @@ * consecutive buffers and thus can be done with a single command. */ buffer = CURRENT->buffer; - pbuffer = VTOP(buffer); + pbuffer = virt_to_phys(buffer); nsect = CURRENT->current_nr_sectors; CurrentNReq = 1; @@ -1051,7 +1042,7 @@ unsigned long pendadr, pnewadr; pendadr = pbuffer + nsect*512; while( (bh = bh->b_reqnext) ) { - pnewadr = VTOP(bh->b_data); + pnewadr = virt_to_phys(bh->b_data); if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break; nsect += bh->b_size >> 9; pendadr = pnewadr + bh->b_size; @@ -1814,7 +1805,7 @@ unregister_blkdev( MAJOR_NR, "ad" ); return -ENOMEM; } - phys_acsi_buffer = VTOP( acsi_buffer ); + phys_acsi_buffer = virt_to_phys( acsi_buffer ); STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c --- v2.2.17/drivers/block/acsi_slm.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/acsi_slm.c Sat Oct 14 00:07:14 2000 @@ -413,8 +413,8 @@ CMDSET_TARG_LUN( slmprint_cmd, sip->target, sip->lun ); cmd = slmprint_cmd; - paddr = VTOP( SLMBuffer ); - dma_cache_maintenance( paddr, VTOP(BufferP)-paddr, 1 ); + paddr = virt_to_phys( SLMBuffer ); + dma_cache_maintenance( paddr, virt_to_phys(BufferP)-paddr, 1 ); DISABLE_IRQ(); /* Low on A1 */ @@ -466,7 +466,7 @@ addr = get_dma_addr(); stat = acsi_getstatus(); SLMError = (stat < 0) ? SLMSTAT_ACSITO : - (addr < VTOP(BufferP)) ? SLMSTAT_NOTALL : + (addr < virt_to_phys(BufferP)) ? SLMSTAT_NOTALL : stat; dma_wd.dma_mode_status = 0x80; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c --- v2.2.17/drivers/block/alim15x3.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/alim15x3.c Mon Sep 11 18:06:33 2000 @@ -0,0 +1,743 @@ +/* + * + * Copyright (C) 1998-99 Michel Aubry, Maintainer + * Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer + * Copyright (C) 1998-99 Andre Hedrick, Integrater and Maintainer + * + * (U)DMA capable version of ali 1543(C), 1535(D) + * + */ + +/* ====================================================== + * linux/drivers/block/alim15x3.c + * version: 1.0 beta3 (Sep. 6, 1999) + * e-mail your problems to cjtsai@ali.com.tw + * + * Note: if you want to combine the code to kernel 2.3.x + * you should --- + * change: //#define ALI_KERNEL_2_3_X + * to: #define ALI_KERNEL_2_3_X + * and replace the "alim15x3.c" exists in kernel 2.3.x + * with this file. I am not very sure that this file can + * support all 2.3.x. Because I only test it in kernel + * version 2.3.16. So, before you replace the file, backup + * the old one. + * ======================================================= */ + +/* ===================== important ======================= + * for 2.2.x, you should use "//#define ALI_KERNEL_2_3_X" + * for 2.3.x, you should use "#define ALI_KERNEL_2_3_X" + * ======================================================= */ +//#define ALI_KERNEL_2_3_X + + +#include +#include +#include +#include +#include +#include + +#if defined(ALI_KERNEL_2_3_X) +#include +#else +#include "ide.h" +#endif + +#include "ide_modes.h" + +static int m5229_revision = -1; +static int chip_is_1543c_e = 0; +static int cable_80_pin[2] = { 0, 0 }; + +/* This is fun. -DaveM */ +#define IDE_SETXFER 0x03 +#define IDE_SETFEATURE 0xef + +#define IDE_DMA2_ENABLE 0x22 // dma +#define IDE_DMA1_ENABLE 0x21 +#define IDE_DMA0_ENABLE 0x20 + +#define IDE_UDMA4_ENABLE 0x44 // ultra 66 +#define IDE_UDMA3_ENABLE 0x43 + +#define IDE_UDMA2_ENABLE 0x42 // ultra 33 +#define IDE_UDMA1_ENABLE 0x41 +#define IDE_UDMA0_ENABLE 0x40 + + + +#if defined(ALI_KERNEL_2_3_X) +// ===================== Support 2.3.x ===================== + + +#define DISPLAY_ALI_TIMINGS + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) +#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 */ +struct pci_dev *bmide_dev; + +char *fifo[4] = { + "FIFO Off", + "FIFO On ", + "DMA mode", + "PIO mode" }; + +char *udmaT[8] = { + "1.5T", + " 2T", + "2.5T", + " 3T", + "3.5T", + " 4T", + " 6T", + " 8T" +}; + +char *channel_status[8] = { + "OK ", + "busy ", + "DRQ ", + "DRQ busy ", + "error ", + "error busy ", + "error DRQ ", + "error DRQ busy" +}; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + +unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) +{ + byte confreg0 = 0, confreg1 =0, progif = 0; + int errors = 0; + + if (pci_read_config_byte(dev, 0x50, &confreg1)) + goto veryspecialsettingserror; + if (!(confreg1 & 0x02)) + if (pci_write_config_byte(dev, 0x50, confreg1 | 0x02)) + goto veryspecialsettingserror; + + if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) + goto veryspecialsettingserror; + if (!(progif & 0x40)) { + /* + * The way to enable them is to set progif + * writable at 0x4Dh register, and set bit 6 + * of progif to 1: + */ + if (pci_read_config_byte(dev, 0x4d, &confreg0)) + goto veryspecialsettingserror; + if (confreg0 & 0x80) + if (pci_write_config_byte(dev, 0x4d, confreg0 & ~0x80)) + goto veryspecialsettingserror; + if (pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x40)) + goto veryspecialsettingserror; + if (confreg0 & 0x80) + if (pci_write_config_byte(dev, 0x4d, confreg0)) + errors++; + } + + if ((pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) || (!(progif & 0x40))) + goto veryspecialsettingserror; + + printk("%s: enabled read of IDE channels state (en/dis-abled) %s.\n", + name, errors ? "with Error(s)" : "Succeeded" ); + return 0; + +veryspecialsettingserror: + printk("%s: impossible to enable read of IDE channels state (en/dis-abled)!\n", name); + return 0; +} + +static void ali15x3_tune_drive (ide_drive_t *drive, byte pio) +{ + ide_pio_data_t d; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int s_time, a_time, c_time; + byte s_clc, a_clc, r_clc; + unsigned long flags; + int bus_speed = ide_system_bus_speed(); + int port = hwif->index ? 0x5c : 0x58; + + pio = ide_get_best_pio_mode(drive, pio, 5, &d); + s_time = ide_pio_timings[pio].setup_time; + a_time = ide_pio_timings[pio].active_time; + if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) + s_clc = 0; + if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8) + a_clc = 0; + c_time = ide_pio_timings[pio].cycle_time; + +#if 0 + if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16) + r_clc = 0; +#endif + + if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) { + r_clc = 1; + } else { + if (r_clc >= 16) + r_clc = 0; + } + 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); + + /* + * setup active rec + * { 70, 165, 365 }, PIO Mode 0 + * { 50, 125, 208 }, PIO Mode 1 + * { 30, 100, 110 }, PIO Mode 2 + * { 30, 80, 70 }, PIO Mode 3 with IORDY + * { 25, 70, 25 }, PIO Mode 4 with IORDY ns + * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) + */ +} + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) +static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy) +{ + byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1; + unsigned int bibma; + byte c0, c1; + byte rev, tmp; + char *p = buffer; + char *q; + + /* fetch rev. */ + pci_read_config_byte(bmide_dev, 0x08, &rev); + if (rev >= 0xc1) /* M1543C or newer */ + udmaT[7] = " ???"; + else + fifo[3] = " ??? "; + + /* first fetch bibma: */ + pci_read_config_dword(bmide_dev, 0x20, &bibma); + bibma = (bibma & 0xfff0) ; + /* + * at that point bibma+0x2 et bibma+0xa are byte + * registers to investigate: + */ + c0 = inb((unsigned short)bibma + 0x02); + c1 = inb((unsigned short)bibma + 0x0a); + + p += sprintf(p, + "\n Ali M15x3 Chipset.\n"); + p += sprintf(p, + " ------------------\n"); + pci_read_config_byte(bmide_dev, 0x78, ®53h); + p += sprintf(p, "PCI Clock: %d.\n", reg53h); + + pci_read_config_byte(bmide_dev, 0x53, ®53h); + p += sprintf(p, + "CD_ROM FIFO:%s, CD_ROM DMA:%s\n", + (reg53h & 0x02) ? "Yes" : "No ", + (reg53h & 0x01) ? "Yes" : "No " ); + pci_read_config_byte(bmide_dev, 0x74, ®53h); + p += sprintf(p, + "FIFO Status: contains %d Words, runs%s%s\n\n", + (reg53h & 0x3f), + (reg53h & 0x40) ? " OVERWR" : "", + (reg53h & 0x80) ? " OVERRD." : "." ); + + p += sprintf(p, + "-------------------primary channel-------------------secondary channel---------\n\n"); + + pci_read_config_byte(bmide_dev, 0x09, ®53h); + p += sprintf(p, + "channel status: %s %s\n", + (reg53h & 0x20) ? "On " : "Off", + (reg53h & 0x10) ? "On " : "Off" ); + + p += sprintf(p, + "both channels togth: %s %s\n", + (c0&0x80) ? "No " : "Yes", + (c1&0x80) ? "No " : "Yes" ); + + pci_read_config_byte(bmide_dev, 0x76, ®53h); + p += sprintf(p, + "Channel state: %s %s\n", + channel_status[reg53h & 0x07], + channel_status[(reg53h & 0x70) >> 4] ); + + pci_read_config_byte(bmide_dev, 0x58, ®5xh); + pci_read_config_byte(bmide_dev, 0x5c, ®5yh); + p += sprintf(p, + "Add. Setup Timing: %dT %dT\n", + (reg5xh & 0x07) ? (reg5xh & 0x07) : 8, + (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 ); + + pci_read_config_byte(bmide_dev, 0x59, ®5xh); + pci_read_config_byte(bmide_dev, 0x5d, ®5yh); + p += sprintf(p, + "Command Act. Count: %dT %dT\n" + "Command Rec. Count: %dT %dT\n\n", + (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, + (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, + (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16, + (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 ); + + p += sprintf(p, + "----------------drive0-----------drive1------------drive0-----------drive1------\n\n"); + p += sprintf(p, + "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "Yes" : "No ", + (c0&0x40) ? "Yes" : "No ", + (c1&0x20) ? "Yes" : "No ", + (c1&0x40) ? "Yes" : "No " ); + + pci_read_config_byte(bmide_dev, 0x54, ®5xh); + pci_read_config_byte(bmide_dev, 0x55, ®5yh); + q = "FIFO threshold: %2d Words %2d Words %2d Words %2d Words\n"; + if (rev < 0xc1) { + if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) { + p += sprintf(p, q, 8, 8, 8, 8); + } else { + p += sprintf(p, q, + (reg5xh & 0x03) + 12, + ((reg5xh & 0x30)>>4) + 12, + (reg5yh & 0x03) + 12, + ((reg5yh & 0x30)>>4) + 12 ); + } + } else { + p += sprintf(p, q, + (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4, + (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4, + (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4, + (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4 ); + } + +#if 0 + p += sprintf(p, + "FIFO threshold: %2d Words %2d Words %2d Words %2d Words\n", + (reg5xh & 0x03) + 12, + ((reg5xh & 0x30)>>4) + 12, + (reg5yh & 0x03) + 12, + ((reg5yh & 0x30)>>4) + 12 ); +#endif + + p += sprintf(p, + "FIFO mode: %s %s %s %s\n", + fifo[((reg5xh & 0x0c) >> 2)], + fifo[((reg5xh & 0xc0) >> 6)], + fifo[((reg5yh & 0x0c) >> 2)], + fifo[((reg5yh & 0xc0) >> 6)] ); + + pci_read_config_byte(bmide_dev, 0x5a, ®5xh); + pci_read_config_byte(bmide_dev, 0x5b, ®5xh1); + pci_read_config_byte(bmide_dev, 0x5e, ®5yh); + pci_read_config_byte(bmide_dev, 0x5f, ®5yh1); + + p += sprintf(p,/* + "------------------drive0-----------drive1------------drive0-----------drive1------\n")*/ + "Dt RW act. Cnt %2dT %2dT %2dT %2dT\n" + "Dt RW rec. Cnt %2dT %2dT %2dT %2dT\n\n", + (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, + (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8, + (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, + (reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8, + (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16, + (reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16, + (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16, + (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 ); + + p += sprintf(p, + "-----------------------------------UDMA Timings--------------------------------\n\n"); + + pci_read_config_byte(bmide_dev, 0x56, ®5xh); + pci_read_config_byte(bmide_dev, 0x57, ®5yh); + p += sprintf(p, + "UDMA: %s %s %s %s\n" + "UDMA timings: %s %s %s %s\n\n", + (reg5xh & 0x08) ? "OK" : "No", + (reg5xh & 0x80) ? "OK" : "No", + (reg5yh & 0x08) ? "OK" : "No", + (reg5yh & 0x80) ? "OK" : "No", + udmaT[(reg5xh & 0x07)], + udmaT[(reg5xh & 0x70) >> 4], + udmaT[reg5yh & 0x07], + udmaT[(reg5yh & 0x70) >> 4] ); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + + +// =================== End Support 2.3.x =================== +#endif // defined(ALI_KERNEL_2_3_X) + + + +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 & 0x10) + return IDE_UDMA4_ENABLE; + if(bits & 0x08) + return IDE_UDMA3_ENABLE; + 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 = 20000; + byte stat; + + while(--timeout) { + stat = GET_STAT(); // printk("STAT(%2x) ", stat); + + if(!(stat & BUSY_STAT)) { + if((stat & READY_STAT) || (stat & ERR_STAT)) + break; + } + udelay(150); + } + 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(); + + old_select = IN_BYTE(IDE_SELECT_REG); // save old selected device + OUT_BYTE(drive->select.all, IDE_SELECT_REG); // "SELECT " + + OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); // "SETXFER " + OUT_BYTE(command, IDE_NSECTOR_REG); // "CMND " + + if(wait_for_ready(drive)) // "wait " + goto out; + + OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG); // "SETFEATURE " + (void) wait_for_ready(drive); // "wait " + +out: + OUT_BYTE(old_select, IDE_SELECT_REG); // restore to old "selected device" + 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; + +/* if((((drive->id->dma_mword & 0x0007) << 8) != + (drive->id->dma_mword & 0x0700)))*/ + ali15x3_do_setfeature(drive, dma2_bits_to_command(bits)); + + // clear "ultra enable" bit + pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte); + if(unit) + tmpbyte &= 0x7f; + else + tmpbyte &= 0xf7; + 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) { // 00011000, disk: ultra66 + 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; + } + } + } + + // set feature only if we are not in that mode +/* if(((drive->id->dma_ultra & 0x001f) << 8) != + (drive->id->dma_ultra & 0x1f00))*/ + 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); + + tmpbyte &= (0x0f << ( (1-unit) << 2) ); // clear bit0~3 or bit 4~7 + // 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); + + 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); + } + + printk(" ALI15X3: Ultra DMA enabled\n"); +} + +static int ali15x3_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; + + if((id->field_valid & 0x0004) && + (id->dma_ultra & 0x001f)) { + // 1543C_E, in ultra mode, some WDC "harddisk" will cause "CRC" errors + // (even if no CRC problem), so we try to use "DMA" here + if( m5229_revision <= 0x20) + ali15x3_dma2_enable(drive, dma_base); /* Normal MultiWord DMA modes. */ + else if( (m5229_revision < 0xC2) && + ( (drive->media!=ide_disk) || (chip_is_1543c_e && strstr(id->model, "WDC ")) ) ) + ali15x3_dma2_enable(drive, dma_base); /* Normal MultiWord DMA modes. */ + else // >= 0xC2 or 0xC1 with no problem + ali15x3_udma_enable(drive, dma_base); /* UltraDMA modes. */ + } else { + ali15x3_dma2_enable(drive, dma_base); /* Normal MultiWord DMA modes. */ + } + } + + drive->using_dma = enable; // on, off + return 0; +} + +static int ali15x3_config_drive_for_dma(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(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) && // dma supported + hwif->autodma ) { + if(id->field_valid & 0x0004) // word 88 is valid + if(id->dma_ultra & 0x001F) // 00011111 => ultra dma mode 0~4 + return hwif->dmaproc(ide_dma_on, drive); + + if(id->field_valid & 0x0002) // words 64~70 is valid + if((id->dma_mword & 0x0007) // word 63, multiword DMA mode 0~2 + || (id->dma_1word & 0x0007)) // word 62, single word DMA mode 0~2 + return hwif->dmaproc(ide_dma_on, drive); + } + + return hwif->dmaproc(ide_dma_off_quietly, drive); +} + +static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + 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 */ + break; + default: + } + + return ide_dmaproc(func, drive); // use standard DMA stuff +} + +void __init ide_init_ali15x3 (ide_hwif_t *hwif) +{ + unsigned long flags; + byte tmp_m5229_revision; + + struct pci_dev *dev_m1533, *dev_m5229 = hwif->pci_dev; + byte ideic, inmir, tmpbyte; + byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, + 1, 11, 0, 12, 0, 14, 0, 15 }; + + hwif->irq = hwif->channel ? 15 : 14; + + // look for ISA bridge m1533 + for (dev_m1533=pci_devices; dev_m1533; dev_m1533=dev_m1533->next) + if(dev_m1533->vendor==PCI_VENDOR_ID_AL && + dev_m1533->device==PCI_DEVICE_ID_AL_M1533) + break; // we find it + + pci_read_config_byte(dev_m1533, 0x58, &ideic); // read IDE interface control + ideic = ideic & 0x03; // bit0, bit1 + + /* get IRQ for IDE Controller */ + if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) { // get SIRQ1 routing table + pci_read_config_byte(dev_m1533, 0x44, &inmir); + inmir = inmir & 0x0f; + hwif->irq = irq_routing_table[inmir]; + } + else if (hwif->channel && !(ideic & 0x01)) { // get SIRQ2 routing table + pci_read_config_byte(dev_m1533, 0x75, &inmir); + inmir = inmir & 0x0f; + hwif->irq = irq_routing_table[inmir]; + } + + // read m5229 revision to a temp variable + pci_read_config_byte(dev_m5229, PCI_REVISION_ID, &tmp_m5229_revision); + + if(m5229_revision == -1) { // only do it one time. + m5229_revision = 0; // change the default to 0 + printk("\n************************************\n"); + printk("* ALi IDE driver (1.0 beta3) *\n"); + printk("* Chip Revision is %02X *\n", tmp_m5229_revision); + printk("* Maximum capability is "); + if(tmp_m5229_revision >= 0xC2) + printk("- UDMA 66 *\n"); + else if(tmp_m5229_revision >= 0xC0) + printk("- UDMA 33 *\n"); + else if(tmp_m5229_revision == 0x20) + printk(" - DMA *\n"); + else + printk(" - PIO *\n"); + printk("************************************\n\n"); + + // support CD-ROM DMA mode + pci_read_config_byte(dev_m5229, 0x53, &tmpbyte); + tmpbyte = (tmpbyte & (~0x02)) | 0x01; + save_flags(flags); + cli(); + pci_write_config_byte(dev_m5229, 0x53, tmpbyte); + restore_flags(flags); + } + + if ( (hwif->dma_base) && (tmp_m5229_revision>=0x20) ) { + +#if defined(ALI_KERNEL_2_3_X) + if(tmp_m5229_revision>=0xC2) + hwif->udma_four = 1; + else + hwif->udma_four = 0; +#endif + + if(m5229_revision == 0) { // only do it one time + m5229_revision = tmp_m5229_revision; // keep it + + if(m5229_revision >= 0xC2) { // 1543C-B?, 1535, 1535D, 1553 + // Note 1: not all "motherboard" support this detection + // Note 2: if no udma 66 device, the detection may "error". + // 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 + pci_read_config_byte(dev_m5229, 0x4b, &tmpbyte); + pci_write_config_byte(dev_m5229, 0x4b, tmpbyte | 0x08); + + // set south-bridge's enable bit, m1533, 0x79 + pci_read_config_byte(dev_m1533, 0x79, &tmpbyte); + if(m5229_revision==0xC2) // 1543C-B0 (m1533, 0x79, bit 2) + pci_write_config_byte(dev_m1533, 0x79, tmpbyte | 0x04); + else if (m5229_revision==0xC3) // 1553/1535 (m1533, 0x79, bit 1) + pci_write_config_byte(dev_m1533, 0x79, tmpbyte | 0x02); + restore_flags(flags); + + // Ultra66 cable detection (from Host View) + // m5229, 0x4a, bit0: primary, bit1: secondary 80 pin + pci_read_config_byte(dev_m5229, 0x4a, &tmpbyte); + if(! (tmpbyte & 0x01)) // 0x4a, bit0 is 0 => + cable_80_pin[0] = 1; // primary channel has 80-pin (from host view) + if(! (tmpbyte & 0x02)) // 0x4a, bit1 is 0 => + cable_80_pin[1] = 1; // secondary channel has 80-pin (from host view) + } else { + // 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_m5229, 0x4b, &tmpbyte); + save_flags(flags); + cli(); + pci_write_config_byte(dev_m5229, 0x4b, tmpbyte & 0x7F); // clear bit 7 + restore_flags(flags); + + // check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010 + pci_read_config_byte(dev_m1533, 0x5e, &tmpbyte); + chip_is_1543c_e = ( (tmpbyte & 0x1e) == 0x12 ) ? 1: 0; + } + } + + // M1543 or newer for DMAing + hwif->dmaproc = &ali15x3_dmaproc; + hwif->autodma = 1; + } else { + // if both channel use PIO, then chip revision is not important. + // we should't assign m5229_revision here (assign it will affect + // the chip detection procedure above --- if(! m5229_revision) + hwif->autodma = 0; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } + +#if defined(ALI_KERNEL_2_3_X) + hwif->tuneproc = &ali15x3_tune_drive; +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) + bmide_dev = hwif->pci_dev; + ali_display_info = &ali_get_info; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ +#endif /* defined(ALI_KERNEL_2_3_X) */ + + return; +} \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/buddha.c linux/drivers/block/buddha.c --- v2.2.17/drivers/block/buddha.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/buddha.c Fri Oct 13 23:57:54 2000 @@ -0,0 +1,168 @@ +/* + * linux/drivers/block/buddha.c -- Amiga Buddha and Catweasel IDE Driver + * + * Copyright (C) 1997 by Geert Uytterhoeven + * + * This driver was written by based on the specifications in README.buddha. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * TODO: + * - test it :-) + * - tune the timings using the speed-register + */ + +#include +#include +#include +#include +#include +#include + +#include "ide.h" + +#include +#include + + + /* + * The Buddha has 2 IDE interfaces, the Catweasel has 3 + */ + +#define BUDDHA_NUM_HWIFS 2 +#define CATWEASEL_NUM_HWIFS 3 + + + /* + * Bases of the IDE interfaces (relative to the board address) + */ + +#define BUDDHA_BASE1 0x800 +#define BUDDHA_BASE2 0xa00 +#define BUDDHA_BASE3 0xc00 + +static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = { + BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 +}; + + + /* + * Offsets from one of the above bases + */ + +#define BUDDHA_DATA 0x00 +#define BUDDHA_ERROR 0x06 /* see err-bits */ +#define BUDDHA_NSECTOR 0x0a /* nr of sectors to read/write */ +#define BUDDHA_SECTOR 0x0e /* starting sector */ +#define BUDDHA_LCYL 0x12 /* starting cylinder */ +#define BUDDHA_HCYL 0x16 /* high byte of starting cyl */ +#define BUDDHA_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ +#define BUDDHA_STATUS 0x1e /* see status-bits */ +#define BUDDHA_CONTROL 0x11a + +static const u_int buddha_offsets[IDE_NR_PORTS] = { + BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, + BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL +}; + + + /* + * Other registers + */ + +#define BUDDHA_IRQ1 0xf00 /* MSB = 1, Harddisk is source of */ +#define BUDDHA_IRQ2 0xf40 /* interrupt */ +#define BUDDHA_IRQ3 0xf80 + +static const int buddha_irqports[CATWEASEL_NUM_HWIFS] = { + BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3 +}; + +#define BUDDHA_IRQ_MR 0xfc0 /* master interrupt enable */ + + + /* + * Board information + */ + +static u_long buddha_board = 0; +static int buddha_num_hwifs = -1; + + + /* + * Check and acknowledge the interrupt status + */ + +static int buddha_ack_intr(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); + if (!(ch & 0x80)) + return 0; + return 1; +} + + + /* + * Any Buddha or Catweasel boards present? + */ + +static int find_buddha(void) +{ + u_int key; + const struct ConfigDev *cd; + + buddha_num_hwifs = 0; + if ((key = zorro_find(ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA, 0, 0))) + buddha_num_hwifs = BUDDHA_NUM_HWIFS; + else if ((key = zorro_find(ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL, 0, + 0))) + buddha_num_hwifs = CATWEASEL_NUM_HWIFS; + if (key) { + cd = zorro_get_board(key); + buddha_board = (u_long)cd->cd_BoardAddr; + if (buddha_board) { + buddha_board = ZTWO_VADDR(buddha_board); + /* write to BUDDHA_IRQ_MR to enable the board IRQ */ + *(char *)(buddha_board+BUDDHA_IRQ_MR) = 0; + zorro_config_board(key, 0); + } + } + return buddha_num_hwifs; +} + + + /* + * Probe for a Buddha or Catweasel IDE interface + * We support only _one_ of them, no multiple boards! + */ + +int buddha_probe_hwif(int index, ide_hwif_t *hwif) +{ + static int buddha_index[CATWEASEL_NUM_HWIFS] = { 0, }; + int i; + + if (buddha_num_hwifs < 0 && !find_buddha()) + return 0; + + for (i = 0; i < buddha_num_hwifs; i++) { + if (!buddha_index[i]) { + printk("ide%d: %s IDE interface\n", index, + buddha_num_hwifs == BUDDHA_NUM_HWIFS ? "Buddha" : + "Catweasel"); + buddha_index[i] = index+1; + } + if (buddha_index[i] == index+1) { + ide_setup_ports(hwif, (ide_ioreg_t)(buddha_board+buddha_bases[i]), + buddha_offsets, + (ide_ioreg_t)(buddha_board+buddha_irqports[i]), + buddha_ack_intr); + hwif->irq = IRQ_AMIGA_PORTS; + return 1; + } + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/cciss.c linux/drivers/block/cciss.c --- v2.2.17/drivers/block/cciss.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/cciss.c Sat Nov 18 00:44:06 2000 @@ -0,0 +1,1936 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 2000 Compaq Computer Corporation + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) +#define DRIVER_NAME "Compaq CISS Driver (v 1.0.0)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(1,0,0) + +/* Embedded module documentation macros - see modules.h */ +MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation"); +MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300"); + +#include "cciss_cmd.h" +#include "cciss.h" +#include + +#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) + +/* board_id = Subsystem Device ID & Vendor ID + * product = Marketing Name for the board + * access = Address of the struct of function pointers + */ +static struct board_type products[] = { + { 0x40700E11, "Smart Array 5300", &SA5_access }, +}; + +/* How long to wait (in millesconds) for board to go into simple mode */ +#define MAX_CONFIG_WAIT 1000 + +#define READ_AHEAD 128 +#define NR_CMDS 128 /* #commands that can be outstanding */ +#define MAX_CTLR 8 +static int nr_ctlr =0; +static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static struct proc_dir_entry *proc_cciss = NULL; + +static void do_cciss_request(int i); +/* + * This is a hack. This driver eats a major number for each controller, and + * sets blkdev[xxx].request_fn to each one of these so the real request + * function knows what controller its working with. + */ +#define DO_CCISS_REQUEST(x) { do_cciss_request(x); } + +static void do_cciss_request0(void) DO_CCISS_REQUEST(0); +static void do_cciss_request1(void) DO_CCISS_REQUEST(1); +static void do_cciss_request2(void) DO_CCISS_REQUEST(2); +static void do_cciss_request3(void) DO_CCISS_REQUEST(3); +static void do_cciss_request4(void) DO_CCISS_REQUEST(4); +static void do_cciss_request5(void) DO_CCISS_REQUEST(5); +static void do_cciss_request6(void) DO_CCISS_REQUEST(6); +static void do_cciss_request7(void) DO_CCISS_REQUEST(7); + +static int cciss_open(struct inode *inode, struct file *filep); +static int cciss_release(struct inode *inode, struct file *filep); +static int cciss_ioctl(struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg); + +static int revalidate_allvol(kdev_t dev); +static int revalidate_logvol(kdev_t dev, int maxusage); +static int frevalidate_logvol(kdev_t dev); + +static void cciss_getgeometry(int cntl_num); + +static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c); +static void start_io( ctlr_info_t *h); + +static struct file_operations cciss_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + cciss_ioctl, /* ioctl */ + NULL, /* mmap */ + cciss_open, /* open code */ + NULL, + cciss_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + NULL, /* Disk change */ + frevalidate_logvol, /* revalidate */ +}; + +/* + * Report information about this controller. + */ +static int cciss_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + off_t pos = 0; + off_t len = 0; + int size, i, ctlr; + ctlr_info_t *h = (ctlr_info_t*)data; + drive_info_struct *drv; + + ctlr = h->ctlr; + size = sprintf(buffer, "%s: Compaq %s Controller\n" + " Board ID: %08lx\n" + " Firmware Version: %c%c%c%c\n" + " Memory Address: %08lx\n" + " IRQ: 0x%x\n" + " Logical drives: %d\n" + " Current Q depth: %d\n" + " Current # commands on controller %d\n" + " Max Q depth since init: %d\n" + " Max # commands on controller since init: %d\n" + " Max SG entries since init: %d\n\n", + h->devname, + h->product_name, + (unsigned long)h->board_id, + h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3], + (unsigned long)h->vaddr, + (unsigned int)h->intr, + h->num_luns, + h->Qdepth, h->commands_outstanding, + h->maxQsinceinit, h->max_outstanding, h->maxSG); + + pos += size; len += size; + for(i=0; inum_luns; i++) { + drv = &h->drv[i]; + size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n", + ctlr, i, drv->block_size, drv->nr_blocks); + pos += size; len += size; + } + + size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n", + h->nr_allocs, h->nr_frees); + pos += size; len += size; + + *eof = 1; + *start = buffer+offset; + len -= offset; + if (len>length) + len = length; + return len; +} + +/* + * Get us a file in /proc/cciss that says something about each controller. + * Create /proc/cciss if it doesn't exist yet. + */ +static void cciss_procinit(int i) +{ + struct proc_dir_entry *pd; + + if (proc_cciss == NULL) { + proc_cciss = create_proc_entry("cciss", S_IFDIR|S_IRUGO|S_IXUGO, &proc_root); + if (!proc_cciss) + return; + } + + pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_cciss); + if (!pd) + return; + pd->read_proc = cciss_proc_get_info; + pd->data = hba[i]; +} + +/* + * For operations that cannot sleep, a command block is allocated at init, + * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track + * which ones are free or in use. For operations that can wait for kmalloc + * to possible sleep, this routine can be called with a NULL pointer. + * cmd_free() MUST be called with a NULL pointer if cmd_alloc was. + */ +static CommandList_struct * cmd_alloc(ctlr_info_t *h) +{ + CommandList_struct *c; + int i; + u64bit temp64; + + if (h == NULL) + { + c = (CommandList_struct *)kmalloc(sizeof(CommandList_struct), + GFP_KERNEL); + if(c==NULL) + return NULL; + memset(c, 0, sizeof(CommandList_struct)); + + c->err_info = (ErrorInfo_struct *)kmalloc( + sizeof(ErrorInfo_struct), GFP_KERNEL); + + if (c->err_info == NULL) + { + kfree(c); + return NULL; + } + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + } else /* get it out of the controllers pool */ + { + do { + i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS); + if (i == NR_CMDS) + return NULL; + } while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0); +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: using command buffer %d\n", i); +#endif + c = h->cmd_pool + i; + memset(c, 0, sizeof(CommandList_struct)); + c->err_info = h->errinfo_pool + i; + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + h->nr_allocs++; + } + + + temp64.val = (__u64) virt_to_bus(c->err_info); + c->ErrDesc.Addr.lower = temp64.val32.lower; + c->ErrDesc.Addr.upper = temp64.val32.upper; + c->ErrDesc.Len = sizeof(ErrorInfo_struct); + c->busaddr = virt_to_bus(c); + return c; + + +} + +/* + * Frees a command block that was previously allocated with cmd_alloc(). + */ +static void cmd_free(ctlr_info_t *h, CommandList_struct *c) +{ + int i; + + if( h == NULL) + { + kfree(c->err_info); + kfree(c); + } else + { + i = c - h->cmd_pool; + clear_bit(i%32, h->cmd_pool_bits+(i/32)); + h->nr_frees++; + } +} + +/* + * fills in the disk information. + */ +static void cciss_geninit( struct gendisk *g) +{ + int ctlr = -1; + drive_info_struct *drv; + int i,j; + + /* find the controller this gendisk data is from */ + for(i=0; i < nr_ctlr; i++) + { + if ( g == &(hba[i]->gendisk)) + { + ctlr = i; + break; + } + } + if ( ctlr < 0) + { + printk(KERN_WARNING "cciss: gendisk data invalid\n"); + return; + } + /* Loop through each real device */ + g->nr_real = 0; + for(i=0; i< NWD; i++) + { + drv = &(hba[ctlr]->drv[i]); + if( !(drv->nr_blocks)) + continue; + hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = + hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks; + + /* for each partition */ + for(j=0; jblocksizes[(i<hardsizes[ (i<block_size; + } + g->nr_real++; + } +} +/* + * Open. Make sure the device is really there. + */ +static int cciss_open(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk); +#endif /* CCISS_DEBUG */ + + if (ctlr > MAX_CTLR || hba[ctlr] == NULL) + return -ENXIO; + + if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0) + return -ENXIO; + + /* + * Root is allowed to open raw volume zero even if its not configured + * so array config can still work. I don't think I really like this, + * but I'm already using way to many device nodes to claim another one + * for "raw controller". + */ + if (suser() + && (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) + && (MINOR(inode->i_rdev)!= 0)) + return -ENXIO; + + hba[ctlr]->drv[dsk].usage_count++; + hba[ctlr]->usage_count++; + MOD_INC_USE_COUNT; + return 0; +} +/* + * Close. Sync first. + */ +static int cciss_release(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk); +#endif /* CCISS_DEBUG */ + + fsync_dev(inode->i_rdev); + + hba[ctlr]->drv[dsk].usage_count--; + hba[ctlr]->usage_count--; + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * ioctl + */ +static int cciss_ioctl(struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int diskinfo[4]; + struct hd_geometry *geo = (struct hd_geometry *)arg; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg); +#endif /* CCISS_DEBUG */ + + switch(cmd) { + case HDIO_GETGEO: + if (hba[ctlr]->drv[dsk].cylinders) { + diskinfo[0] = hba[ctlr]->drv[dsk].heads; + diskinfo[1] = hba[ctlr]->drv[dsk].sectors; + diskinfo[2] = hba[ctlr]->drv[dsk].cylinders; + } else { + diskinfo[0] = 0xff; + diskinfo[1] = 0x3f; + diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); } + put_user(diskinfo[0], &geo->heads); + put_user(diskinfo[1], &geo->sectors); + put_user(diskinfo[2], &geo->cylinders); + put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect, &geo->start); + return 0; + case BLKGETSIZE: + if (!arg) return -EINVAL; + put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (long*)arg); + return 0; + case BLKRASET: + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!(inode->i_rdev)) return -EINVAL; + if (arg>0xff) return -EINVAL; + read_ahead[MAJOR(inode->i_rdev)] = arg; + return 0; + case BLKRAGET: + if (!arg) return -EINVAL; + put_user(read_ahead[MAJOR(inode->i_rdev)], (int*)arg); + return 0; + case BLKRRPART: + return revalidate_logvol(inode->i_rdev, 1); + + case CCISS_GETPCIINFO: + { + cciss_pci_info_struct pciinfo; + + if (!arg) return -EINVAL; + pciinfo.bus = hba[ctlr]->pci_bus; + pciinfo.dev_fn = hba[ctlr]->pci_dev_fn; + pciinfo.board_id = hba[ctlr]->board_id; + copy_to_user_ret((void *) arg, &pciinfo, + sizeof( cciss_pci_info_struct), -EFAULT); + return(0); + } + case CCISS_GETINTINFO: + { + cciss_coalint_struct intinfo; + ctlr_info_t *c = hba[ctlr]; + + if (!arg) return -EINVAL; + intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay); + intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount); + copy_to_user_ret((void *) arg, &intinfo, + sizeof( cciss_coalint_struct), -EFAULT); + return(0); + } + case CCISS_SETINTINFO: + { + cciss_coalint_struct intinfo; + ctlr_info_t *c = hba[ctlr]; + unsigned long flags; + int i; + + if (!arg) return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; + copy_from_user_ret(&intinfo, (void *) arg, + sizeof( cciss_coalint_struct), -EFAULT); + if ( (intinfo.delay == 0 ) && (intinfo.count == 0)) + + { +// printk("cciss_ioctl: delay and count cannot be 0\n"); + return( -EINVAL); + } + spin_lock_irqsave(&io_request_lock, flags); + /* Can only safely update if no commands outstanding */ + if (c->commands_outstanding > 0 ) + { +// printk("cciss_ioctl: cannot change coalasing " +// "%d commands outstanding on controller\n", +// c->commands_outstanding); + spin_unlock_irqrestore(&io_request_lock, flags); + return(-EINVAL); + } + /* Update the field, and then ring the doorbell */ + writel( intinfo.delay, + &(c->cfgtable->HostWrite.CoalIntDelay)); + writel( intinfo.count, + &(c->cfgtable->HostWrite.CoalIntCount)); + writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); + + for(i=0;ivaddr + SA5_DOORBELL) + & CFGTBL_ChangeReq)) + break; + /* delay and try again */ + udelay(1000); + } + spin_unlock_irqrestore(&io_request_lock, flags); + if (i >= MAX_CONFIG_WAIT) + return( -EFAULT); + return(0); + } + case CCISS_GETNODENAME: + { + NodeName_type NodeName; + ctlr_info_t *c = hba[ctlr]; + int i; + + if (!arg) return -EINVAL; + for(i=0;i<16;i++) + NodeName[i] = readb(&c->cfgtable->ServerName[i]); + copy_to_user_ret((void *) arg, NodeName, + sizeof( NodeName_type), -EFAULT); + return(0); + } + case CCISS_SETNODENAME: + { + NodeName_type NodeName; + ctlr_info_t *c = hba[ctlr]; + unsigned long flags; + int i; + + if (!arg) return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; + + copy_from_user_ret(NodeName, (void *) arg, + sizeof( NodeName_type), -EFAULT); + + spin_lock_irqsave(&io_request_lock, flags); + + /* Update the field, and then ring the doorbell */ + for(i=0;i<16;i++) + writeb( NodeName[i], &c->cfgtable->ServerName[i]); + + writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); + + for(i=0;ivaddr + SA5_DOORBELL) + & CFGTBL_ChangeReq)) + break; + /* delay and try again */ + udelay(1000); + } + spin_unlock_irqrestore(&io_request_lock, flags); + if (i >= MAX_CONFIG_WAIT) + return( -EFAULT); + return(0); + } + + case CCISS_GETHEARTBEAT: + { + Heartbeat_type heartbeat; + ctlr_info_t *c = hba[ctlr]; + + if (!arg) return -EINVAL; + heartbeat = readl(&c->cfgtable->HeartBeat); + copy_to_user_ret((void *) arg, &heartbeat, + sizeof( Heartbeat_type), -EFAULT); + return(0); + } + case CCISS_GETBUSTYPES: + { + BusTypes_type BusTypes; + ctlr_info_t *c = hba[ctlr]; + + if (!arg) return -EINVAL; + BusTypes = readl(&c->cfgtable->BusTypes); + copy_to_user_ret((void *) arg, &BusTypes, + sizeof( BusTypes_type), -EFAULT); + return(0); + } + case CCISS_GETFIRMVER: + { + FirmwareVer_type firmware; + + if (!arg) return -EINVAL; + memcpy(firmware, hba[ctlr]->firm_ver, 4); + + copy_to_user_ret((void *) arg, firmware, + sizeof( FirmwareVer_type), -EFAULT); + return(0); + } + case CCISS_GETDRIVVER: + { + DriverVer_type DriverVer = DRIVER_VERSION; + + if (!arg) return -EINVAL; + + copy_to_user_ret((void *) arg, &DriverVer, + sizeof( DriverVer_type), -EFAULT); + return(0); + } + + case CCISS_REVALIDVOLS: + return( revalidate_allvol(inode->i_rdev)); + + case CCISS_PASSTHRU: + { + IOCTL_Command_struct iocommand; + ctlr_info_t *h = hba[ctlr]; + CommandList_struct *c; + char *buff = NULL; + u64bit temp64; + unsigned long flags; + + if (!arg) return -EINVAL; + + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + + copy_from_user_ret(&iocommand, (void *) arg, + sizeof( IOCTL_Command_struct), -EFAULT); + if((iocommand.buf_size < 1) && + (iocommand.Request.Type.Direction != XFER_NONE)) + { + return -EINVAL; + } + /* Check kmalloc limits */ + if(iocommand.buf_size > 128000) + return -EINVAL; + if(iocommand.buf_size > 0) + { + buff = kmalloc(iocommand.buf_size, GFP_KERNEL); + if( buff == NULL) + return -EFAULT; + } + if (iocommand.Request.Type.Direction == XFER_WRITE) + { + /* Copy the data into the buffer we created */ + copy_from_user_ret(buff, iocommand.buf, + iocommand.buf_size, -EFAULT); + } + if ((c = cmd_alloc(NULL)) == NULL) + { + if(buff!=NULL) + kfree(buff); + return -ENOMEM; + } + // Fill in the command type + c->cmd_type = CMD_IOCTL_PEND; + // Fill in Command Header + c->Header.ReplyQueue = 0; // unused in simple mode + if( iocommand.buf_size > 0) // buffer to fill + { + c->Header.SGList = 1; + c->Header.SGTotal= 1; + } else // no buffers to fill + { + c->Header.SGList = 0; + c->Header.SGTotal= 0; + } + c->Header.LUN = iocommand.LUN_info; + c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag + + // Fill in Request block + c->Request = iocommand.Request; + + // Fill in the scatter gather information + if (iocommand.buf_size > 0 ) + { + temp64.val = (__u64) virt_to_bus(buff); + c->SG[0].Addr.lower = temp64.val32.lower; + c->SG[0].Addr.upper = temp64.val32.upper; + c->SG[0].Len = iocommand.buf_size; + c->SG[0].Ext = 0; // we are not chaining + } + /* Put the request on the tail of the request queue */ + spin_lock_irqsave(&io_request_lock, flags); + addQ(&h->reqQ, c); + h->Qdepth++; + start_io(h); + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Wait for completion */ + while(c->cmd_type != CMD_IOCTL_DONE) + { + schedule_timeout(1); + rmb(); + } + + /* Copy the error information out */ + iocommand.error_info = *(c->err_info); + if ( copy_to_user((void *) arg, &iocommand, + sizeof( IOCTL_Command_struct) ) < 0 ) + { + cmd_free(NULL, c); + if (buff != NULL) + kfree(buff); + return( -EFAULT); + } + + if (iocommand.Request.Type.Direction == XFER_READ) + { + /* Copy the data out of the buffer we created */ + if (copy_to_user(iocommand.buf, buff, + iocommand.buf_size) < 0) + { + cmd_free(NULL, c); + kfree(buff); + } + } + cmd_free(NULL, c); + if (buff != NULL) + kfree(buff); + return(0); + } + + RO_IOCTLS(inode->i_rdev, arg); + + default: + return -EBADRQC; + } + +} + +/* Borrowed and adapted from sd.c */ +static int revalidate_logvol(kdev_t dev, int maxusage) +{ + int ctlr, target; + struct gendisk *gdev; + unsigned long flags; + int max_p; + int start; + int i; + + target = MINOR(dev) >> NWD_SHIFT; + ctlr = MAJOR(dev) - MAJOR_NR; + gdev = &(hba[ctlr]->gendisk); + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->drv[target].usage_count > maxusage) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk(KERN_WARNING "cpqarray: Device busy for " + "revalidation (usage=%d)\n", + hba[ctlr]->drv[target].usage_count); + return -EBUSY; + } + hba[ctlr]->drv[target].usage_count++; + spin_unlock_irqrestore(&io_request_lock, flags); + + max_p = gdev->max_p; + start = target << gdev->minor_shift; + + for(i=max_p; i>=0; i--) { + int minor = start+i; + kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); + struct super_block *sb = get_super(devi); + sync_dev(devi); + if (sb) invalidate_inodes(sb); + invalidate_buffers(devi); + gdev->part[minor].start_sect = 0; + gdev->part[minor].nr_sects = 0; + + /* reset the blocksize so we can read the partition table */ + blksize_size[MAJOR_NR+ctlr][minor] = 1024; + } + gdev->part[start].nr_sects = hba[ctlr]->drv[target].nr_blocks; + resetup_one_dev(gdev, target); + hba[ctlr]->drv[target].usage_count--; + return 0; +} + +static int frevalidate_logvol(kdev_t dev) +{ +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: frevalidate has been called\n"); +#endif /* CCISS_DEBUG */ + return revalidate_logvol(dev, 0); +} + +/* + * revalidate_allvol is for online array config utilities. After a + * utility reconfigures the drives in the array, it can use this function + * (through an ioctl) to make the driver zap any previous disk structs for + * that controller and get new ones. + * + * Right now I'm using the getgeometry() function to do this, but this + * function should probably be finer grained and allow you to revalidate one + * particualar logical volume (instead of all of them on a particular + * controller). + */ +static int revalidate_allvol(kdev_t dev) +{ + int ctlr, i; + unsigned long flags; + + ctlr = MAJOR(dev) - MAJOR_NR; + if (MINOR(dev) != 0) + return -ENXIO; + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->usage_count > 1) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk(KERN_WARNING "cciss: Device busy for volume" + " revalidation (usage=%d)\n", hba[ctlr]->usage_count); + return -EBUSY; + } + spin_unlock_irqrestore(&io_request_lock, flags); + hba[ctlr]->usage_count++; + + /* + * Set the partition and block size structures for all volumes + * on this controller to zero. We will reread all of this data + */ + memset(hba[ctlr]->hd, 0, sizeof(struct hd_struct) * 256); + memset(hba[ctlr]->sizes, 0, sizeof(int) * 256); + memset(hba[ctlr]->blocksizes, 0, sizeof(int) * 256); + memset(hba[ctlr]->hardsizes, 0, sizeof(int) * 256); + memset(hba[ctlr]->drv, 0, sizeof(drive_info_struct) + * CISS_MAX_LUN); + hba[ctlr]->gendisk.nr_real = 0; + + /* + * Tell the array controller not to give us any interupts while + * we check the new geometry. Then turn interrupts back on when + * we're done. + */ + hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_OFF); + cciss_getgeometry(ctlr); + hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON); + + cciss_geninit(&(hba[ctlr]->gendisk)); + for(i=0; isizes[ i<usage_count--; + return 0; +} + + + +/* + * Wait polling for a command to complete. + * The memory mapped FIFO is polled for the completion. + * Used only at init time, interrupts disabled. + */ +static unsigned long pollcomplete(int ctlr) +{ + unsigned long done; + int i; + + /* Wait (up to 2 seconds) for a command to complete */ + + for (i = 200000; i > 0; i--) { + done = hba[ctlr]->access.command_completed(hba[ctlr]); + if (done == FIFO_EMPTY) { + udelay(10); /* a short fixed delay */ + } else + return (done); + } + /* Invalid address to tell caller we ran out of time */ + return 1; +} +/* + * Send a command to the controller, and wait for it to complete. + * Only used at init time. + */ +static int sendcmd( + __u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int use_unit_num, + unsigned int log_unit, + __u8 page_code ) +{ + CommandList_struct *c; + int i; + unsigned long complete; + ctlr_info_t *info_p= hba[ctlr]; + u64bit temp64; + + c = cmd_alloc(info_p); + if (c == NULL) + { + printk(KERN_WARNING "cciss: unable to get memory"); + return(IO_ERROR); + } + // Fill in Command Header + c->Header.ReplyQueue = 0; // unused in simple mode + if( buff != NULL) // buffer to fill + { + c->Header.SGList = 1; + c->Header.SGTotal= 1; + } else // no buffers to fill + { + c->Header.SGList = 0; + c->Header.SGTotal= 0; + } + c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag + // Fill in Request block + switch(cmd) + { + case CISS_INQUIRY: + /* If the logical unit number is 0 then, this is going + to controller so It's a physical command + mode = 0 target = 0. + So we have nothing to write. + Otherwise + mode = 1 target = LUNID + */ + if(use_unit_num != 0) + { + c->Header.LUN.LogDev.VolId= + hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + } + /* are we trying to read a vital product page */ + if(page_code != 0) + { + c->Request.CDB[1] = 0x01; + c->Request.CDB[2] = page_code; + } + c->Request.CDBLen = 6; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CISS_INQUIRY; + c->Request.CDB[4] = size & 0xFF; + break; + case CISS_REPORT_LOG: + /* Talking to controller so It's a physical command + mode = 00 target = 0. + So we have nothing to write. + */ + c->Request.CDBLen = 12; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CISS_REPORT_LOG; + c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0xFF; + c->Request.CDB[9] = size & 0xFF; + break; + + case CCISS_READ_CAPACITY: + c->Header.LUN.LogDev.VolId= + hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + c->Request.CDBLen = 10; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CCISS_READ_CAPACITY; + break; + default: + printk(KERN_WARNING + "cciss: Unknown Command 0x%c sent attempted\n", + cmd); + cmd_free(info_p, c); + return(IO_ERROR); + }; + // Fill in the scatter gather information + if (size > 0 ) + { + temp64.val = (__u64) virt_to_bus(buff); + c->SG[0].Addr.lower = temp64.val32.lower; + c->SG[0].Addr.upper = temp64.val32.upper; + c->SG[0].Len = size; + c->SG[0].Ext = 0; // we are not chaining + } + /* + * Disable interrupt + */ +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: turning intr off\n"); +#endif /* CCISS_DEBUG */ + info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); + + /* Make sure there is room in the command FIFO */ + /* Actually it should be completely empty at this time. */ + for (i = 200000; i > 0; i--) + { + /* if fifo isn't full go */ + if (!(info_p->access.fifo_full(info_p))) + { + + break; + } + udelay(10); + printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," + " waiting!\n", ctlr); + } + /* + * Send the cmd + */ + info_p->access.submit_command(info_p, c); + complete = pollcomplete(ctlr); + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: command completed\n"); +#endif /* CCISS_DEBUG */ + + if (complete != 1) { + if ( (complete & CISS_ERROR_BIT) + && (complete & ~CISS_ERROR_BIT) == c->busaddr) + { + /* if data overrun or underun on Report command + ignore it + */ + if (((c->Request.CDB[0] == CISS_REPORT_LOG) || + (c->Request.CDB[0] == CISS_INQUIRY)) && + ((c->err_info->CommandStatus == + CMD_DATA_OVERRUN) || + (c->err_info->CommandStatus == + CMD_DATA_UNDERRUN) + )) + { + complete = c->busaddr; + } else + { + printk(KERN_WARNING "ciss ciss%d: sendcmd" + " Error %x \n", ctlr, + c->err_info->CommandStatus); + printk(KERN_WARNING "ciss ciss%d: sendcmd" + " offensive info\n" + " size %x\n num %x value %x\n", ctlr, + c->err_info->MoreErrInfo.Invalid_Cmd.offense_size, + c->err_info->MoreErrInfo.Invalid_Cmd.offense_num, + c->err_info->MoreErrInfo.Invalid_Cmd.offense_value); + cmd_free(info_p,c); + return(IO_ERROR); + } + } + if (complete != c->busaddr) { + printk( KERN_WARNING "cciss cciss%d: SendCmd " + "Invalid command list address returned! (%lx)\n", + ctlr, complete); + cmd_free(info_p, c); + return (IO_ERROR); + } + } else { + printk( KERN_WARNING + "cciss cciss%d: SendCmd Timeout out, " + "No command list address returned!\n", + ctlr); + cmd_free(info_p, c); + return (IO_ERROR); + } + cmd_free(info_p, c); + return (IO_OK); +} +/* + * Map (physical) PCI mem into (virtual) kernel space + */ +static ulong remap_pci_mem(ulong base, ulong size) +{ + ulong page_base = ((ulong) base) & PAGE_MASK; + ulong page_offs = ((ulong) base) - page_base; + ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + + return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); +} + +/* + * Enqueuing and dequeuing functions for cmdlists. + */ +static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) +{ + if (*Qptr == NULL) { + *Qptr = c; + c->next = c->prev = c; + } else { + c->prev = (*Qptr)->prev; + c->next = (*Qptr); + (*Qptr)->prev->next = c; + (*Qptr)->prev = c; + } +} + +static inline CommandList_struct *removeQ(CommandList_struct **Qptr, + CommandList_struct *c) +{ + if (c && c->next != c) { + if (*Qptr == c) *Qptr = c->next; + c->prev->next = c->next; + c->next->prev = c->prev; + } else { + *Qptr = NULL; + } + return c; +} + +/* + * Takes jobs of the Q and sends them to the hardware, then puts it on + * the Q to wait for completion. + */ +static void start_io( ctlr_info_t *h) +{ + CommandList_struct *c; + + while(( c = h->reqQ) != NULL ) + { + /* can't do anything if fifo is full */ + if ((h->access.fifo_full(h))) + { + printk(KERN_WARNING "cciss: fifo full \n"); + return; + } + /* Get the frist entry from the Request Q */ + removeQ(&(h->reqQ), c); + h->Qdepth--; + + /* Tell the controller execute command */ + h->access.submit_command(h, c); + + /* Put job onto the completed Q */ + addQ (&(h->cmpQ), c); + } +} + +static inline void complete_buffers( struct buffer_head *bh, int status) +{ + struct buffer_head *xbh; + + while(bh) + { + xbh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, status); + bh = xbh; + } +} +/* checks the status of the job and calls complete buffers to mark all + * buffers for the completed job. + */ +static inline void complete_command( CommandList_struct *cmd, int timeout) +{ + int status = 1; + + if (timeout) + status = 0; + if(cmd->err_info->CommandStatus != 0) + { /* an error has occured */ + switch(cmd->err_info->CommandStatus) + { + case CMD_TARGET_STATUS: + printk(KERN_WARNING "cciss: cmd %p has " + " completed with errors\n", cmd); + if( cmd->err_info->ScsiStatus) + { + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status = %x\n", + cmd, + cmd->err_info->ScsiStatus); + } + + break; + case CMD_DATA_UNDERRUN: + printk(KERN_WARNING "cciss: cmd %p has" + " completed with data underrun " + "reported\n", cmd); + break; + case CMD_DATA_OVERRUN: + printk(KERN_WARNING "cciss: cmd %p has" + " completed with data overrun " + "reported\n", cmd); + break; + case CMD_INVALID: + printk(KERN_WARNING "cciss: cmd %p is " + "reported invalid\n", cmd); + status = 0; + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cmd %p has " + "protocol error \n", cmd); + status = 0; + break; + case CMD_HARDWARE_ERR: + printk(KERN_WARNING "cciss: cmd %p had " + " hardware error\n", cmd); + status = 0; + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cmd %p had " + "connection lost\n", cmd); + status=0; + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cmd %p was " + "aborted\n", cmd); + status=0; + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cmd %p reports " + "abort failed\n", cmd); + status=0; + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING "cciss: cmd %p aborted " + "do to an unsolicited abort\n", cmd); + status=0; + break; + case CMD_TIMEOUT: + printk(KERN_WARNING "cciss: cmd %p timedout\n", + cmd); + status=0; + break; + default: + printk(KERN_WARNING "cciss: cmd %p returned " + "unknown status %x\n", cmd, + cmd->err_info->CommandStatus); + status=0; + } + } + complete_buffers(cmd->bh, status); +} +/* + * Get a request and submit it to the controller. + * Currently we do one request at a time. Ideally we would like to send + * everything to the controller on the first call, but there is a danger + * of holding the io_request_lock for to long. + */ +static void do_cciss_request(int ctlr) +{ + ctlr_info_t *h= hba[ctlr]; + CommandList_struct *c; + int log_unit, start_blk, seg, sect; + char *lastdataend; + struct buffer_head *bh; + struct request *creq; + u64bit temp64; + + /* loop till creq is null or current_request is inactive */ + creq = blk_dev[MAJOR_NR+ctlr].current_request; + if ((creq == NULL) || (creq->rq_status == RQ_INACTIVE)) + { + /* nothing to do... restart processing and return */ + start_io(h); + return; + } + if ((ctlr != (MAJOR(creq->rq_dev)-MAJOR_NR)) || (ctlr > nr_ctlr) + || (h == NULL)) + { +#ifdef CCISS_DEBUG + printk(KERN_WARNING "cciss: doreq cmd of %d, %x at %p\n", + ctlr, creq->rq_dev, creq); +#endif /* CCISS_DEBUG */ + complete_buffers(creq->bh, 0); + return; + } + if (( c = cmd_alloc(h)) == NULL) + { + start_io(h); + return; + } + c->cmd_type = CMD_RWREQ; + bh = c->bh = creq->bh; + + /* fill in the request */ + log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; + c->Header.ReplyQueue = 0; // unused in simple mode + c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag + c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + c->Request.CDBLen = 10; // 12 byte commands not in FW yet; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = + (creq->cmd == READ) ? XFER_READ: XFER_WRITE; + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE; + start_blk = hba[ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector; + if (bh == NULL) + panic("cciss: bh== NULL?"); +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector, + (int) creq->nr_sectors); +#endif /* CCISS_DEBUG */ + seg = 0; + lastdataend = NULL; + sect = 0; + while(bh) + { + sect += bh->b_size/512; + if (bh->b_size % 512) + { + printk(KERN_CRIT "cciss: Oh Man. %d+%d, size=%d\n", + (int) creq->sector, sect, (int) bh->b_size); + panic("b_size 512 != 0\n"); + } + if (bh->b_data == lastdataend) + { // tack it on to the last segment + c->SG[seg-1].Len +=bh->b_size; + lastdataend += bh->b_size; + } else + { + c->SG[seg].Len = bh->b_size; + temp64.val = (__u64) virt_to_bus(bh->b_data); + c->SG[seg].Addr.lower = temp64.val32.lower; + c->SG[seg].Addr.upper = temp64.val32.upper; + c->SG[0].Ext = 0; // we are not chaining + lastdataend = bh->b_data + bh->b_size; + if( ++seg == MAXSGENTRIES) + { + break; + } + } + bh = bh->b_reqnext; + } + /* track how many SG entries we are using */ + if( seg > h->maxSG) + h->maxSG = seg; + + /* adjusting the remaining request, if any */ + creq-> sector+= sect; + creq->nr_sectors -= sect; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", sect, seg); +#endif /* CCISS_DEBUG */ + + c->Header.SGList = c->Header.SGTotal = seg; + c->Request.CDB[1]= 0; + c->Request.CDB[2]= (start_blk >> 24) & 0xff; //MSB + c->Request.CDB[3]= (start_blk >> 16) & 0xff; + c->Request.CDB[4]= (start_blk >> 8) & 0xff; + c->Request.CDB[5]= start_blk & 0xff; + c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB + // c->Request.CDB[7]= (sect >> 16) & 0xff; + c->Request.CDB[7]= (sect >> 8) & 0xff; + c->Request.CDB[8]= sect & 0xff; + c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; + + /* check to see if we going to complete the entire request */ + /* if so, mark this request as Done and ready the next one */ + if (creq->nr_sectors) + { +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: More to do on the same request %p %ld\n", + creq, creq->nr_sectors); +#endif /* CCISS_DEBUG */ + + creq->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + } else + { +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: Done with %p, queueing %p\n", creq, creq->next); +#endif /* CCISS_DEBUG */ + + creq->rq_status = RQ_INACTIVE; + blk_dev[MAJOR_NR+ctlr].current_request = creq->next; + wake_up(&wait_for_request); + } + addQ(&(h->reqQ),c); + h->Qdepth++; + if(h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; + start_io(h); +} + +static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + ctlr_info_t *h = dev_id; + CommandList_struct *c; + unsigned long flags; + __u32 a, a1; + + + /* Is this interrupt for us? */ + if ( h->access.intr_pending(h) == 0) + return; + + /* + * If there are completed commands in the completion queue, + * we had better do something about it. + */ + spin_lock_irqsave(&io_request_lock, flags); + while( h->access.intr_pending(h)) + { + while((a = h->access.command_completed(h)) != FIFO_EMPTY) + { + a1 = a; + a &= ~3; + if ((c = h->cmpQ) == NULL) + { + printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1); + continue; + } + while(c->busaddr != a) { + c = c->next; + if (c == h->cmpQ) + break; + } + /* + * If we've found the command, take it off the + * completion Q and free it + */ + if (c->busaddr == a) { + removeQ(&h->cmpQ, c); + if (c->cmd_type == CMD_RWREQ) { + complete_command(c, 0); + cmd_free(h, c); + } else if (c->cmd_type == CMD_IOCTL_PEND) { + c->cmd_type = CMD_IOCTL_DONE; + } + continue; + } + } + } + /* + * See if we can queue up some more IO + */ + do_cciss_request(h->ctlr); + spin_unlock_irqrestore(&io_request_lock, flags); +} +/* + * We cannot read the structure directly, for portablity we must use + * the io functions. + * This is for debug only. + */ +#ifdef CCISS_DEBUG +static void print_cfg_table( CfgTable_struct *tb) +{ + int i; + char temp_name[17]; + + printk("Controller Configuration information\n"); + printk("------------------------------------\n"); + for(i=0;i<4;i++) + temp_name[i] = readb(&(tb->Signature[i])); + temp_name[4]='\0'; + printk(" Signature = %s\n", temp_name); + printk(" Spec Number = %d\n", readl(&(tb->SpecValence))); + printk(" Transport methods supported = 0x%x\n", + readl(&(tb-> TransportSupport))); + printk(" Transport methods active = 0x%x\n", + readl(&(tb->TransportActive))); + printk(" Requested transport Method = 0x%x\n", + readl(&(tb->HostWrite.TransportRequest))); + printk(" Coalese Interrupt Delay = 0x%x\n", + readl(&(tb->HostWrite.CoalIntDelay))); + printk(" Coalese Interrupt Count = 0x%x\n", + readl(&(tb->HostWrite.CoalIntCount))); + printk(" Max outstanding commands = 0x%d\n", + readl(&(tb->CmdsOutMax))); + printk(" Bus Types = 0x%x\n", readl(&(tb-> BusTypes))); + for(i=0;i<16;i++) + temp_name[i] = readb(&(tb->ServerName[i])); + temp_name[16] = '\0'; + printk(" Server Name = %s\n", temp_name); + printk(" Heartbeat Counter = 0x%x\n\n\n", + readl(&(tb->HeartBeat))); +} +#endif /* CCISS_DEBUG */ + +static int cciss_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) +{ + ushort vendor_id, device_id, command; + unchar cache_line_size, latency_timer; + unchar irq, revision; + uint addr[6]; + __u32 board_id; + struct pci_dev *pdev; + + int i; + + pdev = pci_find_slot(bus, device_fn); + vendor_id = pdev->vendor; + device_id = pdev->device; + irq = pdev->irq; + + for(i=0; i<6; i++) + addr[i] = pdev->base_address[i]; + (void) pcibios_read_config_word(bus, device_fn, + PCI_COMMAND,&command); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_CLASS_REVISION,&revision); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_CACHE_LINE_SIZE, &cache_line_size); + (void) pcibios_read_config_byte(bus, device_fn, + PCI_LATENCY_TIMER, &latency_timer); + + (void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id); + +#ifdef CCISS_DEBUG + printk("vendor_id = %x\n", vendor_id); + printk("device_id = %x\n", device_id); + printk("command = %x\n", command); + for(i=0; i<6; i++) + printk("addr[%d] = %x\n", i, addr[i]); + printk("revision = %x\n", revision); + printk("irq = %x\n", irq); + printk("cache_line_size = %x\n", cache_line_size); + printk("latency_timer = %x\n", latency_timer); + printk("board_id = %x\n", board_id); +#endif /* CCISS_DEBUG */ + + c->intr = irq; + + /* + * Memory base addr is first addr , the second points to the config + * table + */ + c->paddr = addr[0]; + c->vaddr = remap_pci_mem(c->paddr, 128); + c->cfgtable = (CfgTable_struct *) remap_pci_mem(addr[1], + sizeof(CfgTable_struct)); + c->board_id = board_id; + +#ifdef CCISS_DEBUG + print_cfg_table(c->cfgtable); +#endif /* CCISS_DEBUG */ + for(i=0; iproduct_name = products[i].product_name; + c->access = *(products[i].access); + break; + } + } + if (i == NR_PRODUCTS) { + printk(KERN_WARNING "cciss: Sorry, I don't know how" + " to access the Smart Array controller %08lx\n", + (unsigned long)board_id); + return -1; + } +#ifdef CCISS_DEBUG + printk("Trying to put board into Simple mode\n"); +#endif /* CCISS_DEBUG */ + c->max_commands = readl(&(c->cfgtable->CmdsOutMax)); + /* Update the field, and then ring the doorbell */ + writel( CFGTBL_Trans_Simple, + &(c->cfgtable->HostWrite.TransportRequest)); + writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); + + for(i=0;ivaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) + break; + /* delay and try again */ + udelay(1000); + } + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL)); +#endif /* CCISS_DEBUG */ +#ifdef CCISS_DEBUG + print_cfg_table(c->cfgtable); +#endif /* CCISS_DEBUG */ + + if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) + { + printk(KERN_WARNING "cciss: unable to get board into" + " simple mode\n"); + return -1; + } + return 0; + +} +/* + * Scans PCI space for any controllers that this driver can control. + */ +static int cciss_pci_detect(void) +{ + + int index; + unchar bus=0, dev_fn=0; + + for(index=0; ; index++) { + if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_COMPAQ_CISS, + index, &bus, &dev_fn)) + break; + printk(KERN_DEBUG "cciss: Device %x has been found at %x %x\n", + PCI_DEVICE_ID_COMPAQ_CISS, bus, dev_fn); + if (index == 1000000) break; + if (nr_ctlr == 8) { + printk(KERN_WARNING "cciss: This driver" + " supports a maximum of 8 controllers.\n"); + break; + } + hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); + if(hba[nr_ctlr]==NULL) + { + printk(KERN_ERR "cciss: out of memory.\n"); + continue; + } + memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); + if (cciss_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) + { + kfree(hba[nr_ctlr]); + continue; + } + sprintf(hba[nr_ctlr]->devname, "cciss%d", nr_ctlr); + hba[nr_ctlr]->ctlr = nr_ctlr; + hba[nr_ctlr]->pci_bus = bus; + hba[nr_ctlr]->pci_dev_fn = dev_fn; + nr_ctlr++; + + } + return nr_ctlr; + +} + +/* + * Gets information about the local volumes attached to the controller. + */ +static void cciss_getgeometry(int cntl_num) +{ + ReportLunData_struct *ld_buff; + ReadCapdata_struct *size_buff; + InquiryData_struct *inq_buff; + int return_code; + int i; + int listlength = 0; + int lunid = 0; + int block_size; + int total_size; + + ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL); + if (ld_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + return; + } + memset(ld_buff, 0, sizeof(ReportLunData_struct)); + size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); + if (size_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + return; + } + inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + kfree(size_buff); + return; + } + /* Get the firmware version */ + return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, + sizeof(InquiryData_struct), 0, 0 ,0 ); + if (return_code == IO_OK) + { + hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32]; + hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33]; + hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34]; + hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35]; + } else /* send command failed */ + { + printk(KERN_WARNING "cciss: unable to determine firmware" + " version of controller\n"); + } + /* Get the number of logical volumes */ + return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, + sizeof(ReportLunData_struct), 0, 0, 0 ); + + if( return_code == IO_OK) + { +#ifdef CCISS_DEBUG + printk("LUN Data\n--------------------------\n"); +#endif /* CCISS_DEBUG */ + + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; + listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); + } else /* reading number of logical volumes failed */ + { + printk(KERN_WARNING "cciss: report logical volume" + " command failed\n"); + listlength = 0; + } + hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry + if (hba[cntl_num]->num_luns > CISS_MAX_LUN) + { + printk(KERN_ERR "ciss: only %d number of logical volumes supported\n", + CISS_MAX_LUN); + hba[cntl_num]->num_luns = CISS_MAX_LUN; + } +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0], + ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], + ld_buff->LUNListLength[3], hba[cntl_num]->num_luns); +#endif /* CCISS_DEBUG */ + for(i=0; i< hba[cntl_num]->num_luns ; i++) + { + lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; + lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); + hba[cntl_num]->drv[i].LunID = lunid; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, + ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], + ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID); +#endif /* CCISS_DEBUG */ + + memset(size_buff, 0, sizeof(ReadCapdata_struct)); + return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, + sizeof( ReadCapdata_struct), 1, i, 0 ); + if (return_code == IO_OK) + { + total_size = (0xff & + (unsigned int)(size_buff->total_size[0])) << 24; + total_size |= (0xff & + (unsigned int)(size_buff->total_size[1])) << 16; + total_size |= (0xff & + (unsigned int)(size_buff->total_size[2])) << 8; + total_size |= (0xff & (unsigned int) + (size_buff->total_size[3])); + total_size++; // command returns highest block address + + block_size = (0xff & + (unsigned int)(size_buff->block_size[0])) << 24; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[1])) << 16; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[2])) << 8; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[3])); + } else /* read capacity command failed */ + { + printk(KERN_WARNING "cciss: read capacity failed\n"); + total_size = block_size = 0; + } + printk(" blocks= %d block_size= %d\n", total_size, + block_size); + + /* Execute the command to read the disk geometry */ + memset(inq_buff, 0, sizeof(InquiryData_struct)); + return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, + sizeof(InquiryData_struct), 1, i ,0xC1 ); + if (return_code == IO_OK) + { + if(inq_buff->data_byte[8] == 0xFF) + { + printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n"); + + hba[cntl_num]->drv[i].block_size = block_size; + hba[cntl_num]->drv[i].nr_blocks = total_size; + hba[cntl_num]->drv[i].heads = 255; + hba[cntl_num]->drv[i].sectors = 32; // Sectors per track + hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; } else + { + + hba[cntl_num]->drv[i].block_size = block_size; + hba[cntl_num]->drv[i].nr_blocks = total_size; + hba[cntl_num]->drv[i].heads = + inq_buff->data_byte[6]; + hba[cntl_num]->drv[i].sectors = + inq_buff->data_byte[7]; + hba[cntl_num]->drv[i].cylinders = + (inq_buff->data_byte[4] & 0xff) << 8; + hba[cntl_num]->drv[i].cylinders += + inq_buff->data_byte[5]; + } + } + else /* Get geometry failed */ + { + printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); + + hba[cntl_num]->drv[i].block_size = block_size; + hba[cntl_num]->drv[i].nr_blocks = total_size; + hba[cntl_num]->drv[i].heads = 255; + hba[cntl_num]->drv[i].sectors = 32; // Sectors per track + hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; + } + printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", + hba[cntl_num]->drv[i].heads, + hba[cntl_num]->drv[i].sectors, + hba[cntl_num]->drv[i].cylinders); + + } + kfree(ld_buff); + kfree(size_buff); +} + +/* + * This is it. Find all the controllers and register them. I really hate + * stealing all these major device numbers. + * returns the number of block devices registered. + */ +int cciss_init(void) +{ + int num_cntlrs_reg = 0; + int i; + + void (*request_fns[MAX_CTLR])(void) = { + do_cciss_request0, do_cciss_request1, + do_cciss_request2, do_cciss_request3, + do_cciss_request4, do_cciss_request5, + do_cciss_request6, do_cciss_request7, + }; + + /* detect controllers */ + cciss_pci_detect(); + + if (nr_ctlr == 0) + return(num_cntlrs_reg); + + printk(KERN_INFO DRIVER_NAME "\n"); + printk(KERN_INFO "Found %d controller(s)\n", nr_ctlr); + for(i=0;idevname, &cciss_fops)) + { + printk(KERN_ERR "cciss: Unable to get major number " + "%d for %s\n", MAJOR_NR+i, hba[i]->devname); + continue; + } + /* make sure the board interrupts are off */ + hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); + if( request_irq(hba[i]->intr, do_cciss_intr, + SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM, + hba[i]->devname, hba[i])) + { + printk(KERN_ERR "ciss: Unable to get irq %d for %s\n", + hba[i]->intr, hba[i]->devname); + unregister_blkdev( MAJOR_NR+i, hba[i]->devname); + continue; + } + num_cntlrs_reg++; + hba[i]->cmd_pool_bits = (__u32*)kmalloc( + ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); + hba[i]->cmd_pool = (CommandList_struct *)kmalloc( + NR_CMDS * sizeof(CommandList_struct), + GFP_KERNEL); + hba[i]->errinfo_pool = (ErrorInfo_struct *)kmalloc( + NR_CMDS * sizeof( ErrorInfo_struct), + GFP_KERNEL); + if((hba[i]->cmd_pool_bits == NULL) + || (hba[i]->cmd_pool == NULL) + || (hba[i]->errinfo_pool == NULL)) + { + nr_ctlr = i; + if(hba[i]->cmd_pool_bits) + kfree(hba[i]->cmd_pool_bits); + if(hba[i]->cmd_pool) + kfree(hba[i]->cmd_pool); + if(hba[i]->errinfo_pool) + kfree(hba[i]->errinfo_pool); + free_irq(hba[i]->intr, hba[i]); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + num_cntlrs_reg--; + printk( KERN_ERR "cciss: out of memory"); + return(num_cntlrs_reg); + } + + /* command and error info recs zeroed out before + they are used */ + memset(hba[i]->cmd_pool_bits, 0, + ((NR_CMDS+31)/32)*sizeof(__u32)); + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i); +#endif /* CCISS_DEBUG */ + + cciss_getgeometry(i); + + /* Turn the interrupts on so we can service requests */ + hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); + + cciss_procinit(i); + /* Fill in the gendisk data */ + hba[i]->gendisk.major = MAJOR_NR + i; + hba[i]->gendisk.major_name = "cciss"; + hba[i]->gendisk.minor_shift = NWD_SHIFT; + hba[i]->gendisk.max_p = MAX_PART; + hba[i]->gendisk.max_nr = NWD; + hba[i]->gendisk.init = cciss_geninit; + hba[i]->gendisk.part = hba[i]->hd; + hba[i]->gendisk.sizes = hba[i]->sizes; + hba[i]->gendisk.nr_real = hba[i]->num_luns; + + /* fill in the other Kernel structs */ + blk_dev[MAJOR_NR+i].request_fn = request_fns[i]; + blksize_size[MAJOR_NR+i] = hba[i]->blocksizes; + hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes; + read_ahead[MAJOR_NR+i] = READ_AHEAD; + + /* Get on the disk list */ + hba[i]->gendisk.next = gendisk_head; + gendisk_head = &(hba[i]->gendisk); + } + return(nr_ctlr); +} + +#ifdef MODULE +EXPORT_NO_SYMBOLS; + + +/* This is a bit of a hack... */ +int init_module(void) +{ + int i,j; + + if (cciss_init() == 0) /* all the block dev numbers already used */ + return -EIO; /* or no controllers were found */ + for(i=0; igendisk)); + for(j=0; jsizes[j<gendisk), j); + } + } + return 0; +} +void cleanup_module(void) +{ + int i; + struct gendisk *g; + + for(i=0; iaccess.set_intr_mask(hba[i], CCISS_INTR_OFF); + free_irq(hba[i]->intr, hba[i]); + iounmap((void*)hba[i]->vaddr); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + remove_proc_entry(hba[i]->devname, proc_cciss); + + /* remove it from the disk list */ + if (gendisk_head == &(hba[i]->gendisk)) + { + gendisk_head = hba[i]->gendisk.next; + } else + { + for(g=gendisk_head; g ; g=g->next) + { + if(g->next == &(hba[i]->gendisk)) + { + g->next = hba[i]->gendisk.next; + } + } + } + remove_proc_entry("cciss", &proc_root); + kfree(hba[i]->cmd_pool); + kfree(hba[i]->errinfo_pool); + kfree(hba[i]->cmd_pool_bits); + kfree(hba[i]); + } +} + +#endif /* MODULE */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/cciss.h linux/drivers/block/cciss.h --- v2.2.17/drivers/block/cciss.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/cciss.h Wed Nov 8 23:19:44 2000 @@ -0,0 +1,201 @@ +#ifndef CCISS_H +#define CCISS_H + +#include + +#include "cciss_cmd.h" + + +#define NWD 16 +#define NWD_SHIFT 4 +#define MAX_PART 16 + +#define IO_OK 0 +#define IO_ERROR 1 + +#define MAJOR_NR COMPAQ_CISS_MAJOR + +struct ctlr_info; +typedef struct ctlr_info ctlr_info_t; + +struct access_method { + void (*submit_command)(ctlr_info_t *h, CommandList_struct *c); + void (*set_intr_mask)(ctlr_info_t *h, unsigned long val); + unsigned long (*fifo_full)(ctlr_info_t *h); + unsigned long (*intr_pending)(ctlr_info_t *h); + unsigned long (*command_completed)(ctlr_info_t *h); +}; +typedef struct _drive_info_struct +{ + __u32 LunID; + int usage_count; + int nr_blocks; + int block_size; + int heads; + int sectors; + int cylinders; +} drive_info_struct; + +struct ctlr_info +{ + int ctlr; + char devname[8]; + char *product_name; + char firm_ver[4]; // Firmware version + unchar pci_bus; + unchar pci_dev_fn; + __u32 board_id; + __u32 vaddr; + __u32 paddr; + CfgTable_struct *cfgtable; + int intr; + + int max_commands; + int commands_outstanding; + int max_outstanding; /* Debug */ + int num_luns; + int usage_count; /* number of opens all all minor devices */ + + // information about each logical volume + drive_info_struct drv[CISS_MAX_LUN]; + + struct access_method access; + + /* queue and queue Info */ + CommandList_struct *reqQ; + CommandList_struct *cmpQ; + unsigned int Qdepth; + unsigned int maxQsinceinit; + unsigned int maxSG; + + //* pointers to command and error info pool */ + CommandList_struct *cmd_pool; + ErrorInfo_struct *errinfo_pool; + __u32 *cmd_pool_bits; + int nr_allocs; + int nr_frees; + + // Disk structures we need to pass back + struct gendisk gendisk; + // indexed by minor numbers + struct hd_struct hd[256]; + int sizes[256]; + int blocksizes[256]; + int hardsizes[256]; +}; + +/* Defining the diffent access_menthods */ +/* + * Memory mapped FIFO interface (SMART 53xx cards) + */ +#define SA5_DOORBELL 0x20 +#define SA5_REQUEST_PORT_OFFSET 0x40 +#define SA5_REPLY_INTR_MASK_OFFSET 0x34 +#define SA5_REPLY_PORT_OFFSET 0x44 +#define SA5_INTR_STATUS 0x30 + +#define SA5_INTR_OFF 0x08 +#define SA5_INTR_PENDING 0x08 +#define FIFO_EMPTY 0xffffffff + +#define CISS_ERROR_BIT 0x02 + +#define CCISS_INTR_ON 1 +#define CCISS_INTR_OFF 0 +/* + Send the command to the hardware +*/ +static void SA5_submit_command( ctlr_info_t *h, CommandList_struct *c) +{ +#ifdef CCISS_DEBUG + printk("Sending %x - down to controller\n", c->busaddr ); +#endif /* CCISS_DEBUG */ + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + h->commands_outstanding++; + if ( h->commands_outstanding > h->max_outstanding) + h->max_outstanding = h->commands_outstanding; +} + +/* + * This card is the oposite of the other cards. + * 0 turns interrupts on... + * 0x08 turns them off... + */ +static void SA5_intr_mask(ctlr_info_t *h, unsigned long val) +{ + if (val) + { /* Turn interrupts on */ + writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + } else /* Turn them off */ + { + writel( SA5_INTR_OFF, + h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + } +} +/* + * Returns true if fifo is full. + * + */ +static unsigned long SA5_fifo_full(ctlr_info_t *h) +{ + if( h->commands_outstanding >= h->max_commands) + return(1); + else + return(0); + +} +/* + * returns value read from hardware. + * returns FIFO_EMPTY if there is nothing to read + */ +static unsigned long SA5_completed(ctlr_info_t *h) +{ + unsigned long register_value + = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); + if(register_value != FIFO_EMPTY) + { + h->commands_outstanding--; +#ifdef CCISS_DEBUG + printk("cciss: Read %lx back from board\n", register_value); +#endif /* CCISS_DEBUG */ + } +#ifdef CCISS_DEBUG + else + { + printk("cciss: FIFO Empty read\n"); + } +#endif + return ( register_value); + +} +/* + * Returns true if an interrupt is pending.. + */ +static unsigned long SA5_intr_pending(ctlr_info_t *h) +{ + unsigned long register_value = + readl(h->vaddr + SA5_INTR_STATUS); +#ifdef CCISS_DEBUG + printk("cciss: intr_pending %lx\n", register_value); +#endif /* CCISS_DEBUG */ + if( register_value & SA5_INTR_PENDING) + return 1; + return 0 ; +} + + +static struct access_method SA5_access = { + SA5_submit_command, + SA5_intr_mask, + SA5_fifo_full, + SA5_intr_pending, + SA5_completed, +}; + +struct board_type { + __u32 board_id; + char *product_name; + struct access_method *access; +}; +#endif /* CCISS_H */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h --- v2.2.17/drivers/block/cciss_cmd.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/cciss_cmd.h Fri Sep 1 13:32:19 2000 @@ -0,0 +1,254 @@ +#ifndef CCISS_CMD_H +#define CCISS_CMD_H +//########################################################################### +//DEFINES +//########################################################################### +#define CISS_VERSION "1.00" + +//general boundary defintions +#define SENSEINFOBYTES 32//note that this value may vary between host implementations +#define MAXSGENTRIES 31 +#define MAXREPLYQS 256 + +//Command Status value +#define CMD_SUCCESS 0x0000 +#define CMD_TARGET_STATUS 0x0001 +#define CMD_DATA_UNDERRUN 0x0002 +#define CMD_DATA_OVERRUN 0x0003 +#define CMD_INVALID 0x0004 +#define CMD_PROTOCOL_ERR 0x0005 +#define CMD_HARDWARE_ERR 0x0006 +#define CMD_CONNECTION_LOST 0x0007 +#define CMD_ABORTED 0x0008 +#define CMD_ABORT_FAILED 0x0009 +#define CMD_UNSOLICITED_ABORT 0x000A +#define CMD_TIMEOUT 0x000B +#define CMD_UNABORTABLE 0x000C + +//transfer direction +#define XFER_NONE 0x00 +#define XFER_WRITE 0x01 +#define XFER_READ 0x02 +#define XFER_RSVD 0x03 + +//task attribute +#define ATTR_UNTAGGED 0x00 +#define ATTR_SIMPLE 0x04 +#define ATTR_HEADOFQUEUE 0x05 +#define ATTR_ORDERED 0x06 +#define ATTR_ACA 0x07 + +//cdb type +#define TYPE_CMD 0x00 +#define TYPE_MSG 0x01 + +//config space register offsets +#define CFG_VENDORID 0x00 +#define CFG_DEVICEID 0x02 +#define CFG_I2OBAR 0x10 +#define CFG_MEM1BAR 0x14 + +//i2o space register offsets +#define I2O_IBDB_SET 0x20 +#define I2O_IBDB_CLEAR 0x70 +#define I2O_INT_STATUS 0x30 +#define I2O_INT_MASK 0x34 +#define I2O_IBPOST_Q 0x40 +#define I2O_OBPOST_Q 0x44 + +//Configuration Table +#define CFGTBL_ChangeReq 0x00000001l +#define CFGTBL_AccCmds 0x00000001l + +#define CFGTBL_Trans_Simple 0x00000002l + +#define CFGTBL_BusType_Ultra2 0x00000001l +#define CFGTBL_BusType_Ultra3 0x00000002l +#define CFGTBL_BusType_Fibre1G 0x00000100l +#define CFGTBL_BusType_Fibre2G 0x00000200l +typedef struct _vals32 +{ + __u32 lower; + __u32 upper; +} vals32; + +typedef union _u64bit +{ + vals32 val32; + __u64 val; +} u64bit; + +// Type defs used in the following structs +#define BYTE __u8 +#define WORD __u16 +#define HWORD __u16 +#define DWORD __u32 +#define QWORD vals32 + +//########################################################################### +//STRUCTURES +//########################################################################### +#define CISS_MAX_LUN 16 +// SCSI-3 Cmmands + +#pragma pack(1) + +#define CISS_INQUIRY 0x12 +//Date returned +typedef struct _InquiryData_struct +{ + BYTE data_byte[36]; +} InquiryData_struct; + +#define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */ +// Data returned +typedef struct _ReportLUNdata_struct +{ + BYTE LUNListLength[4]; + DWORD reserved; + BYTE LUN[CISS_MAX_LUN][8]; +} ReportLunData_struct; + +#define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ +typedef struct _ReadCapdata_struct +{ + BYTE total_size[4]; // Total size in blocks + BYTE block_size[4]; // Size of blocks in bytes +} ReadCapdata_struct; + +// 12 byte commands not implemented in firmware yet. +// #define CCISS_READ 0xa8 // Read(12) +// #define CCISS_WRITE 0xaa // Write(12) + #define CCISS_READ 0x28 // Read(10) + #define CCISS_WRITE 0x2a // Write(10) + +//Command List Structure +typedef union _SCSI3Addr_struct { + struct { + BYTE Bus:6; + BYTE Mode:2; // b00 + BYTE Dev; + } PeripDev; + struct { + BYTE DevMSB:6; + BYTE Mode:2; // b01 + BYTE DevLSB; + } LogDev; + struct { + BYTE Targ:6; + BYTE Mode:2; // b10 + BYTE Dev:5; + BYTE Bus:3; + } LogUnit; +} SCSI3Addr_struct; + +typedef struct _PhysDevAddr_struct { + DWORD TargetId:24; + DWORD Bus:6; + DWORD Mode:2; + SCSI3Addr_struct Target[2]; //2 level target device addr +} PhysDevAddr_struct; + +typedef struct _LogDevAddr_struct { + DWORD VolId:30; + DWORD Mode:2; + BYTE reserved[4]; +} LogDevAddr_struct; + +typedef union _LUNAddr_struct { + BYTE LunAddrBytes[8]; + SCSI3Addr_struct SCSI3Lun[4]; + PhysDevAddr_struct PhysDev; + LogDevAddr_struct LogDev; +} LUNAddr_struct; + +typedef struct _CommandListHeader_struct { + BYTE ReplyQueue; + BYTE SGList; + HWORD SGTotal; + QWORD Tag; + LUNAddr_struct LUN; +} CommandListHeader_struct; +typedef struct _RequestBlock_struct { + BYTE CDBLen; + struct { + BYTE Type:3; + BYTE Attribute:3; + BYTE Direction:2; + } Type; + HWORD Timeout; + BYTE CDB[16]; +} RequestBlock_struct; +typedef struct _ErrDescriptor_struct { + QWORD Addr; + DWORD Len; +} ErrDescriptor_struct; +typedef struct _SGDescriptor_struct { + QWORD Addr; + DWORD Len; + DWORD Ext; +} SGDescriptor_struct; + +typedef union _MoreErrInfo_struct{ + struct { + BYTE Reserved[3]; + BYTE Type; + DWORD ErrorInfo; + }Common_Info; + struct{ + BYTE Reserved[2]; + BYTE offense_size;//size of offending entry + BYTE offense_num; //byte # of offense 0-base + DWORD offense_value; + }Invalid_Cmd; +}MoreErrInfo_struct; +typedef struct _ErrorInfo_struct { + BYTE ScsiStatus; + BYTE SenseLen; + HWORD CommandStatus; + DWORD ResidualCnt; + MoreErrInfo_struct MoreErrInfo; + BYTE SenseInfo[SENSEINFOBYTES]; +} ErrorInfo_struct; + +/* Command types */ +#define CMD_RWREQ 0x00 +#define CMD_IOCTL_PEND 0x01 +#define CMD_IOCTL_DONE 0x02 + +typedef struct _CommandList_struct { + CommandListHeader_struct Header; + RequestBlock_struct Request; + ErrDescriptor_struct ErrDesc; + SGDescriptor_struct SG[MAXSGENTRIES]; + /* information associated with the command */ + __u32 busaddr; /* physical addres of this record */ + ErrorInfo_struct * err_info; /* pointer to the allocated mem */ + int cmd_type; + struct _CommandList_struct *prev; + struct _CommandList_struct *next; + struct buffer_head * bh; +} CommandList_struct; + +//Configuration Table Structure +typedef struct _HostWrite_struct { + DWORD TransportRequest; + DWORD Reserved; + DWORD CoalIntDelay; + DWORD CoalIntCount; +} HostWrite_struct; + +typedef struct _CfgTable_struct { + BYTE Signature[4]; + DWORD SpecValence; + DWORD TransportSupport; + DWORD TransportActive; + HostWrite_struct HostWrite; + DWORD CmdsOutMax; + DWORD BusTypes; + DWORD Reserved; + BYTE ServerName[16]; + DWORD HeartBeat; +} CfgTable_struct; +#pragma pack() +#endif // CCISS_CMD_H diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.2.17/drivers/block/cpqarray.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/cpqarray.c Tue Nov 21 17:42:10 2000 @@ -41,8 +41,14 @@ #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.9)" -#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,9) +#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.11)" +#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,11) + +/* Embedded module documentation macros - see modules.h */ +/* Original author Chris Frantz - Compaq Computer Corporation */ +MODULE_AUTHOR("Compaq Computer Corporation"); +MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers"); + #define MAJOR_NR COMPAQ_SMART2_MAJOR #include #include @@ -449,7 +455,8 @@ hba[i]->access.set_intr_mask(hba[i], 0); if (request_irq(hba[i]->intr, do_ida_intr, - SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) { + SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM, + hba[i]->devname, hba[i])) { printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", hba[i]->intr, hba[i]->devname); @@ -617,6 +624,8 @@ int i; + c->pci_bus = bus; + c->pci_dev_fn = device_fn; pdev = pci_find_slot(bus, device_fn); vendor_id = pdev->vendor; device_id = pdev->device; @@ -663,6 +672,7 @@ c->vaddr = remap_pci_mem(c->paddr, 128); c->board_id = board_id; + for(i=0; iproduct_name = products[i].product_name; @@ -752,6 +762,8 @@ hba[nr_ctlr]->access = *(products[j].access); hba[nr_ctlr]->ctlr = nr_ctlr; hba[nr_ctlr]->board_id = board_id; + hba[nr_ctlr]->pci_bus = 0; /* not PCI */ + hba[nr_ctlr]->pci_dev_fn = 0; /* not PCI */ DBGINFO( printk("i = %d, j = %d\n", i, j); @@ -1174,7 +1186,20 @@ if (!arg) return -EINVAL; put_user(DRIVER_VERSION, (unsigned long*)arg); return 0; + case IDAGETPCIINFO: + { + + ida_pci_info_struct pciinfo; + if (!arg) return -EINVAL; + pciinfo.bus = hba[ctlr]->pci_bus; + pciinfo.dev_fn = hba[ctlr]->pci_dev_fn; + pciinfo.board_id = hba[ctlr]->board_id; + copy_to_user_ret((void *) arg, &pciinfo, + sizeof( ida_pci_info_struct), -EFAULT); + return(0); + } + RO_IOCTLS(inode->i_rdev, arg); default: @@ -1358,6 +1383,8 @@ ctlr_info_t *info_p = hba[ctlr]; c = cmd_alloc(info_p); + if (!c) + return IO_ERROR; c->ctlr = ctlr; c->hdr.unit = log_unit; c->hdr.prio = 0; @@ -1623,6 +1650,7 @@ int ret_code, size; drv_info_t *drv; ctlr_info_t *info_p = hba[ctlr]; + int i; info_p->log_drv_map = 0; @@ -1687,7 +1715,8 @@ } info_p->log_drives = id_ctlr_buf->nr_drvs;; - *(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev); + for(i=0;i<4;i++) + info_p->firm_rev[i] = id_ctlr_buf->firm_rev[i]; info_p->ctlr_sig = id_ctlr_buf->cfg_sig; printk(" (%s)\n", info_p->product_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h --- v2.2.17/drivers/block/cpqarray.h Fri Apr 21 23:13:37 2000 +++ linux/drivers/block/cpqarray.h Tue Nov 28 17:12:46 2000 @@ -87,6 +87,8 @@ int log_drives; int phys_drives; + unsigned char pci_bus; /* 0 if EISA */ + unsigned char pci_dev_fn; /* 0 if EISA */ __u32 board_id; char *product_name; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/falconide.c linux/drivers/block/falconide.c --- v2.2.17/drivers/block/falconide.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/falconide.c Sat Oct 14 00:06:42 2000 @@ -0,0 +1,72 @@ +/* + * linux/drivers/block/falconide.c -- Atari Falcon IDE Driver + * + * Created 12 Jul 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include + +#include "ide.h" + +#include +#include +#include + + + /* + * Base of the IDE interface + */ + +#define ATA_HD_BASE 0xfff00000 + + /* + * Offsets from the above base + */ + +#define ATA_HD_DATA 0x00 +#define ATA_HD_ERROR 0x05 /* see err-bits */ +#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */ +#define ATA_HD_SECTOR 0x0d /* starting sector */ +#define ATA_HD_LCYL 0x11 /* starting cylinder */ +#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */ +#define ATA_HD_SELECT 0x19 /* 101dhhhh , d=drive, hhhh=head */ +#define ATA_HD_STATUS 0x1d /* see status-bits */ +#define ATA_HD_CONTROL 0x39 + +static const int falconide_offsets[IDE_NR_PORTS] = { + ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL, + ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL +}; + + + /* + * Probe for a Falcon IDE interface + */ + +int falconide_probe_hwif(int index, ide_hwif_t *hwif) +{ + static int falcon_index = 0; + + if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE)) + return 0; + + if (!falcon_index) { + printk("ide%d: Falcon IDE interface\n", index); + falcon_index = index+1; + } + if (falcon_index == index+1) { + ide_setup_ports(hwif, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets, 0, + NULL); + hwif->irq = IRQ_MFP_IDE; + return 1; + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.2.17/drivers/block/floppy.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/floppy.c Sat Sep 23 13:24:12 2000 @@ -2257,6 +2257,7 @@ static void request_done(int uptodate) { int block; + unsigned long flags; probing = 0; reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate); @@ -2275,6 +2276,7 @@ DRS->maxtrack = 1; /* unlock chained buffers */ + spin_lock_irqsave(&io_request_lock, flags); while (current_count_sectors && CURRENT && current_count_sectors >= CURRENT->current_nr_sectors){ current_count_sectors -= CURRENT->current_nr_sectors; @@ -2282,6 +2284,7 @@ CURRENT->sector += CURRENT->current_nr_sectors; end_request(1); } + spin_unlock_irqrestore(&io_request_lock, flags); if (current_count_sectors && CURRENT){ /* "unlock" last subsector */ CURRENT->buffer += current_count_sectors <<9; @@ -2305,7 +2308,9 @@ DRWE->last_error_sector = CURRENT->sector; DRWE->last_error_generation = DRS->generation; } + spin_lock_irqsave(&io_request_lock, flags); end_request(0); + spin_unlock_irqrestore(&io_request_lock, flags); } } @@ -2313,6 +2318,13 @@ static void rw_interrupt(void) { int nr_sectors, ssize, eoc, heads; + + if (R_HEAD >= 2) { + /* some Toshiba floppy controllers occasionnally seem to + * return bogus interrupts after read/write operations, which + * can be recognized by a bad head number (>= 2) */ + return; + } if (!DRS->first_read_date) DRS->first_read_date = jiffies; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/gayle.c linux/drivers/block/gayle.c --- v2.2.17/drivers/block/gayle.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/gayle.c Fri Oct 13 23:57:54 2000 @@ -0,0 +1,169 @@ +/* + * linux/drivers/block/gayle.c -- Amiga Gayle IDE Driver + * + * Created 9 Jul 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "ide.h" + +#include +#include +#include + + + /* + * Bases of the IDE interfaces + */ + +#define GAYLE_BASE_4000 0xdd2020 /* A4000/A4000T */ +#define GAYLE_BASE_1200 0xda0000 /* A1200/A600 */ + + /* + * Offsets from one of the above bases + */ + +#define GAYLE_DATA 0x00 +#define GAYLE_ERROR 0x06 /* see err-bits */ +#define GAYLE_NSECTOR 0x0a /* nr of sectors to read/write */ +#define GAYLE_SECTOR 0x0e /* starting sector */ +#define GAYLE_LCYL 0x12 /* starting cylinder */ +#define GAYLE_HCYL 0x16 /* high byte of starting cyl */ +#define GAYLE_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ +#define GAYLE_STATUS 0x1e /* see status-bits */ +#define GAYLE_CONTROL 0x101a + +static u_int gayle_offsets[IDE_NR_PORTS] = { + GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, + GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, GAYLE_CONTROL +}; + + + /* + * These are at different offsets from the base + */ + +#define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */ +#define GAYLE_IRQ_1200 0xda9000 /* interrupt */ + + + /* + * Offset of the secondary port for IDE doublers + * Note that GAYLE_CONTROL is NOT available then! + */ + +#define GAYLE_NEXT_PORT 0x1000 + +#ifndef CONFIG_BLK_DEV_IDEDOUBLER +#define GAYLE_NUM_HWIFS 1 +#define GAYLE_NUM_PROBE_HWIFS GAYLE_NUM_HWIFS +#define GAYLE_HAS_CONTROL_REG 1 +#else /* CONFIG_BLK_DEV_IDEDOUBLER */ +#define GAYLE_NUM_HWIFS 2 +#define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \ + GAYLE_NUM_HWIFS-1) +#define GAYLE_HAS_CONTROL_REG (!ide_doubler) +int ide_doubler = 0; /* support IDE doublers? */ +#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + + + /* + * Check and acknowledge the interrupt status + */ + +static int gayle_ack_intr_a4000(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); + if (!(ch & 0x80)) + return 0; + return 1; +} + +static int gayle_ack_intr_a1200(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]); + if (!(ch & 0x80)) + return 0; + (void)inb(hwif->io_ports[IDE_STATUS_OFFSET]); + outb(0x7c | (ch & 0x03), hwif->io_ports[IDE_IRQ_OFFSET]); + return 1; +} + + + /* + * Probe for a Gayle IDE interface (and optionally for an IDE doubler) + */ + +int gayle_probe_hwif(int index, ide_hwif_t *hwif) +{ + static int gayle_index[GAYLE_NUM_HWIFS] = { 0, }; + int a4000, i; + + if (!MACH_IS_AMIGA) + return 0; + + if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE)) + return 0; + + if (!GAYLE_HAS_CONTROL_REG) + gayle_offsets[IDE_CONTROL_OFFSET] = -1; + + for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) { + if (!gayle_index[i]) { + switch (i) { + case 0: + printk("ide%d: Gayle IDE interface (A%d style)\n", index, + a4000 ? 4000 : 1200); + break; +#ifdef CONFIG_BLK_DEV_IDEDOUBLER + case 1: + printk("ide%d: IDE doubler\n", index); + break; +#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + } + gayle_index[i] = index+1; + } + if (gayle_index[i] == index+1) { + ide_ioreg_t base, irqport; + ide_ack_intr_t *ack_intr; + if (a4000) { + base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_4000); + irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000); + ack_intr = gayle_ack_intr_a4000; + } else { + base = (ide_ioreg_t)ZTWO_VADDR(GAYLE_BASE_1200); + irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200); + ack_intr = gayle_ack_intr_a1200; + } + base += i*GAYLE_NEXT_PORT; + ide_setup_ports(hwif, base, gayle_offsets, irqport, ack_intr); +#if 1 /* TESTING */ + if (i == 1) { + volatile u_short *addr = (u_short *)base; + u_short data; + printk("+++ Probing for IDE doubler... "); + *addr = 0xffff; + data = *addr; + printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data); + } +#endif /* TESTING */ + hwif->irq = IRQ_AMIGA_PORTS; + return 1; + } + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.2.17/drivers/block/genhd.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/genhd.c Wed Nov 8 23:08:16 2000 @@ -29,6 +29,10 @@ #include #include +#ifdef CONFIG_ARCH_S390 +#include +#endif /* CONFIG_ARCH_S390 */ + #include #include @@ -67,7 +71,7 @@ extern int net_dev_init(void); #ifdef CONFIG_PPC -extern void note_bootable_part(kdev_t dev, int part); +extern void note_bootable_part(kdev_t dev, int part, int goodness); #endif static char *raid_name (struct gendisk *hd, int minor, int major_base, @@ -84,6 +88,10 @@ return buf; } +#ifdef CONFIG_ARCH_S390 +int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; +#endif + /* * disk_name() is used by genhd.c and md.c. * It formats the devicename of the indicated disk @@ -96,6 +104,14 @@ const char *maj = hd->major_name; int unit = (minor >> hd->minor_shift) + 'a'; +#ifdef CONFIG_ARCH_S390 + if ( strncmp ( hd->major_name,"dasd",4) == 0 ){ + part = minor & ((1 << hd->minor_shift) - 1); + if ( genhd_dasd_name ) + genhd_dasd_name(buf,minor>>hd->minor_shift,part,hd); + return buf; + } +#endif /* * IDE devices use multiple major numbers, but the drives * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. @@ -131,6 +147,10 @@ return buf; } } + if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= + COMPAQ_CISS_MAJOR+7) { + return raid_name (hd, minor, COMPAQ_CISS_MAJOR, buf); + } if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) { return raid_name (hd, minor, COMPAQ_SMART2_MAJOR, buf); @@ -1175,7 +1195,8 @@ goodness++; if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0 - || strcasecmp(part->type, "Linux_PPC") == 0) { + || (strnicmp(part->type, "Linux", 5) == 0 + && strcasecmp(part->type, "Linux_swap") != 0)) { int i, l; goodness++; @@ -1204,7 +1225,7 @@ } #ifdef CONFIG_PPC if (found_root_goodness) - note_bootable_part(dev, found_root); + note_bootable_part(dev, found_root, found_root_goodness); #endif brelse(bh); printk("\n"); @@ -1398,10 +1419,11 @@ #endif /* CONFIG_ULTRIX_PARTITION */ #ifdef CONFIG_ARCH_S390 +#include +#include +#include #include -#include "../s390/block/dasd_types.h" - -dasd_information_t **dasd_information = NULL; +#include typedef enum { ibm_partition_none = 0, @@ -1438,14 +1460,45 @@ ibm_partition_t partition_type; char type[5] = {0,}; char name[7] = {0,}; - int di = MINOR(dev) >> hd->minor_shift; - if ( ! get_ptable_blocksize(dev) ) + struct hd_geometry geo; + mm_segment_t old_fs; + int blocksize; + struct file *filp = NULL; + struct inode *inode = NULL; + int offset, size; + int rc; + + blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; + if ( blocksize <= 0 ) { return 0; - if ( ! dasd_information ) + } + set_blocksize(dev, blocksize); /* OUCH !! */ + + /* find out offset of volume label (partn table) */ + filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL); + if ( filp == NULL ) { + printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed for filp\n"); + return 0; + } + memset(filp,0,sizeof(struct file)); + filp ->f_mode = 1; /* read only */ + inode = get_empty_inode(); + inode -> i_rdev = dev; + rc = blkdev_open(inode,filp); + if ( rc ) { + return 0; + } + old_fs=get_fs(); + set_fs(KERNEL_DS); + rc = filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo)); + set_fs(old_fs); + if ( rc ) { return 0; - if ( ( bh = bread( dev, - dasd_information[di]->sizes.label_block, - dasd_information[di]->sizes.bp_sector ) ) != NULL ) { + } + blkdev_release(inode); + + size = hd -> sizes[MINOR(dev)]<<1; + if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) { strncpy ( type,bh -> b_data, 4); strncpy ( name,bh -> b_data + 4, 6); } else { @@ -1455,50 +1508,45 @@ EBCASC(name,6); } switch ( partition_type = get_partition_type(type) ) { - case ibm_partition_lnx1: + case ibm_partition_lnx1: + offset = (geo.start + 1); printk ( "(LNX1)/%6s:",name); - add_partition( hd, MINOR(dev) + 1, - (dasd_information[di]->sizes.label_block + 1) << - dasd_information[di]->sizes.s2b_shift, - (dasd_information [di]->sizes.blocks - - dasd_information[di]->sizes.label_block - 1) << - dasd_information[di]->sizes.s2b_shift,0 ); break; case ibm_partition_vol1: + offset = 0; + size = 0; printk ( "(VOL1)/%6s:",name); break; case ibm_partition_cms1: printk ( "(CMS1)/%6s:",name); if (* (((long *)bh->b_data) + 13) == 0) { /* disk holds a CMS filesystem */ - add_partition( hd, MINOR(dev) + 1, - (dasd_information [di]->sizes.label_block + 1) << - dasd_information [di]->sizes.s2b_shift, - (dasd_information [di]->sizes.blocks - - dasd_information [di]->sizes.label_block) << - dasd_information [di]->sizes.s2b_shift,0 ); + offset = (geo.start + 1); printk ("(CMS)"); } else { - /* disk is reserved minidisk */ - long *label=(long*)bh->b_data; - int offset = label[13]; - int size = (label[7]-1-label[13])*(label[3]>>9); - add_partition( hd, MINOR(dev) + 1, - offset << dasd_information [di]->sizes.s2b_shift, - size<sizes.s2b_shift,0 ); + /* disk is reserved minidisk */ + // mdisk_setup_data.size[i] = + // (label[7] - 1 - label[13]) * + // (label[3] >> 9) >> 1; + long *label=(long*)bh->b_data; + blocksize = label[3]; + offset = label[13]; + size = (label[7]-1)*(blocksize>>9); printk ("(MDSK)"); } break; case ibm_partition_none: printk ( "(nonl)/ :"); - add_partition( hd, MINOR(dev) + 1, - (dasd_information [di]->sizes.label_block + 1) << - dasd_information [di]->sizes.s2b_shift, - (dasd_information [di]->sizes.blocks - - dasd_information [di]->sizes.label_block - 1) << - dasd_information [di]->sizes.s2b_shift,0 ); + offset = (geo.start+1); break; - } + default: + offset = 0; + size = 0; + + } + add_partition( hd, MINOR(dev), 0,size,0); + add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9), + size-offset*(blocksize>>9) ,0 ); printk ( "\n" ); bforget(bh); return 1; @@ -1512,7 +1560,7 @@ char buf[MAX_DISKNAME_LEN]; if (first_time) - printk("Partition check:\n"); + printk(KERN_INFO "Partition check:\n"); first_time = 0; first_sector = hd->part[MINOR(dev)].start_sect; @@ -1525,7 +1573,7 @@ return; } - printk(" %s:", disk_name(hd, MINOR(dev), buf)); + printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); #ifdef CONFIG_MSDOS_PARTITION if (msdos_partition(hd, dev, first_sector)) return; @@ -1605,14 +1653,18 @@ dev->part[i].start_sect = 0; dev->part[i].nr_sects = 0; } - dev->init(dev); + if ( dev->init != NULL ) + dev->init(dev); for (drive = 0 ; drive < dev->nr_real ; drive++) { int first_minor = drive << dev->minor_shift; current_minor = 1 + first_minor; - check_partition(dev, MKDEV(dev->major, first_minor)); + /* If we really have a device check partition table */ + if ( blksize_size[dev->major] == NULL || + blksize_size[dev->major][current_minor]) + check_partition(dev, MKDEV(dev->major, first_minor)); } if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ - for (i = 0; i < end_minor; i++) + for (i = 0; i < end_minor; i++) dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); blk_size[dev->major] = dev->sizes; } @@ -1622,6 +1674,9 @@ { extern void console_map_init(void); extern void cpqarray_init(void); +#ifdef CONFIG_BLK_CPQ_CISS_DA + extern int cciss_init(void); +#endif #ifdef CONFIG_PARPORT extern int parport_init(void); #endif @@ -1654,6 +1709,9 @@ #endif #ifdef CONFIG_BLK_CPQ_DA cpqarray_init(); +#endif +#ifdef CONFIG_BLK_CPQ_CISS_DA + cciss_init(); #endif #ifdef CONFIG_NET net_dev_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/hd.c linux/drivers/block/hd.c --- v2.2.17/drivers/block/hd.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/hd.c Sat Oct 28 13:40:23 2000 @@ -21,6 +21,8 @@ * Removed 99% of above. Use Mark's ide driver for those options. * This is now a lightweight ST-506 driver. (Paul Gortmaker) * + * 17-OCT-2000 rjohnson@analogic.com Added spin-lock for reading + * CMOS chip. */ /* Uncomment the following if you want verbose error reports. */ @@ -48,7 +50,7 @@ #define MAJOR_NR HD_MAJOR #include - +extern spinlock_t rtc_lock; static int revalidate_hddisk(kdev_t, int); #define HD_DELAY 0 @@ -701,6 +703,7 @@ static void hd_geninit(struct gendisk *ignored) { int drive; + unsigned long flags; #ifdef __i386__ if (!NR_HD) { @@ -743,13 +746,14 @@ */ - + spin_lock_irqsave(&rtc_lock, flags); if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) { if (cmos_disks & 0x0f) NR_HD = 2; else NR_HD = 1; } + spin_unlock_irqrestore(&rtc_lock, flags); } #endif /* __i386__ */ for (drive=0 ; drive < NR_HD ; drive++) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h --- v2.2.17/drivers/block/ida_ioctl.h Fri Apr 21 23:13:37 2000 +++ linux/drivers/block/ida_ioctl.h Tue Nov 28 17:12:46 2000 @@ -33,7 +33,14 @@ #define IDAGETCTLRSIG 0x29293030 #define IDAREVALIDATEVOLS 0x30303131 #define IDADRIVERVERSION 0x31313232 +#define IDAGETPCIINFO 0x32323333 +typedef struct _ida_pci_info_struct +{ + unsigned char bus; + unsigned char dev_fn; + __u32 board_id; +} ida_pci_info_struct; /* * Normally, the ioctl determines the logical unit for this command by * the major,minor number of the fd passed to ioctl. If you need to send @@ -60,7 +67,7 @@ union ctlr_cmds { drv_info_t drv; - unsigned char buf[512]; + unsigned char buf[1024]; id_ctlr_t id_ctlr; drv_param_t drv_param; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.2.17/drivers/block/ide-cd.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/ide-cd.c Sat Nov 18 19:12:22 2000 @@ -210,17 +210,17 @@ * patch thanks to "Eddie C. Dost" * * 4.50 Oct 19, 1998 -- New maintainers! - * Jens Axboe + * Jens Axboe * Chris Zwilling * - * 4.51 Dec 23, 1998 -- Jens Axboe + * 4.51 Dec 23, 1998 -- Jens Axboe * - ide_cdrom_reset enabled since the ide subsystem - * handles resets fine now. + * handles resets fine now. * - Transfer size fix for Samsung CD-ROMs, thanks to * "Ville Hallik" . * - other minor stuff. * - * 4.52 Jan 19, 1999 -- Jens Axboe + * 4.52 Jan 19, 1999 -- Jens Axboe * - Detect DVD-ROM/RAM drives * * 4.53 Feb 22, 1999 - Include other model Samsung and one Goldstar @@ -324,41 +324,50 @@ info->nsectors_buffered = 0; } +static int cdrom_log_sense(ide_drive_t *drive, struct packet_command *pc, + struct request_sense *sense) +{ + int log = 0; + + if (sense == NULL) + return 0; + + switch (sense->sense_key) { + case NO_SENSE: case RECOVERED_ERROR: + break; + case NOT_READY: + /* + * don't care about tray state messages for + * e.g. capacity commands or in-progress or + * becoming ready + */ + if (sense->asc == 0x3a || sense->asc == 0x04) + break; + log = 1; + break; + case UNIT_ATTENTION: + /* + * Make good and sure we've seen this potential media + * change. Some drives (i.e. Creative) fail to present + * the correct sense key in the error register. + */ + cdrom_saw_media_change(drive); + break; + default: + log = 1; + break; + } + return log; +} static void cdrom_analyze_sense_data(ide_drive_t *drive, struct packet_command *failed_command, struct request_sense *sense) { - if (sense->sense_key == NOT_READY || - sense->sense_key == UNIT_ATTENTION) { - /* Make good and sure we've seen this potential media change. - Some drives (i.e. Creative) fail to present the correct - sense key in the error register. */ - cdrom_saw_media_change (drive); - - - /* Don't print not ready or unit attention errors for - READ_SUBCHANNEL. Workman (and probably other programs) - uses this command to poll the drive, and we don't want - to fill the syslog with useless errors. */ - if (failed_command && - (failed_command->c[0] == GPCMD_READ_SUBCHANNEL || - failed_command->c[0] == GPCMD_TEST_UNIT_READY)) - return; - } - - if (sense->error_code == 0x70 && sense->sense_key == 0x02 - && ((sense->asc == 0x3a && sense->ascq == 0x00) || - (sense->asc == 0x04 && sense->ascq == 0x01))) - { - /* - * Suppress the following errors: - * "Medium not present", "in progress of becoming ready", - * and "writing" to keep the noise level down to a dull roar. - */ + + if (!cdrom_log_sense(drive, failed_command, sense)) return; - } #if VERBOSE_IDE_CD_ERRORS { @@ -1105,7 +1114,13 @@ if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) { if (--retry == 0) { + /* + * this condition is far too common, to bother + * users about it + */ +#if 0 printk("%s: disabled DSC seek overlap\n", drive->name); +#endif drive->dsc_overlap = 0; } } @@ -1329,8 +1344,12 @@ static void cdrom_sleep (int time) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(time); + int sleep = time; + + do { + set_current_state(TASK_INTERRUPTIBLE); + sleep = schedule_timeout(sleep); + } while (sleep); } static @@ -1827,6 +1846,20 @@ return cdrom_queue_packet_command(drive, &pc); } +static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end) +{ + struct request_sense sense; + struct packet_command pc; + + memset(&pc, 0, sizeof (pc)); + pc.sense = &sense; + + pc.c[0] = GPCMD_PLAY_AUDIO_MSF; + lba_to_msf(lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); + lba_to_msf(lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]); + + return cdrom_queue_packet_command(drive, &pc); +} static int cdrom_get_toc_entry(ide_drive_t *drive, int track, struct atapi_toc_entry **ent) @@ -1835,6 +1868,9 @@ struct atapi_toc *toc = info->toc; int ntracks; + if (!CDROM_STATE_FLAGS(drive)->toc_valid) + return -EINVAL; + /* Check validity of requested track number. */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0; @@ -1930,10 +1966,38 @@ { ide_drive_t *drive = (ide_drive_t*) cdi->handle; struct cdrom_info *info = drive->driver_data; + int stat; switch (cmd) { + /* + * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_MSF, since + * atapi doesn't support it + */ + case CDROMPLAYTRKIND: { + int lba_start, lba_end; + struct cdrom_ti *ti = (struct cdrom_ti *)arg; + struct atapi_toc_entry *first_toc, *last_toc; + + stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc); + if (stat) + return stat; + + stat = cdrom_get_toc_entry(drive, ti->cdti_trk1, &last_toc); + if (stat) + return stat; + + if (ti->cdti_trk1 != CDROM_LEADOUT) + ++last_toc; + lba_start = first_toc->addr.lba; + lba_end = last_toc->addr.lba; + + if (lba_end <= lba_start) + return -EINVAL; + + return cdrom_play_audio(drive, lba_start, lba_end); + } + case CDROMREADTOCHDR: { - int stat; struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; struct atapi_toc *toc; @@ -1949,7 +2013,6 @@ } case CDROMREADTOCENTRY: { - int stat; struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg; struct atapi_toc_entry *toce; @@ -2275,7 +2338,7 @@ CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1; if (cap.audio_play) CDROM_CONFIG_FLAGS (drive)->audio_play = 1; - if (cap.mechtype == 0) + if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup) CDROM_CONFIG_FLAGS (drive)->close_tray = 0; #if ! STANDARD_ATAPI diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.2.17/drivers/block/ide-dma.c Sun Jun 11 21:44:12 2000 +++ linux/drivers/block/ide-dma.c Mon Sep 11 18:06:33 2000 @@ -433,6 +433,12 @@ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; + + /* ====== ALI M5229 ================================*/ + if( hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229) + outb(inb(dma_base+2) & 0x60, dma_base+2); + /* =================================================*/ + if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA disabled\n", name); dma_base = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.2.17/drivers/block/ide-floppy.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/ide-floppy.c Sat Oct 28 11:31:51 2000 @@ -1,7 +1,8 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 + * linux/drivers/block/ide-floppy.c Version 0.94 Oct 27, 2000 * * Copyright (C) 1996 - 1999 Gadi Oxman + * Copyright (C) 2000 Paul Bristow */ /* @@ -10,6 +11,12 @@ * The driver currently doesn't have any fancy features, just the bare * minimum read/write support. * + * This driver supports the following IDE floppy drives: + * + * LS-120 SuperDisk + * Iomega Zip 100/250 + * Iomega PC Card Clik!/PocketZip + * * Many thanks to Lode Leroy , who tested so many * ALPHA patches to this driver on an EASYSTOR LS-120 ATAPI floppy drive. * @@ -29,9 +36,17 @@ * Ver 0.9 Jul 4 99 Fix a bug which might have caused the number of * bytes requested on each interrupt to be zero. * Thanks to for pointing this out. + * Ver 0.91 Dec 11 99 Added IOMEGA Clik! drive support by + * + * Ver 0.92 Oct 22 00 Paul Bristow became official maintainer for this + * driver. Included Powerbook internal zip kludge. + * Ver 0.93 Oct 24 00 Fixed bugs for Clik! drive + * no disk on insert and disk change now works + * Ver 0.94 Oct 27 00 Tidied up to remove strstr(Clik) everywhere + * */ -#define IDEFLOPPY_VERSION "0.9" +#define IDEFLOPPY_VERSION "0.94" #include #include @@ -60,12 +75,14 @@ */ #include "ide.h" + /* * The following are used to debug the driver. */ -#define IDEFLOPPY_DEBUG_LOG 0 #define IDEFLOPPY_DEBUG_INFO 0 #define IDEFLOPPY_DEBUG_BUGS 1 +/* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */ +#define IDEFLOPPY_DEBUG( fmt, args... ) /* * Some drives require a longer irq timeout. @@ -185,6 +202,7 @@ u8 reserved30[2]; } idefloppy_flexible_disk_page_t; + /* * Format capacity */ @@ -250,6 +268,8 @@ #define IDEFLOPPY_DRQ_INTERRUPT 0 /* DRQ interrupt device */ #define IDEFLOPPY_MEDIA_CHANGED 1 /* Media may have changed */ #define IDEFLOPPY_USE_READ12 2 /* Use READ12/WRITE12 or READ10/WRITE10 */ +#define IDEFLOPPY_CLIK_DRIVE 3 /* Avoid commands not supported in Clik drive */ +#define IDEFLOPPY_POWERBOOK_ZIP 4 /* Kludge for Apple Powerbook Zip drive */ /* * ATAPI floppy drive packet commands @@ -625,9 +645,7 @@ struct request *rq = hwgroup->rq; int error; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "Reached idefloppy_end_request\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "Reached idefloppy_end_request\n"); switch (uptodate) { case 0: error = IDEFLOPPY_ERROR_GENERAL; break; @@ -750,21 +768,19 @@ idefloppy_floppy_t *floppy = drive->driver_data; floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq; -#if IDEFLOPPY_DEBUG_LOG - if (floppy->failed_pc) - printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq); - else - printk (KERN_INFO "ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq); -#endif /* IDEFLOPPY_DEBUG_LOG */ + if (floppy->failed_pc) { + IDEFLOPPY_DEBUG("ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq); + } + else { + IDEFLOPPY_DEBUG("ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq); + } } static void idefloppy_request_sense_callback (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: Reached idefloppy_request_sense_callback\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: Reached idefloppy_request_sense_callback\n"); if (!floppy->pc->error) { idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer); idefloppy_end_request (1,HWGROUP (drive)); @@ -781,9 +797,7 @@ { idefloppy_floppy_t *floppy = drive->driver_data; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: Reached idefloppy_pc_callback\n"); idefloppy_end_request (floppy->pc->error ? 0:1, HWGROUP(drive)); } @@ -844,9 +858,7 @@ struct request *rq = pc->rq; unsigned int temp; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n"); #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { @@ -856,26 +868,20 @@ pc->actually_transferred=pc->request_transfer; idefloppy_update_buffers (drive, pc); } -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: DMA finished\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: DMA finished\n"); } #endif /* CONFIG_BLK_DEV_IDEDMA */ status.all = GET_STAT(); /* Clear the interrupt */ if (!status.b.drq) { /* No more interrupts */ -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "Packet command completed, %d bytes transferred\n", pc->actually_transferred); clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); ide__sti(); /* local CPU only */ if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: %s: I/O error\n",drive->name); rq->errors++; if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { printk (KERN_ERR "ide-floppy: I/O error in request sense command\n"); @@ -919,9 +925,7 @@ ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD,NULL); return ide_started; } -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n"); } } if (test_bit (PC_WRITING, &pc->flags)) { @@ -987,7 +991,7 @@ * a legitimate error code was received. */ if (!test_bit (PC_ABORT, &pc->flags)) { - printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", + IDEFLOPPY_DEBUG( "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq); pc->error = IDEFLOPPY_ERROR_GENERAL; /* Giving up */ } @@ -995,9 +999,7 @@ pc->callback(drive); return ide_stopped; } -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "Retry number - %d\n",pc->retries); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "Retry number - %d\n",pc->retries); pc->retries++; pc->actually_transferred=0; /* We haven't transferred any data yet */ @@ -1037,9 +1039,7 @@ static void idefloppy_rw_callback (ide_drive_t *drive) { -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: Reached idefloppy_rw_callback\n"); idefloppy_end_request(1, HWGROUP(drive)); return; @@ -1047,9 +1047,7 @@ static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent) { -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: creating prevent removal command, prevent = %d\n", prevent); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "ide-floppy: creating prevent removal command, prevent = %d\n", prevent); idefloppy_init_pc (pc); pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD; @@ -1109,10 +1107,8 @@ int block = sector / floppy->bs_factor; int blocks = rq->nr_sectors / floppy->bs_factor; -#if IDEFLOPPY_DEBUG_LOG - printk ("create_rw1%d_cmd: block == %d, blocks == %d\n", + IDEFLOPPY_DEBUG( "create_rw1%d_cmd: block == %d, blocks == %d\n", 2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks); -#endif /* IDEFLOPPY_DEBUG_LOG */ idefloppy_init_pc (pc); if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) { @@ -1142,10 +1138,8 @@ idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_pc_t *pc; -#if IDEFLOPPY_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); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); + IDEFLOPPY_DEBUG( "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); if (rq->errors >= ERROR_MAX) { if (floppy->failed_pc != NULL) @@ -1238,6 +1232,7 @@ return 0; } + /* * Determine if a media is present in the floppy drive, and if so, * its LBA capacity. @@ -1266,7 +1261,12 @@ for (i = 0; i < descriptors; i++, descriptor++) { blocks = descriptor->blocks = ntohl (descriptor->blocks); length = descriptor->length = ntohs (descriptor->length); - if (!i && descriptor->dc == CAPACITY_CURRENT) { + if (!i) { + switch (descriptor->dc) { + case CAPACITY_UNFORMATTED: /* Clik! drive returns this instead of CAPACITY_CURRENT */ + if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) + break; /* If it is not a clik drive, break out (maintains previous driver behaviour) */ + case CAPACITY_CURRENT: /* Normal Zip/LS-120 disks */ if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length); floppy->capacity = *descriptor; @@ -1279,32 +1279,50 @@ printk (KERN_NOTICE "%s: warning: non 512 bytes block size not fully supported\n", drive->name); rc = 0; } + break; + case CAPACITY_NO_CARTRIDGE: + /* This is a KERN_ERR so it appears on screen for the user to see */ + printk (KERN_ERR "%s: No disk in drive\n", drive->name); + break; + case CAPACITY_INVALID: + printk (KERN_ERR "%s: Invalid capacity for disk in drive\n", drive->name); + break; } -#if IDEFLOPPY_DEBUG_INFO - if (!i) printk (KERN_INFO "Descriptor 0 Code: %d\n", descriptor->dc); - printk (KERN_INFO "Descriptor %d: %dkB, %d blocks, %d sector size\n", i, blocks * length / 1024, blocks, length); -#endif /* IDEFLOPPY_DEBUG_INFO */ } + if (!i) { + IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n", descriptor->dc); + } + IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d sector size\n", i, blocks * length / 1024, blocks, length); + } + + /* Clik! disk does not support get_flexible_disk_page */ + if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) (void) idefloppy_get_flexible_disk_page (drive); + drive->part[0].nr_sects = floppy->blocks * floppy->bs_factor; return rc; } + /* * Our special ide-floppy ioctl's. * - * Currently there aren't any ioctl's. + * Supports eject command */ static int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { idefloppy_pc_t pc; + idefloppy_floppy_t *floppy = drive->driver_data; if (cmd == CDROMEJECT) { if (drive->usage > 1) return -EBUSY; + /* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */ + if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { idefloppy_create_prevent_cmd (&pc, 0); (void) idefloppy_queue_pc_tail (drive, &pc); + } idefloppy_create_start_stop_cmd (&pc, 2); (void) idefloppy_queue_pc_tail (drive, &pc); return 0; @@ -1320,20 +1338,24 @@ idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_pc_t pc; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "Reached idefloppy_open\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "Reached idefloppy_open\n"); MOD_INC_USE_COUNT; if (drive->usage == 1) { + IDEFLOPPY_DEBUG( "Testing if unit is ready...\n"); idefloppy_create_test_unit_ready_cmd(&pc); if (idefloppy_queue_pc_tail(drive, &pc)) { + IDEFLOPPY_DEBUG( "Not ready, issuing start command\n"); idefloppy_create_start_stop_cmd (&pc, 1); (void) idefloppy_queue_pc_tail (drive, &pc); + } else + { + IDEFLOPPY_DEBUG( "Yes unit is ready\n"); } if (idefloppy_get_capacity (drive)) { drive->usage--; MOD_DEC_USE_COUNT; + IDEFLOPPY_DEBUG( "I/O Error Getting Capacity\n"); return -EIO; } if (floppy->wp && (filp->f_mode & 2)) { @@ -1342,8 +1364,11 @@ return -EROFS; } set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags); + /* IOMEGA Clik! drives do not support lock/unlock commands - no room for mechanism */ + if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { idefloppy_create_prevent_cmd (&pc, 1); (void) idefloppy_queue_pc_tail (drive, &pc); + } check_disk_change(inode->i_rdev); } return 0; @@ -1352,16 +1377,18 @@ static void idefloppy_release (struct inode *inode, struct file *filp, ide_drive_t *drive) { idefloppy_pc_t pc; + idefloppy_floppy_t *floppy = drive->driver_data; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "Reached idefloppy_release\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + IDEFLOPPY_DEBUG( "Reached idefloppy_release\n"); if (!drive->usage) { invalidate_buffers (inode->i_rdev); + /* IOMEGA Clik! drives do not support lock/unlock commands */ + if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { idefloppy_create_prevent_cmd (&pc, 0); (void) idefloppy_queue_pc_tail (drive, &pc); } + } MOD_DEC_USE_COUNT; } @@ -1549,6 +1576,17 @@ for (i = 0; i < 1 << PARTN_BITS; i++) max_sectors[major][minor + i] = 64; } + /* + * Guess what? The IOMEGA Clik! drive also needs the + * above fix. It makes nasty clicking noises without + * it, so please don't remove this. + */ + if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0) + { + for (i = 0; i < 1 << PARTN_BITS; i++) + max_sectors[major][minor + i] = 64; + set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags); + } (void) idefloppy_get_capacity (drive); idefloppy_add_settings(drive); @@ -1578,6 +1616,7 @@ #endif /* CONFIG_PROC_FS */ + /* * IDE subdriver functions, registered with ide.c */ @@ -1609,6 +1648,7 @@ NULL }; + /* * idefloppy_init will register the driver for each floppy. */ @@ -1641,12 +1681,16 @@ return 0; } + #ifdef MODULE +/* Initialisation code for loading the driver as a modules */ int init_module (void) { return idefloppy_init (); } + +/* Cleanup code for removing the driver module */ void cleanup_module (void) { ide_drive_t *drive; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.2.17/drivers/block/ide-pci.c Sun Jun 11 21:44:12 2000 +++ linux/drivers/block/ide-pci.c Mon Sep 11 23:03:25 2000 @@ -30,6 +30,7 @@ #define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) +#define DEVID_VP_OLDIDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) #define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000}) #define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001}) @@ -39,6 +40,7 @@ #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}) #define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, 0xd568}) /* from datasheets */ +#define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) #define DEVID_TRM290 ((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290}) #define DEVID_NS87410 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410}) #define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415}) @@ -52,6 +54,13 @@ #define IDE_IGNORE ((void *)-1) +#ifdef CONFIG_BLK_DEV_ALI15X3 +extern void ide_init_ali15x3(ide_hwif_t *); +#define INIT_ALI15X3 &ide_init_ali15x3 +#else +#define INIT_ALI15X3 NULL +#endif + #ifdef CONFIG_BLK_DEV_TRM290 extern void ide_init_trm290(ide_hwif_t *); #define INIT_TRM290 &ide_init_trm290 @@ -145,6 +154,7 @@ {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621, "OPTI621", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, {DEVID_OPTI621X,"OPTI621X", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, + {DEVID_ALI15X3, "ALI15X3", INIT_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_NS87415, "NS87415", INIT_NS87415, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_AEC6210, "AEC6210", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, @@ -451,6 +461,19 @@ devid.vid = dev->vendor; devid.did = dev->device; if (IDE_PCI_DEVID_EQ(devid, DEVID_450NX)) { + autodma_default = 0; + break; + } + /* + * Don't try and tune a VIA 82C586 or 586A + */ + if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_IDE)) + { + autodma_default = 0; + break; + } + if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_OLDIDE)) + { autodma_default = 0; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.2.17/drivers/block/ide-pmac.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/ide-pmac.c Wed Nov 8 23:00:34 2000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -93,14 +94,14 @@ /* allow up to 256 DBDMA commands per xfer */ #define MAX_DCMDS 256 -/* Wait 1.5s for disk to answer on IDE bus after +/* Wait 2s for disk to answer on IDE bus after * enable operation. * NOTE: There is at least one case I know of a disk that needs about 10sec * before anwering on the bus. I beleive we could add a kernel command * line arg to override this delay for such cases. */ -#define IDE_WAKEUP_DELAY_MS 1500 -#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */ +#define IDE_WAKEUP_DELAY_MS 2000 +#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */ static void pmac_ide_setup_dma(struct device_node *np, int ix); static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive); @@ -393,6 +394,7 @@ */ feature_set(np, FEATURE_IDE0_enable); feature_set(np, FEATURE_IOBUS_enable); + big_delay = 1; /* Poor old machines with crappy disks */ } else { /* This is necessary to enable IDE when net-booting */ printk("pmac_ide: enabling IDE bus ID %d\n", pmac_ide[i].aapl_bus_id); @@ -596,13 +598,13 @@ static __inline__ int wait_for_ready(ide_drive_t *drive) { - /* Timeout bumped for some powerbooks */ - int timeout = 2000; + /* Timeout bumped (again) for some powerbooks with old disks */ + int timeout = 10000; byte stat; while(--timeout) { stat = GET_STAT(); - if(!(stat & BUSY_STAT)) { + if (!(stat & BUSY_STAT)) { if (drive->ready_stat == 0) break; else if((stat & drive->ready_stat) || (stat & ERR_STAT)) @@ -631,20 +633,31 @@ old_select = IN_BYTE(IDE_SELECT_REG); OUT_BYTE(drive->select.all, IDE_SELECT_REG); udelay(10); - OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); - OUT_BYTE(command, IDE_NSECTOR_REG); if(wait_for_ready(drive)) { printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); goto out; } + OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); +#if 0 + /* That one cause the wallstreet to freeze, I don't know why yet. We'll have to leave with + * the bogus interrupt until I figure out what's up + */ + /* Better not leave a dangling interrupt */ + OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); +#endif + OUT_BYTE(command, IDE_NSECTOR_REG); OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG); + udelay(10); result = wait_for_ready(drive); if (result) printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); + /* May help kill the bogus interrupt */ + mdelay(1); + (void)GET_STAT(); out: OUT_BYTE(old_select, IDE_SELECT_REG); restore_flags(flags); - + return result; } @@ -848,13 +861,15 @@ #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ #ifdef CONFIG_PMAC_PBOOK -static void idepmac_sleep_disk(int i, unsigned long base) +static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base) { - struct device_node* np = pmac_ide[i].node; int j; - - /* FIXME: We only handle the master IDE */ - if (ide_hwifs[i].drives[0].media == ide_disk) { + + /* FIXME: We only handle the master IDE disk, we shoud + * try to fix CD-ROMs here + */ + switch (drive->media) { + case ide_disk: /* Spin down the drive */ outb(0xa0, base+0x60); outb(0x0, base+0x30); @@ -870,99 +885,127 @@ if (!(status & BUSY_STAT) && (status & DRQ_STAT)) break; } - } - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - feature_clear(np, FEATURE_IDE1_enable); + case ide_cdrom: + // todo break; - case 2: - feature_set(np, FEATURE_IDE2_reset); + case ide_floppy: + // todo break; } - pmac_ide[i].timings[0] = 0; - pmac_ide[i].timings[1] = 0; } -static void idepmac_wake_disk(int i, unsigned long base) +static void idepmac_wake_device(ide_drive_t *drive, int used_dma) + { + unsigned long flags; + + /* We force the IDE subdriver to check for a media change + * This must be done first or we may lost the condition + * + * Problem: This can schedule. I moved the block device + * wakeup almost late by priority because of that. + */ + DRIVER(drive)->media_change(drive); + + /* We kick the VFS too (see fix in ide.c revalidate) */ + check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS)); + +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + /* We re-enable DMA on the drive if it was active. */ + /* This doesn't work with the CD-ROM in the media-bay, probably + * because of a pending unit attention. The problem if that if I + * clear the error, the filesystem dies. + */ + if (used_dma && !ide_spin_wait_hwgroup(drive, &flags)) { + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + pmac_ide_dma_onoff(drive, 1); + HWGROUP(drive)->busy = 0; + spin_unlock_irqrestore(&io_request_lock, flags); + } +#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ +} + +static void idepmac_sleep_interface(int i, unsigned base, int mediabay) { struct device_node* np = pmac_ide[i].node; - int j; - /* Revive IDE disk and controller */ + /* We clear the timings */ + pmac_ide[i].timings[0] = 0; + pmac_ide[i].timings[1] = 0; + + /* The media bay will handle itself just fine */ + if (mediabay) + return; + + /* Disable and reset the bus */ + feature_set(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IDE0_enable); switch(pmac_ide[i].aapl_bus_id) { case 0: feature_set(np, FEATURE_IDE0_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IDE0_enable); break; case 1: feature_set(np, FEATURE_IDE1_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE1_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE1_reset); + feature_clear(np, FEATURE_IDE1_enable); break; case 2: - /* This one exists only for KL, I don't know - about any enable bit */ feature_set(np, FEATURE_IDE2_reset); - mdelay(10); - feature_clear(np, FEATURE_IDE2_reset); break; } - mdelay(IDE_WAKEUP_DELAY_MS); - - /* Reset timings */ - pmac_ide_selectproc(&ide_hwifs[i].drives[0]); - mdelay(10); - - /* Wait up to 10 seconds (enough for recent drives) */ - for (j = 0; j < 100; j++) { - int status; - mdelay(100); - status = inb(base + 0x70); - if (!(status & BUSY_STAT)) - break; - } } -/* Here we handle media bay devices */ -static void -idepmac_wake_bay(int i, unsigned long base) +static void idepmac_wake_interface(int i, unsigned long base, int mediabay) { - int timeout; + struct device_node* np = pmac_ide[i].node; + if (!mediabay) { + /* Revive IDE disk and controller */ + switch(pmac_ide[i].aapl_bus_id) { + case 0: + feature_set(np, FEATURE_IDE0_reset); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE0_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE0_reset); + break; + case 1: + feature_set(np, FEATURE_IDE1_reset); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE1_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE1_reset); + break; + case 2: + /* This one exists only for KL, I don't know + about any enable bit */ + feature_set(np, FEATURE_IDE2_reset); + mdelay(10); + feature_clear(np, FEATURE_IDE2_reset); + break; + } + } + /* Reset timings */ pmac_ide_selectproc(&ide_hwifs[i].drives[0]); mdelay(10); - - timeout = 10000; - while ((inb(base + 0x70) & BUSY_STAT) && timeout) { - mdelay(1); - --timeout; - } } /* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM * is a slave */ + static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) { int i, ret; unsigned long base; - + unsigned long flags; + int big_delay; + switch (when) { case PBOOK_SLEEP_REQUEST: break; @@ -970,37 +1013,108 @@ break; case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { + ide_hwif_t *hwif; + ide_drive_t *drive; + int unlock = 0; + if ((base = pmac_ide[i].regbase) == 0) - continue; + continue; + + hwif = &ide_hwifs[i]; + drive = &hwif->drives[0]; + + if (drive->present) { + /* Wait for HW group to complete operations */ + if (ide_spin_wait_hwgroup(drive, &flags)) { + // What can we do here ? Wake drive we had already + // put to sleep and return an error ? + } else { + unlock = 1; + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + + /* Stop the device */ + idepmac_sleep_device(drive, i, base); + + } + } /* Disable irq during sleep */ - disable_irq(pmac_ide[i].irq); + disable_irq(pmac_ide[i].irq); + if (unlock) + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Check if this is a media bay with an IDE device or not + * a media bay. + */ ret = check_media_bay_by_base(base, MB_CD); - if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) - /* not media bay - put the disk to sleep */ - idepmac_sleep_disk(i, base); + if ((ret == 0) || (ret == -ENODEV)) + idepmac_sleep_interface(i, base, (ret == 0)); } break; case PBOOK_WAKE: + big_delay = 0; + for (i = 0; i < pmac_ide_count; ++i) { + + if ((base = pmac_ide[i].regbase) == 0) + continue; + + /* Check if this is a media bay with an IDE device or not + * a media bay + */ + ret = check_media_bay_by_base(base, MB_CD); + if ((ret == 0) || (ret == -ENODEV)) { + idepmac_wake_interface(i, base, (ret == 0)); + big_delay = 1; + } + + } + /* Let hardware get up to speed */ + if (big_delay) + mdelay(IDE_WAKEUP_DELAY_MS); + for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; + ide_drive_t *drive; + int j, used_dma; + if ((base = pmac_ide[i].regbase) == 0) continue; + hwif = &ide_hwifs[i]; - /* We don't handle media bay devices this way */ - ret = check_media_bay_by_base(base, MB_CD); - if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) - idepmac_wake_disk(i, base); - else if (ret == 0) - idepmac_wake_bay(i, base); - enable_irq(pmac_ide[i].irq); + drive = &hwif->drives[0]; -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - if (hwif->drives[0].present && hwif->drives[0].using_dma) - pmac_ide_dma_onoff(&hwif->drives[0], 1); -#endif + /* Wait for the drive to come up and set it's DMA */ + if (drive->present) { + /* Wait up to 20 seconds */ + for (j = 0; j < 200; j++) { + int status; + mdelay(100); + status = inb(base + 0x70); + if (!(status & BUSY_STAT)) + break; + } + } + + /* We don't have re-configured DMA yet */ + used_dma = drive->using_dma; + drive->using_dma = 0; + + /* We resume processing on the HW group */ + spin_lock_irqsave(&io_request_lock, flags); + enable_irq(pmac_ide[i].irq); + if (drive->present) + HWGROUP(drive)->busy = 0; + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Wake the device + * We could handle the slave here + */ + if (drive->present) + idepmac_wake_device(drive, used_dma); } break; } return PBOOK_SLEEP_OK; } + #endif /* CONFIG_PMAC_PBOOK */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.2.17/drivers/block/ide-probe.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/ide-probe.c Thu Nov 2 12:55:28 2000 @@ -18,6 +18,8 @@ * by Andrea Arcangeli * Version 1.03 fix for (hwif->chipset == ide_4drives) * Version 1.04 fixed buggy treatments of known flash memory cards + * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS + * chip. */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -35,6 +37,7 @@ #include #include #include +#include /* CMOS defines */ #include #include @@ -386,6 +389,7 @@ static void probe_cmos_for_drives (ide_hwif_t *hwif) { #ifdef __i386__ + unsigned long flags; extern struct drive_info_struct drive_info; byte cmos_disks, *BIOS = (byte *) &drive_info; int unit; @@ -394,8 +398,10 @@ if (hwif->chipset == ide_pdc4030 && hwif->channel != 0) return; #endif /* CONFIG_BLK_DEV_PDC4030 */ + spin_lock_irqsave(&rtc_lock, flags); outb_p(0x12,0x70); /* specify CMOS address 0x12 */ cmos_disks = inb_p(0x71); /* read the data from 0x12 */ + spin_unlock_irqrestore(&rtc_lock, flags); /* Extract drive geometry from CMOS+BIOS if not already setup */ for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ide.c linux/drivers/block/ide.c --- v2.2.17/drivers/block/ide.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/ide.c Sat Oct 14 01:00:34 2000 @@ -1627,6 +1627,8 @@ ide_drive_t *drive; ide_hwgroup_t *hwgroup; unsigned int p, major, minor; + int old_blksize; + extern int *blksize_size[]; long flags; if ((drive = get_info_ptr(i_rdev)) == NULL) @@ -1634,6 +1636,7 @@ major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; hwgroup = HWGROUP(drive); + old_blksize = blksize_size[major][minor]; spin_lock_irqsave(&io_request_lock, flags); if (drive->busy || (drive->usage > 1)) { spin_unlock_irqrestore(&io_request_lock, flags); @@ -1651,7 +1654,10 @@ if (sb) invalidate_inodes(sb); invalidate_buffers (devp); - set_blocksize(devp, 1024); + if (!old_blksize) + set_blocksize(devp, 1024); + else + set_blocksize(devp, old_blksize); } drive->part[p].start_sect = 0; drive->part[p].nr_sects = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.2.17/drivers/block/ll_rw_blk.c Sun Jun 11 21:44:12 2000 +++ linux/drivers/block/ll_rw_blk.c Thu Oct 19 01:19:35 2000 @@ -312,7 +312,7 @@ output.queue_ID = elevator->queue_ID; output.read_latency = elevator->read_latency; output.write_latency = elevator->write_latency; - output.max_bomb_segments = elevator->max_bomb_segments; + output.max_bomb_segments = 0; ret = -EFAULT; if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t))) @@ -336,12 +336,9 @@ goto out; if (input.write_latency < 0) goto out; - if (input.max_bomb_segments <= 0) - goto out; elevator->read_latency = input.read_latency; elevator->write_latency = input.write_latency; - elevator->max_bomb_segments = input.max_bomb_segments; ret = 0; out: @@ -362,26 +359,15 @@ return -EINVAL; } -static inline int seek_to_not_starving_chunk(struct request ** req, int * lat) +static inline struct request * seek_to_not_starving_chunk(struct request * req) { - struct request * tmp = *req; - int found = 0, pos = 0; - int last_pos = 0, __lat = *lat; + struct request * tmp = req; - do { - if (tmp->elevator_latency <= 0) - { - *req = tmp; - found = 1; - last_pos = pos; - if (last_pos >= __lat) - break; - } - pos += tmp->nr_segments; - } while ((tmp = tmp->next)); - *lat -= last_pos; + while ((tmp = tmp->next)) + if ((tmp->cmd != READ && tmp->cmd != WRITE) || !tmp->elevator_latency) + req = tmp; - return found; + return req; } #define CASE_COALESCE_BUT_FIRST_REQUEST_MAYBE_BUSY \ @@ -421,56 +407,31 @@ case COMPAQ_SMART2_MAJOR+4: \ case COMPAQ_SMART2_MAJOR+5: \ case COMPAQ_SMART2_MAJOR+6: \ - case COMPAQ_SMART2_MAJOR+7: + case COMPAQ_SMART2_MAJOR+7: \ + case COMPAQ_CISS_MAJOR+0: \ + case COMPAQ_CISS_MAJOR+1: \ + case COMPAQ_CISS_MAJOR+2: \ + case COMPAQ_CISS_MAJOR+3: \ + case COMPAQ_CISS_MAJOR+4: \ + case COMPAQ_CISS_MAJOR+5: \ + case COMPAQ_CISS_MAJOR+6: \ + case COMPAQ_CISS_MAJOR+7: #define elevator_starve_rest_of_queue(req) \ do { \ struct request * tmp = (req); \ - for ((tmp) = (tmp)->next; (tmp); (tmp) = (tmp)->next) \ - (tmp)->elevator_latency--; \ + for ((tmp) = (tmp)->next; (tmp); (tmp) = (tmp)->next) { \ + if ((tmp)->cmd != READ && (tmp)->cmd != WRITE) \ + continue; \ + if (--(tmp)->elevator_latency < 0) \ + panic("elevator_starve_rest_of_queue"); \ + } \ } while (0) static inline void elevator_queue(struct request * req, - struct request * tmp, - int latency, - struct blk_dev_struct * dev, - struct request ** queue_head) + struct request * tmp) { - struct request * __tmp; - int starving, __latency; - - starving = seek_to_not_starving_chunk(&tmp, &latency); - __tmp = tmp; - __latency = latency; - - for (;; tmp = tmp->next) - { - if ((latency -= tmp->nr_segments) <= 0) - { - tmp = __tmp; - latency = __latency - tmp->nr_segments; - - if (starving) - break; - - switch (MAJOR(req->rq_dev)) - { - CASE_COALESCE_BUT_FIRST_REQUEST_MAYBE_BUSY - if (tmp == dev->current_request) - default: - goto link; - CASE_COALESCE_ALSO_FIRST_REQUEST - } - - latency += tmp->nr_segments; - req->next = tmp; - *queue_head = req; - goto after_link; - } - - if (!tmp->next) - break; - + for (tmp = seek_to_not_starving_chunk(tmp); tmp->next; tmp = tmp->next) { { const int after_current = IN_ORDER(tmp,req); const int before_next = IN_ORDER(req,tmp->next); @@ -485,13 +446,9 @@ } } - link: req->next = tmp->next; tmp->next = req; - after_link: - req->elevator_latency = latency; - elevator_starve_rest_of_queue(req); } @@ -513,7 +470,6 @@ short disk_index; unsigned long flags; int queue_new_request = 0; - int latency; switch (major) { case DAC960_MAJOR+0: @@ -544,7 +500,7 @@ if (disk_index >= 0 && disk_index < 4) drive_stat_acct(req->cmd, req->nr_sectors, disk_index); - latency = get_request_latency(&dev->elevator, req->cmd); + req->elevator_latency = get_request_latency(&dev->elevator, req->cmd); /* * We use the goto to reduce locking complexity @@ -556,19 +512,20 @@ mark_buffer_clean(req->bh); if (!(tmp = *current_request)) { req->next = NULL; - req->elevator_latency = latency; *current_request = req; if (dev->current_request != &dev->plug) queue_new_request = 1; goto out; } - elevator_queue(req, tmp, latency, dev, current_request); + elevator_queue(req, tmp); /* for SCSI devices, call request_fn unconditionally */ if (scsi_blk_major(major) || (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) || (major >= COMPAQ_SMART2_MAJOR+0 && - major <= COMPAQ_SMART2_MAJOR+7)) + major <= COMPAQ_SMART2_MAJOR+7) || + (major >= COMPAQ_CISS_MAJOR+0 && + major <= COMPAQ_CISS_MAJOR+7)) queue_new_request = 1; out: @@ -610,28 +567,13 @@ wake_up (&wait_for_request); } -#define read_pendings(req) \ -({ \ - int __ret = 0; \ - struct request * tmp = (req); \ - do { \ - if (tmp->cmd == READ) \ - { \ - __ret = 1; \ - break; \ - } \ - tmp = tmp->next; \ - } while (tmp); \ - __ret; \ -}) - void make_request(int major, int rw, struct buffer_head * bh) { unsigned int sector, count; struct request * req, * prev; int rw_ahead, max_req, max_sectors, max_segments; unsigned long flags; - int latency, starving; + int back, front; count = bh->b_size >> 9; sector = bh->b_rsector; @@ -708,8 +650,6 @@ max_sectors = get_max_sectors(bh->b_rdev); max_segments = get_max_segments(bh->b_rdev); - latency = get_request_latency(&blk_dev[major].elevator, rw); - /* * Now we acquire the request spinlock, we have to be mega careful * not to schedule or do something nonatomic @@ -733,33 +673,31 @@ * entry may be busy being processed and we thus can't change it. */ if (req == blk_dev[major].current_request) - { if (!(req = req->next)) break; - latency -= req->nr_segments; - } /* fall through */ CASE_COALESCE_ALSO_FIRST_REQUEST - /* avoid write-bombs to not hurt iteractiveness of reads */ - if (rw != READ && read_pendings(req)) - max_segments = blk_dev[major].elevator.max_bomb_segments; - - starving = seek_to_not_starving_chunk(&req, &latency); + req = seek_to_not_starving_chunk(req); prev = NULL; + back = front = 0; do { - if (req->sem) - continue; if (req->cmd != rw) continue; + if (req->rq_dev != bh->b_rdev) + continue; + if (req->sector + req->nr_sectors == sector) + back = 1; + else if (req->sector - count == sector) + front = 1; + if (req->nr_sectors + count > max_sectors) continue; - if (req->rq_dev != bh->b_rdev) + if (req->sem) continue; + /* Can we add it to the end of this request? */ - if (req->sector + req->nr_sectors == sector) { - if (latency - req->nr_segments < 0) - break; + if (back) { if (req->bhtail->b_data + req->bhtail->b_size != bh->b_data) { if (req->nr_segments < max_segments) @@ -770,16 +708,18 @@ req->bhtail = bh; req->nr_sectors += count; - /* latency stuff */ - if ((latency -= req->nr_segments) < req->elevator_latency) - req->elevator_latency = latency; elevator_starve_rest_of_queue(req); /* Can we now merge this req with the next? */ attempt_merge(req, max_sectors, max_segments); /* or to the beginning? */ - } else if (req->sector - count == sector) { - if (!prev && starving) + } else if (front) { + /* + * Check that we didn't seek on a starving request, + * that could happen only at the first pass, thus + * do that only if prev is NULL. + */ + if (!prev && ((req->cmd != READ && req->cmd != WRITE) || !req->elevator_latency)) break; if (bh->b_data + bh->b_size != req->bh->b_data) { @@ -795,8 +735,8 @@ req->nr_sectors += count; /* latency stuff */ - if (latency < --req->elevator_latency) - req->elevator_latency = latency; + --req->elevator_latency; + elevator_starve_rest_of_queue(req); if (prev) @@ -809,7 +749,7 @@ return; } while (prev = req, - (latency -= req->nr_segments) >= 0 && (req = req->next) != NULL); + !front && !back && (req = req->next) != NULL); } /* find an unused request. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/macide.c linux/drivers/block/macide.c --- v2.2.17/drivers/block/macide.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/macide.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,122 @@ +/* + * linux/drivers/block/macide.c -- Macintosh IDE Driver + * + * Copyright (C) 1998 by Michael Schmitz + * + * This driver was written based on information obtained from the MacOS IDE + * driver binary by Mikael Forselius + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "ide.h" + +#include +#include +#include + + /* + * Base of the IDE interface (see ATAManager ROM code) + */ + +#define MAC_HD_BASE 0x50f1a000 + + /* + * Offsets from the above base (scaling 4) + */ + +#define MAC_HD_DATA 0x00 +#define MAC_HD_ERROR 0x04 /* see err-bits */ +#define MAC_HD_NSECTOR 0x08 /* nr of sectors to read/write */ +#define MAC_HD_SECTOR 0x0c /* starting sector */ +#define MAC_HD_LCYL 0x10 /* starting cylinder */ +#define MAC_HD_HCYL 0x14 /* high byte of starting cyl */ +#define MAC_HD_SELECT 0x18 /* 101dhhhh , d=drive, hhhh=head */ +#define MAC_HD_STATUS 0x1c /* see status-bits */ +#define MAC_HD_CONTROL 0x38 /* control/altstatus */ + +static const int macide_offsets[IDE_NR_PORTS] = { + MAC_HD_DATA, MAC_HD_ERROR, MAC_HD_NSECTOR, MAC_HD_SECTOR, MAC_HD_LCYL, + MAC_HD_HCYL, MAC_HD_SELECT, MAC_HD_STATUS, MAC_HD_CONTROL +}; + + /* + * Other registers + */ + + /* + * IDE interrupt status register for both (?) hwifs on Quadra + * Initial setting: 0xc + * Guessing again: + * Bit 0+1: some interrupt flags + * Bit 2+3: some interrupt enable + * Bit 4: ?? + * Bit 5: IDE interrupt flag (any hwif) + * Bit 6: maybe IDE interrupt enable (any hwif) ?? + * Bit 7: Any interrupt condition + * + * Only relevant item: bit 5, to be checked by mac_ack_intr + */ + +#define MAC_HD_ISR 0x101 + +static int mac_ack_intr(ide_hwif_t* hwif) +{ + unsigned char isr; + isr = readb(MAC_HD_BASE + MAC_HD_ISR); + if (isr & (1<<5)) { + writeb(isr & ~(1<<5), MAC_HD_BASE + MAC_HD_ISR); + return 1; + } + + return 0; +} + + /* + * Probe for a Macintosh IDE interface + */ + +__initfunc(int macide_probe_hwif(int index, ide_hwif_t *hwif)) +{ + static int mac_index = 0; + + if (!MACH_IS_MAC || macintosh_config->ide_type == 0) + return 0; + + if (!mac_index) { + if (macintosh_config->ide_type == MAC_IDE_QUADRA) + printk("ide%d: Macintosh Quadra IDE interface\n", + index); + else + printk("ide%d: Macintosh Powerbook IDE interface\n", + index); + mac_index = index+1; + } + if (mac_index == index+1) { + ide_setup_ports(hwif, + (ide_ioreg_t)MAC_HD_BASE, + macide_offsets, + 0, NULL); + + if (macintosh_config->ide_type == MAC_IDE_QUADRA) { + hwif->irq = IRQ_NUBUS_F; + } else { + /* PowerBooks - Slot C is the Comm Slot on the + Q630 */ + hwif->irq = IRQ_NUBUS_C; + } + hwif->ack_intr = mac_ack_intr; + + return 1; + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.2.17/drivers/block/nbd.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/nbd.c Sat Oct 28 20:13:14 2000 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,7 @@ do { + sock->sk->allocation = GFP_BUFFER; iov.iov_base = buf; iov.iov_len = size; msg.msg_name = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/q40ide.c linux/drivers/block/q40ide.c --- v2.2.17/drivers/block/q40ide.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/q40ide.c Fri Oct 13 23:59:43 2000 @@ -0,0 +1,109 @@ +/* + * linux/drivers/block/q40ide.c -- Q40 I/O port IDE Driver + * + * original file created 12 Jul 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * RZ: + * almost identical with pcide.c, maybe we can merge it later. + * Differences: + * max 2 HWIFS for now + * translate portaddresses to q40 native addresses (not yet...) instead rely on in/out[bw] + * address translation + * + */ + +#include +#include +#include +#include +#include + +#include "ide.h" + + /* + * Bases of the IDE interfaces + */ + +#define PCIDE_NUM_HWIFS 2 + +#define PCIDE_BASE1 0x1f0 +#define PCIDE_BASE2 0x170 +#define PCIDE_BASE3 0x1e8 +#define PCIDE_BASE4 0x168 +#define PCIDE_BASE5 0x1e0 +#define PCIDE_BASE6 0x160 + +static const q40ide_ioreg_t pcide_bases[PCIDE_NUM_HWIFS] = { + PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5, + PCIDE_BASE6 */ +}; + + + /* + * Offsets from one of the above bases + */ + +#undef HD_DATA +#define HD_DATA 0x1f0 + +#define PCIDE_REG(x) ((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1)) + +static const int pcide_offsets[IDE_NR_PORTS] = { + PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR), + PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS), + PCIDE_REG(CMD) +}; + +int q40ide_default_irq(q40ide_ioreg_t base) +{ + switch (base) { + case 0x1f0: return 14; + case 0x170: return 15; + case 0x1e8: return 11; + default: + return 0; + } +} + +void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq) +{ + q40ide_ioreg_t port = base; + int i = 8; + + while (i--) + *p++ = port++; + *p++ = base + 0x206; + if (irq != NULL) + *irq = 0; +} + + + /* + * Probe for PC IDE interfaces + */ + +int q40ide_probe_hwif(int index, ide_hwif_t *hwif) +{ + static int pcide_index[PCIDE_NUM_HWIFS] = { 0, }; + int i; + + if (!MACH_IS_Q40) + return 0; + + for (i = 0; i < PCIDE_NUM_HWIFS; i++) { + if (!pcide_index[i]) { + /*printk("ide%d: Q40 IDE interface\n", index);*/ + pcide_index[i] = index+1; + } + if (pcide_index[i] == index+1) { + ide_setup_ports(hwif,(ide_ioreg_t) pcide_bases[i], pcide_offsets, 0, /*q40_ack_intr???*/ NULL); + hwif->irq = ide_default_irq((ide_ioreg_t)pcide_bases[i]); /*q40_ide_irq[i]; */ /* 14 */ + return 1; + } + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/raid1.c linux/drivers/block/raid1.c --- v2.2.17/drivers/block/raid1.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/raid1.c Sat Oct 28 11:12:10 2000 @@ -209,7 +209,7 @@ PRINTK(("raid1_make_request().\n")); while (!( /* FIXME: now we are rather fault tolerant than nice */ - r1_bh = kmalloc (sizeof (struct raid1_bh), GFP_KERNEL) + r1_bh = kmalloc (sizeof (struct raid1_bh), GFP_BUFFER) ) ) { printk ("raid1_make_request(#1): out of memory\n"); @@ -301,7 +301,7 @@ * of this function to grok the difference ;) */ while (!( /* FIXME: now we are rather fault tolerant than nice */ - mirror_bh[i] = kmalloc (sizeof (struct buffer_head), GFP_KERNEL) + mirror_bh[i] = kmalloc (sizeof (struct buffer_head), GFP_BUFFER) ) ) { printk ("raid1_make_request(#2): out of memory\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/rd.c linux/drivers/block/rd.c --- v2.2.17/drivers/block/rd.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/block/rd.c Wed Nov 8 23:00:34 2000 @@ -614,9 +614,11 @@ #ifdef CONFIG_MAC_FLOPPY if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(ROOT_DEV)); +#ifdef CONFIG_BLK_DEV_INITRD else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(real_root_dev)); #endif +#endif printk(KERN_NOTICE "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n"); wait_for_keypress(); @@ -653,7 +655,9 @@ #define OF(args) args +#ifndef memzero #define memzero(s, n) memset ((s), 0, (n)) +#endif typedef unsigned char uch; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/rz1000.c linux/drivers/block/rz1000.c --- v2.2.17/drivers/block/rz1000.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/rz1000.c Fri Sep 29 10:11:45 2000 @@ -86,9 +86,9 @@ { struct pci_dev *dev = NULL; - while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev)) + while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))) init_rz1000 (dev, "RZ1000"); - while (dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev)) + while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))) init_rz1000 (dev, "RZ1001"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c --- v2.2.17/drivers/block/swim_iop.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/block/swim_iop.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,674 @@ +/* + * Driver for the SWIM (Super Woz Integrated Machine) IOP + * floppy controller on the Macintosh IIfx and Quadra 900/950 + * + * Written by Joshua M. Thompson (funaho@jurai.org) + * based on the SWIM3 driver (c) 1996 by 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. + * + * 1999-06-12 (jmt) - Initial implementation. + */ + +/* + * ------------------- + * Theory of Operation + * ------------------- + * + * Since the SWIM IOP is message-driven we implement a simple request queue + * system. One outstanding request may be queued at any given time (this is + * an IOP limitation); only when that request has completed can a new request + * be sent. + */ + +/* This has to be defined before some of the #includes below */ + +#define MAJOR_NR FLOPPY_MAJOR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "Version 0.1 (1999-06-12)" + +#define MAX_FLOPPIES 4 + +#define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 + +enum swim_state { + idle, + available, + revalidating, + transferring, + ejecting +}; + +struct floppy_state { + enum swim_state state; + int drive_num; /* device number */ + int secpercyl; /* disk geometry information */ + int secpertrack; + int total_secs; + int write_prot; /* 1 if write-protected, 0 if not, -1 dunno */ + int ref_count; + struct timer_list timeout; + int ejected; + struct wait_queue *wait; + int wanted; + int timeout_pending; +}; + +struct swim_iop_req { + int sent; + int complete; + __u8 command[32]; + struct floppy_state *fs; + void (*done)(struct swim_iop_req *); +}; + +static struct swim_iop_req *current_req; +static int floppy_count; + +static struct floppy_state floppy_states[MAX_FLOPPIES]; + +static int floppy_blocksizes[2] = {512,512}; +static int floppy_sizes[2] = {2880,2880}; + +static char *drive_names[7] = { + "not installed", /* DRV_NONE */ + "unknown (1)", /* DRV_UNKNOWN */ + "a 400K drive", /* DRV_400K */ + "an 800K drive" /* DRV_800K */ + "unknown (4)", /* ???? */ + "an FDHD", /* DRV_FDHD */ + "unknown (6)", /* ???? */ + "an Apple HD20" /* DRV_HD20 */ +}; + +int swimiop_init(void); +static void swimiop_init_request(struct swim_iop_req *); +static int swimiop_send_request(struct swim_iop_req *); +static void swimiop_receive(struct iop_msg *, struct pt_regs *); +static void swimiop_status_update(int, struct swim_drvstatus *); +static int swimiop_eject(struct floppy_state *fs); + +static ssize_t floppy_read(struct file *filp, char *buf, + size_t count, loff_t *ppos); +static ssize_t floppy_write(struct file *filp, const char *buf, + size_t count, loff_t *ppos); +static int floppy_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param); +static int floppy_open(struct inode *inode, struct file *filp); +static int floppy_release(struct inode *inode, struct file *filp); +static int floppy_check_change(kdev_t dev); +static int floppy_revalidate(kdev_t dev); +static int grab_drive(struct floppy_state *fs, enum swim_state state, + int interruptible); +static void release_drive(struct floppy_state *fs); +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 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 */ +}; + +/* + * SWIM IOP initialization + */ + +int swimiop_init(void) +{ + volatile struct swim_iop_req req; + struct swimcmd_status *cmd = (struct swimcmd_status *) &req.command[0]; + struct swim_drvstatus *ds = &cmd->status; + struct floppy_state *fs; + int i; + + current_req = NULL; + floppy_count = 0; + + if (!iop_ism_present) return -ENODEV; + + if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + printk(KERN_ERR "SWIM-IOP: Unable to get major %d for floppy\n", + MAJOR_NR); + return -EBUSY; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_size[MAJOR_NR] = floppy_sizes; + + printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n", + DRIVER_VERSION); + + if (iop_listen(SWIM_IOP, SWIM_CHAN, swimiop_receive, "SWIM") != 0) { + printk(KERN_ERR "SWIM-IOP: IOP channel already in use; can't initialize.\n"); + return -EBUSY; + } + + printk(KERN_ERR "SWIM_IOP: probing for installed drives.\n"); + + for (i = 0 ; i < MAX_FLOPPIES ; i++) { + memset(&floppy_states[i], 0, sizeof(struct floppy_state)); + fs = &floppy_states[floppy_count]; + + swimiop_init_request(&req); + cmd->code = CMD_STATUS; + cmd->drive_num = i + 1; + if (swimiop_send_request(&req) != 0) continue; + while (!req.complete); + if (cmd->error != 0) { + printk(KERN_ERR "SWIM-IOP: probe on drive %d returned error %d\n", i, (uint) cmd->error); + continue; + } + if (ds->installed != 0x01) continue; + printk("SWIM-IOP: drive %d is %s (%s, %s, %s, %s)\n", i, + drive_names[ds->info.type], + ds->info.external? "ext" : "int", + ds->info.scsi? "scsi" : "floppy", + ds->info.fixed? "fixed" : "removable", + ds->info.secondary? "secondary" : "primary"); + swimiop_status_update(floppy_count, ds); + fs->state = idle; + + init_timer(&fs->timeout); + floppy_count++; + } + printk("SWIM-IOP: detected %d installed drives.\n", floppy_count); + + do_floppy = NULL; + + return 0; +} + +static void swimiop_init_request(struct swim_iop_req *req) +{ + req->sent = 0; + req->complete = 0; + req->done = NULL; +} + +static int swimiop_send_request(struct swim_iop_req *req) +{ + unsigned long cpu_flags; + int err; + + /* It's doubtful an interrupt routine would try to send */ + /* a SWIM request, but I'd rather play it safe here. */ + + save_flags(cpu_flags); + cli(); + + if (current_req != NULL) { + restore_flags(cpu_flags); + return -ENOMEM; + } + + current_req = req; + + /* Interrupts should be back on for iop_send_message() */ + + restore_flags(cpu_flags); + + err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req, + sizeof(req->command), (__u8 *) &req->command[0], + swimiop_receive); + + /* No race condition here; we own current_req at this point */ + + if (err) { + current_req = NULL; + } else { + req->sent = 1; + } + return err; +} + +/* + * Receive a SWIM message from the IOP. + * + * This will be called in two cases: + * + * 1. A message has been successfully sent to the IOP. + * 2. An unsolicited message was received from the IOP. + */ + +void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs) +{ + struct swim_iop_req *req; + struct swimmsg_status *sm; + struct swim_drvstatus *ds; + + req = current_req; + + switch(msg->status) { + case IOP_MSGSTATUS_COMPLETE: + memcpy(&req->command[0], &msg->reply[0], sizeof(req->command)); + req->complete = 1; + if (req->done) (*req->done)(req); + current_req = NULL; + break; + case IOP_MSGSTATUS_UNSOL: + sm = (struct swimmsg_status *) &msg->message[0]; + ds = &sm->status; + swimiop_status_update(sm->drive_num, ds); + iop_complete_message(msg); + break; + } +} + +static void swimiop_status_update(int drive_num, struct swim_drvstatus *ds) +{ + struct floppy_state *fs = &floppy_states[drive_num]; + + fs->write_prot = (ds->write_prot == 0x80); + if ((ds->disk_in_drive != 0x01) && (ds->disk_in_drive != 0x02)) { + fs->ejected = 1; + } else { + fs->ejected = 0; + } + switch(ds->info.type) { + case DRV_400K: + fs->secpercyl = 10; + fs->secpertrack = 10; + fs->total_secs = 800; + break; + case DRV_800K: + fs->secpercyl = 20; + fs->secpertrack = 10; + fs->total_secs = 1600; + break; + case DRV_FDHD: + fs->secpercyl = 36; + fs->secpertrack = 18; + fs->total_secs = 2880; + break; + default: + fs->secpercyl = 0; + fs->secpertrack = 0; + fs->total_secs = 0; + break; + } +} + +static int swimiop_eject(struct floppy_state *fs) +{ + int err, n; + struct swim_iop_req req; + struct swimcmd_eject *cmd = (struct swimcmd_eject *) &req.command[0]; + + err = grab_drive(fs, ejecting, 1); + if (err) return err; + + swimiop_init_request(&req); + cmd->code = CMD_EJECT; + cmd->drive_num = fs->drive_num; + err = swimiop_send_request(&req); + if (err) { + release_drive(fs); + return err; + } + for (n = 2*HZ; n > 0; --n) { + if (req.complete) break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + release_drive(fs); + return cmd->error; +} + +static ssize_t floppy_read(struct file *filp, char *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + fs = &floppy_states[devnum]; + if (fs->ejected) + 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; + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + check_disk_change(inode->i_rdev); + fs = &floppy_states[devnum]; + if (fs->ejected) + return -ENXIO; + if (fs->write_prot) + return -EROFS; + return block_write(filp, buf, count, ppos); +} + +static struct floppy_struct floppy_type = + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ + +static int floppy_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ + struct floppy_state *fs; + int err; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + + if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) || + ((cmd & 0x80) && !suser())) + return -EPERM; + + fs = &floppy_states[devnum]; + + switch (cmd) { + case FDEJECT: + if (fs->ref_count != 1) + return -EBUSY; + err = swimiop_eject(fs); + return err; + case FDGETPRM: + err = copy_to_user((void *) param, (void *) &floppy_type, + sizeof(struct floppy_struct)); + return err; + } + return -ENOIOCTLCMD; +} + +static int floppy_open(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int err; + int devnum = MINOR(inode->i_rdev); + + if (devnum >= floppy_count) + return -ENODEV; + if (filp == 0) + return -EIO; + + fs = &floppy_states[devnum]; + err = 0; + if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; + + if (err == 0 && (filp->f_flags & O_NDELAY) == 0 + && (filp->f_mode & 3)) { + check_disk_change(inode->i_rdev); + if (fs->ejected) + err = -ENXIO; + } + + if (err == 0 && (filp->f_mode & 2)) { + if (fs->write_prot) + err = -EROFS; + } + + if (err) return err; + + if (filp->f_flags & O_EXCL) + fs->ref_count = -1; + 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; +} + +static int floppy_release(struct inode *inode, struct file *filp) +{ + struct floppy_state *fs; + int devnum = MINOR(inode->i_rdev); + + 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; +} + +static int floppy_check_change(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + return fs->ejected; +} + +static int floppy_revalidate(kdev_t dev) +{ + struct floppy_state *fs; + int devnum = MINOR(dev); + + if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) + return 0; + + fs = &floppy_states[devnum]; + + grab_drive(fs, revalidating, 0); + /* yadda, yadda */ + release_drive(fs); + + return 0; +} + +static void floppy_off(unsigned int nr) +{ +} + +static int grab_drive(struct floppy_state *fs, enum swim_state state, + int interruptible) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (fs->state != idle) { + ++fs->wanted; + while (fs->state != available) { + if (interruptible && signal_pending(current)) { + --fs->wanted; + restore_flags(flags); + return -EINTR; + } + interruptible_sleep_on(&fs->wait); + } + --fs->wanted; + } + fs->state = state; + restore_flags(flags); + return 0; +} + +static void release_drive(struct floppy_state *fs) +{ + unsigned long flags; + + save_flags(flags); + cli(); + fs->state = idle; + start_request(fs); + restore_flags(flags); +} + +static void set_timeout(struct floppy_state *fs, int nticks, + void (*proc)(unsigned long)) +{ + unsigned long flags; + + save_flags(flags); cli(); + if (fs->timeout_pending) + del_timer(&fs->timeout); + fs->timeout.expires = jiffies + nticks; + fs->timeout.function = proc; + fs->timeout.data = (unsigned long) fs; + add_timer(&fs->timeout); + fs->timeout_pending = 1; + restore_flags(flags); +} + +static void do_fd_request(void) +{ + int i; + + for (i = 0 ; i < floppy_count ; i++) { + start_request(&floppy_states[i]); + } +} + +static void fd_request_complete(struct swim_iop_req *req) +{ + struct floppy_state *fs = req->fs; + struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req->command[0]; + + del_timer(&fs->timeout); + fs->timeout_pending = 0; + fs->state = idle; + if (cmd->error) { + printk(KERN_ERR "SWIM-IOP: error %d on read/write request.\n", cmd->error); + end_request(0); + } else { + CURRENT->sector += cmd->num_blocks; + CURRENT->current_nr_sectors -= cmd->num_blocks; + if (CURRENT->current_nr_sectors <= 0) { + end_request(1); + return; + } + } + start_request(fs); +} + +static void fd_request_timeout(unsigned long data) +{ + struct floppy_state *fs = (struct floppy_state *) data; + + fs->timeout_pending = 0; + end_request(0); + fs->state = idle; +} + +static void start_request(struct floppy_state *fs) +{ + volatile struct swim_iop_req req; + struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req.command[0]; + + if (fs->state == idle && fs->wanted) { + fs->state = available; + wake_up(&fs->wait); + return; + } + while (CURRENT && fs->state == idle) { + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + if (CURRENT->bh && !buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); +#if 0 + printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n", + kdev_t_to_nr(CURRENT->rq_dev), CURRENT->cmd, + CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer); + printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n", + CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors); +#endif + + if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) { + end_request(0); + continue; + } + if (CURRENT->current_nr_sectors == 0) { + end_request(1); + continue; + } + if (fs->ejected) { + end_request(0); + continue; + } + + swimiop_init_request(&req); + req.fs = fs; + req.done = fd_request_complete; + + if (CURRENT->cmd == WRITE) { + if (fs->write_prot) { + end_request(0); + continue; + } + cmd->code = CMD_WRITE; + } else { + cmd->code = CMD_READ; + + } + cmd->drive_num = fs->drive_num; + cmd->buffer = CURRENT->buffer; + cmd->first_block = CURRENT->sector; + cmd->num_blocks = CURRENT->current_nr_sectors; + + if (swimiop_send_request(&req)) { + end_request(0); + continue; + } + + set_timeout(fs, HZ*CURRENT->current_nr_sectors, + fd_request_timeout); + + fs->state = transferring; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/block/z2ram.c linux/drivers/block/z2ram.c --- v2.2.17/drivers/block/z2ram.c Fri Apr 21 12:45:50 2000 +++ linux/drivers/block/z2ram.c Fri Oct 13 23:58:25 2000 @@ -32,23 +32,18 @@ #include #include #include - -#if defined(MODULE) #include -#endif #include #include #include -#ifdef CONFIG_APUS #include #include -#endif #include -extern int num_memory; -extern struct mem_info memory[NUM_MEMINFO]; +extern int m68k_realnum_memory; +extern struct mem_info m68k_memory[NUM_MEMINFO]; #define TRUE (1) #define FALSE (0) @@ -191,14 +186,14 @@ int index = device - Z2MINOR_MEMLIST1 + 1; unsigned long size, paddr, vaddr; - if (index >= num_memory) { + if (index >= m68k_realnum_memory) { printk( KERN_ERR DEVICE_NAME ": no such entry in z2ram_map\n" ); return -ENOMEM; } - paddr = memory[index].addr; - size = memory[index].size & ~(Z2RAM_CHUNKSIZE-1); + paddr = m68k_memory[index].addr; + size = m68k_memory[index].size & ~(Z2RAM_CHUNKSIZE-1); #ifdef __powerpc__ /* FIXME: ioremap doesn't build correct memory tables. */ @@ -212,8 +207,7 @@ _PAGE_WRITETHRU); #else - vaddr = kernel_map (paddr, size, KERNELMAP_FULL_CACHING, - NULL); + vaddr = (unsigned long)ioremap(paddr, size); #endif z2ram_map = kmalloc((size/Z2RAM_CHUNKSIZE)*sizeof(z2ram_map[0]), @@ -316,9 +310,7 @@ blk_size[ MAJOR_NR ] = z2_sizes; } -#if defined(MODULE) MOD_INC_USE_COUNT; -#endif return 0; } @@ -331,9 +323,11 @@ sync_dev( inode->i_rdev ); -#if defined(MODULE) + /* + * FIXME: unmap memory + */ + MOD_DEC_USE_COUNT; -#endif return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.2.17/drivers/cdrom/cdrom.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/cdrom/cdrom.c Mon Oct 2 10:21:52 2000 @@ -82,17 +82,17 @@ Thanks to Grant R. Guenther for spotting this bug. -- Made a few things more pedanticly correct. -2.50 Oct 19, 1998 - Jens Axboe +2.50 Oct 19, 1998 - Jens Axboe -- New maintainers! Erik was too busy to continue the work on the driver, - so now Chris Zwilling and Jens Axboe + so now Chris Zwilling and Jens Axboe will do their best to follow in his footsteps - 2.51 Dec 20, 1998 - Jens Axboe + 2.51 Dec 20, 1998 - Jens Axboe -- Check if drive is capable of doing what we ask before blindly changing cdi->options in various ioctl. -- Added version to proc entry. - 2.52 Jan 16, 1999 - Jens Axboe + 2.52 Jan 16, 1999 - Jens Axboe -- Fixed an error in open_for_data where we would sometimes not return the correct error value. Thanks Huba Gaspar . -- Fixed module usage count - usage was based on /proc/sys/dev @@ -101,7 +101,7 @@ dev would be removed even though it was used. cdrom.c just illuminated that bug. - 2.53 Feb 22, 1999 - Jens Axboe + 2.53 Feb 22, 1999 - Jens Axboe -- Fixup of several ioctl calls, in particular CDROM_SET_OPTIONS has been "rewritten" because capabilities and options aren't in sync. They should be... @@ -111,16 +111,16 @@ -- Added CDROM_GET_CAPABILITY ioctl. This relieves userspace programs from parsing /proc/sys/dev/cdrom/info. - 2.54 Mar 15, 1999 - Jens Axboe + 2.54 Mar 15, 1999 - Jens Axboe -- Check capability mask from low level driver when counting tracks as per suggestion from Corey J. Scotts . - 2.55 Apr 25, 1999 - Jens Axboe + 2.55 Apr 25, 1999 - Jens Axboe -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of CDC_CLOSE_TRAY. -- proc info didn't mask against capabilities mask. - 3.00 Aug 5, 1999 - Jens Axboe + 3.00 Aug 5, 1999 - Jens Axboe -- Unified audio ioctl handling across CD-ROM drivers. A lot of the code was duplicated before. Drives that support the generic packet interface are now being fed packets from here instead. @@ -138,13 +138,13 @@ -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for doing this anyway, with the generic_packet addition. - 3.01 Aug 6, 1999 - Jens Axboe + 3.01 Aug 6, 1999 - Jens Axboe -- Fix up the sysctl handling so that the option flags get set correctly. -- Fix up ioctl handling so the device specific ones actually get called :). - 3.02 Aug 8, 1999 - Jens Axboe + 3.02 Aug 8, 1999 - Jens Axboe -- Fixed volume control on SCSI drives (or others with longer audio page). -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath @@ -153,7 +153,7 @@ DVD patches for ide-cd and while I rearranged and unified them, the interface is still the same. - 3.03 Sep 1, 1999 - Jens Axboe + 3.03 Sep 1, 1999 - Jens Axboe -- Moved the rest of the audio ioctls from the CD-ROM drivers here. Only CDROMREADTOCENTRY and CDROMREADTOCHDR are left. -- Moved the CDROMREADxxx ioctls in here. @@ -164,7 +164,7 @@ drivers are updated as well. -- Various other cleanups. - 3.04 Sep 12, 1999 - Jens Axboe + 3.04 Sep 12, 1999 - Jens Axboe -- Fixed a couple of possible memory leaks (if an operation failed and we didn't free the buffer before returning the error). -- Integrated Uniform CD Changer handling from Richard Sharman @@ -178,7 +178,7 @@ -- Export cdrom_mode_sense and cdrom_mode_select. -- init_cdrom_command() for setting up a cgc command. - 3.05 Oct 24, 1999 - Jens Axboe + 3.05 Oct 24, 1999 - Jens Axboe -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually impossible to send the drive data in a sensible way. -- Lowered stack usage in mmc_ioctl(), dvd_read_disckey(), and @@ -187,7 +187,7 @@ -- Fixed CDDA ripping with cdda2wav - accept much larger requests of number of frames and split the reads in blocks of 8. - 3.06 Dec 13, 1999 - Jens Axboe + 3.06 Dec 13, 1999 - Jens Axboe -- Added support for changing the region of DVD drives. -- Added sense data to generic command. @@ -1106,6 +1106,8 @@ cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); setup_report_key(&cgc, 0, 8); memset(&rpc_state, 0, sizeof(rpc_state_t)); + cgc.buffer = (char *) &rpc_state; + cgc.buffer = (char *) &rpc_state; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; @@ -1604,7 +1606,7 @@ return -EDRIVE_CANT_DO_THIS; keeplocked = arg ? 1 : 0; /* don't unlock the door on multiple opens */ - if ((cdi->use_count != 1) && !arg) + if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN)) return -EBUSY; return cdo->lock_door(cdi, arg); } @@ -1966,19 +1968,6 @@ /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ return 0; } - case CDROMPLAYTRKIND: { - struct cdrom_ti ti; - - cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); - IOCTL_IN(arg, struct cdrom_ti, ti); - - cgc.cmd[0] = GPCMD_PLAY_AUDIO_TI; - cgc.cmd[4] = ti.cdti_trk0; - cgc.cmd[5] = ti.cdti_ind0; - cgc.cmd[7] = ti.cdti_trk1; - cgc.cmd[8] = ti.cdti_ind1; - return cdo->generic_packet(cdi, &cgc); - } case CDROMPLAYMSF: { struct cdrom_msf msf; cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); @@ -2565,6 +2554,7 @@ * Note: only the top-level directory needs to do this; if * a lower level is referenced, the parent will be as well. */ +#ifdef CONFIG_PROC_FS static void cdrom_procfs_modcount(struct inode *inode, int fill) { if (fill) { @@ -2573,6 +2563,7 @@ MOD_DEC_USE_COUNT; } } +#endif static void cdrom_sysctl_register(void) { @@ -2582,7 +2573,9 @@ return; cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); +#ifdef CONFIG_PROC_FS cdrom_root_table->child->de->fill_inode = &cdrom_procfs_modcount; +#endif /* set the defaults */ cdrom_sysctl_settings.autoclose = autoclose; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/Config.in linux/drivers/char/Config.in --- v2.2.17/drivers/char/Config.in Sun Jun 11 21:44:12 2000 +++ linux/drivers/char/Config.in Wed Nov 8 23:00:34 2000 @@ -66,7 +66,7 @@ bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK fi fi - + bool 'Mouse Support (not serial mice)' CONFIG_MOUSE if [ "$CONFIG_MOUSE" = "y" ]; then mainmenu_option next_comment @@ -106,6 +106,7 @@ bool ' Fan Tachometer' CONFIG_WDT_501_FAN fi fi + tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT @@ -120,7 +121,23 @@ if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP n + 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 + source drivers/char/drm/Config.in +fi + mainmenu_option next_comment comment 'Video For Linux' @@ -139,11 +156,12 @@ hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 fi dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV - dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x24c, 0x248, 0x30c, or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi + dep_tristate 'Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV + dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV dep_tristate 'Trust FM Radio' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_TRUST" = "y" ]; then hex ' Trust FM Radio I/O port (0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350 @@ -160,18 +178,18 @@ dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate 'CPiA Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV + dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate 'CPiA Parallel Port Lowlevel Support (EXPERIMENTAL)' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT - if [ "$CONFIG_VIDEO_CPIA_PP" != "n" ]; then - bool 'CPiA Parallel Port DMA Support (EXPERIMENTAL)' CONFIG_VIDEO_CPIA_PP_DMA - fi + if [ "CONFIG_PARPORT_1284" != "n" ]; then + dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT + fi + if [ "$CONFIG_USB" != "n" ]; then + dep_tristate ' CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB fi fi fi dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV - if [ "$CONFIG_PMAC" = "y" ]; then + if [ "$CONFIG_POWERMAC" = "y" ]; then dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV fi dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/Makefile linux/drivers/char/Makefile --- v2.2.17/drivers/char/Makefile Sat Sep 9 18:42:34 2000 +++ linux/drivers/char/Makefile Thu Dec 7 14:53:44 2000 @@ -11,21 +11,23 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) rio ftape joystick +ALL_SUB_DIRS := $(SUB_DIRS) rio ftape hfmodem joystick agp drm # # This file contains the font map for the default (hardware) font # FONTMAPFILE = cp437.uni -L_TARGET := char.a +O_TARGET := char.o M_OBJS := -L_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o -LX_OBJS := pty.o misc.o +O_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o +OX_OBJS := pty.o misc.o +obj-y := +obj-m := ifdef CONFIG_VT -L_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o -LX_OBJS += console.o selection.o +O_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o +OX_OBJS += console.o selection.o endif ifeq ($(CONFIG_SERIAL),y) @@ -33,7 +35,7 @@ ifeq ($(CONFIG_SGI_SERIAL),) ifeq ($(CONFIG_DECSTATION),) ifeq ($(CONFIG_BAGET_MIPS),) - LX_OBJS += serial.o + OX_OBJS += serial.o endif endif endif @@ -56,28 +58,28 @@ ifndef CONFIG_BAGET_MIPS ifndef CONFIG_SUN_KEYBOARD ifdef CONFIG_VT -LX_OBJS += keyboard.o -endif +OX_OBJS += keyboard.o ifneq ($(ARCH),m68k) ifneq ($(ARCH),s390) - L_OBJS += pc_keyb.o defkeymap.o + O_OBJS += pc_keyb.o defkeymap.o endif endif +endif else ifdef CONFIG_PCI -L_OBJS += defkeymap.o -LX_OBJS += keyboard.o +O_OBJS += defkeymap.o +OX_OBJS += keyboard.o endif endif ifdef CONFIG_MAGIC_SYSRQ -LX_OBJS += sysrq.o +OX_OBJS += sysrq.o endif endif endif ifeq ($(CONFIG_ATARI_DSP56K),y) -L_OBJS += dsp56k.o +O_OBJS += dsp56k.o S = y else ifeq ($(CONFIG_ATARI_DSP56K),m) @@ -87,7 +89,7 @@ endif ifeq ($(CONFIG_ROCKETPORT),y) -L_OBJS += rocket.o +O_OBJS += rocket.o else ifeq ($(CONFIG_ROCKETPORT),m) M_OBJS += rocket.o @@ -95,7 +97,7 @@ endif ifeq ($(CONFIG_MOXA_SMARTIO),y) -L_OBJS += mxser.o +O_OBJS += mxser.o else ifeq ($(CONFIG_MOXA_SMARTIO),m) M_OBJS += mxser.o @@ -103,7 +105,7 @@ endif ifeq ($(CONFIG_MOXA_INTELLIO),y) -L_OBJS += moxa.o +O_OBJS += moxa.o else ifeq ($(CONFIG_MOXA_INTELLIO),m) M_OBJS += moxa.o @@ -111,7 +113,7 @@ endif ifeq ($(CONFIG_DIGI),y) -L_OBJS += pcxx.o +O_OBJS += pcxx.o else ifeq ($(CONFIG_DIGI),m) M_OBJS += pcxx.o @@ -119,7 +121,7 @@ endif ifeq ($(CONFIG_DIGIEPCA),y) -L_OBJS += epca.o +O_OBJS += epca.o else ifeq ($(CONFIG_DIGIEPCA),m) M_OBJS += epca.o @@ -127,7 +129,7 @@ endif ifeq ($(CONFIG_CYCLADES),y) -L_OBJS += cyclades.o +O_OBJS += cyclades.o else ifeq ($(CONFIG_CYCLADES),m) M_OBJS += cyclades.o @@ -135,7 +137,7 @@ endif ifeq ($(CONFIG_STALLION),y) -L_OBJS += stallion.o +O_OBJS += stallion.o else ifeq ($(CONFIG_STALLION),m) M_OBJS += stallion.o @@ -143,7 +145,7 @@ endif ifeq ($(CONFIG_ISTALLION),y) -L_OBJS += istallion.o +O_OBJS += istallion.o else ifeq ($(CONFIG_ISTALLION),m) M_OBJS += istallion.o @@ -151,7 +153,7 @@ endif ifeq ($(CONFIG_COMPUTONE),y) -L_OBJS += ip2.o ip2main.o +O_OBJS += ip2.o ip2main.o else ifeq ($(CONFIG_COMPUTONE),m) M_OBJS += ip2.o ip2main.o @@ -159,7 +161,7 @@ endif ifeq ($(CONFIG_RISCOM8),y) -L_OBJS += riscom8.o +O_OBJS += riscom8.o else ifeq ($(CONFIG_RISCOM8),m) M_OBJS += riscom8.o @@ -167,7 +169,7 @@ endif ifeq ($(CONFIG_ISI),y) -L_OBJS += isicom.o +O_OBJS += isicom.o else ifeq ($(CONFIG_ISI),m) M_OBJS += isicom.o @@ -175,7 +177,7 @@ endif ifeq ($(CONFIG_ESPSERIAL),y) -L_OBJS += esp.o +O_OBJS += esp.o else ifeq ($(CONFIG_ESPSERIAL),m) M_OBJS += esp.o @@ -191,23 +193,17 @@ endif ifeq ($(CONFIG_SPECIALIX),y) -L_OBJS += specialix.o +O_OBJS += specialix.o else ifeq ($(CONFIG_SPECIALIX),m) M_OBJS += specialix.o endif endif -ifeq ($(CONFIG_SX),y) -L_OBJS += sx.o generic_serial.o -else - ifeq ($(CONFIG_SX),m) - M_OBJS += sx.o generic_serial.o - endif -endif +obj-$(CONFIG_SX) += sx.o generic_serial.o ifeq ($(CONFIG_RIO),y) -L_OBJS += rio/rio.o generic_serial.o +O_OBJS += rio/rio.o generic_serial.o SUB_DIRS += rio MOD_SUB_DIRS += rio else @@ -218,7 +214,7 @@ endif ifeq ($(CONFIG_ATIXL_BUSMOUSE),y) -L_OBJS += atixlmouse.o +O_OBJS += atixlmouse.o else ifeq ($(CONFIG_ATIXL_BUSMOUSE),m) M_OBJS += atixlmouse.o @@ -226,7 +222,7 @@ endif ifeq ($(CONFIG_BUSMOUSE),y) -L_OBJS += busmouse.o +O_OBJS += busmouse.o else ifeq ($(CONFIG_BUSMOUSE),m) M_OBJS += busmouse.o @@ -234,7 +230,7 @@ endif ifeq ($(CONFIG_PRINTER),y) -L_OBJS += lp.o +O_OBJS += lp.o else ifeq ($(CONFIG_PRINTER),m) M_OBJS += lp.o @@ -242,7 +238,7 @@ endif ifeq ($(CONFIG_JOYSTICK),y) -L_OBJS += joystick/js.o +O_OBJS += joystick/js.o SUB_DIRS += joystick MOD_SUB_DIRS += joystick else @@ -252,7 +248,7 @@ endif ifeq ($(CONFIG_DTLK),y) -L_OBJS += dtlk.o +O_OBJS += dtlk.o else ifeq ($(CONFIG_DTLK),m) M_OBJS += dtlk.o @@ -260,7 +256,7 @@ endif ifeq ($(CONFIG_MS_BUSMOUSE),y) -L_OBJS += msbusmouse.o +O_OBJS += msbusmouse.o else ifeq ($(CONFIG_MS_BUSMOUSE),m) M_OBJS += msbusmouse.o @@ -268,7 +264,7 @@ endif ifeq ($(CONFIG_82C710_MOUSE),y) -L_OBJS += qpmouse.o +O_OBJS += qpmouse.o else ifeq ($(CONFIG_82C710_MOUSE),m) M_OBJS += qpmouse.o @@ -276,7 +272,7 @@ endif ifeq ($(CONFIG_SOFT_WATCHDOG),y) -L_OBJS += softdog.o +O_OBJS += softdog.o else ifeq ($(CONFIG_SOFT_WATCHDOG),m) M_OBJS += softdog.o @@ -284,7 +280,7 @@ endif ifeq ($(CONFIG_PCWATCHDOG),y) -L_OBJS += pcwd.o +O_OBJS += pcwd.o else ifeq ($(CONFIG_PCWATCHDOG),m) M_OBJS += pcwd.o @@ -292,7 +288,7 @@ endif ifeq ($(CONFIG_ACQUIRE_WDT),y) -L_OBJS += acquirewdt.o +O_OBJS += acquirewdt.o else ifeq ($(CONFIG_ACQUIRE_WDT),m) M_OBJS += acquirewdt.o @@ -300,7 +296,7 @@ endif ifeq ($(CONFIG_60XX_WDT),y) -L_OBJS += sbc60xxwdt.o +O_OBJS += sbc60xxwdt.o else ifeq ($(CONFIG_60XX_WDT),m) M_OBJS += sbc60xxwdt.o @@ -308,7 +304,7 @@ endif ifeq ($(CONFIG_MIXCOMWD),y) -L_OBJS += mixcomwd.o +O_OBJS += mixcomwd.o else ifeq ($(CONFIG_MIXCOMWD),m) M_OBJS += mixcomwd.o @@ -316,7 +312,7 @@ endif ifeq ($(CONFIG_AMIGAMOUSE),y) -L_OBJS += amigamouse.o +O_OBJS += amigamouse.o else ifeq ($(CONFIG_AMIGAMOUSE),m) M_OBJS += amigamouse.o @@ -324,7 +320,7 @@ endif ifeq ($(CONFIG_ATARIMOUSE),y) -L_OBJS += atarimouse.o +O_OBJS += atarimouse.o else ifeq ($(CONFIG_ATARIMOUSE),m) M_OBJS += atarimouse.o @@ -332,7 +328,7 @@ endif ifeq ($(CONFIG_ADBMOUSE),y) -L_OBJS += adbmouse.o +O_OBJS += adbmouse.o else ifeq ($(CONFIG_ADBMOUSE),m) M_OBJS += adbmouse.o @@ -340,7 +336,7 @@ endif ifeq ($(CONFIG_PC110_PAD),y) -L_OBJS += pc110pad.o +O_OBJS += pc110pad.o else ifeq ($(CONFIG_PC110_PAD),m) M_OBJS += pc110pad.o @@ -348,20 +344,28 @@ endif ifeq ($(CONFIG_WDT),y) -L_OBJS += wdt.o +O_OBJS += wdt.o else ifeq ($(CONFIG_WDT),m) M_OBJS += wdt.o endif endif +ifeq ($(CONFIG_WDTPCI),y) +O_OBJS += wdt_pci.o +else + ifeq ($(CONFIG_WDTPCI),m) + M_OBJS += wdt_pci.o + endif +endif + ifeq ($(CONFIG_RTC),y) -L_OBJS += rtc.o +O_OBJS += rtc.o endif ifeq ($(CONFIG_NVRAM),y) ifeq ($(CONFIG_PPC),) - L_OBJS += nvram.o + O_OBJS += nvram.o endif else ifeq ($(CONFIG_NVRAM),m) @@ -371,8 +375,35 @@ endif endif +ifeq ($(CONFIG_AGP),y) +O_OBJS += agp/agp.o +SUB_DIRS += agp +else + ifeq ($(CONFIG_AGP),m) + MOD_SUB_DIRS += agp + endif +endif + +ifeq ($(CONFIG_DRM),y) +O_OBJS += drm/drm.o +MOD_SUB_DIRS += drm +SUB_DIRS += drm +else + ifeq ($(CONFIG_DRM),m) + MOD_SUB_DIRS += drm + endif +endif + +ifeq ($(CONFIG_INTEL_RNG),y) +O_OBJS += i810_rng.o +else + ifeq ($(CONFIG_INTEL_RNG),m) + M_OBJS += i810_rng.o + endif +endif + ifeq ($(CONFIG_VIDEO_DEV),y) -LX_OBJS += videodev.o +OX_OBJS += videodev.o else ifeq ($(CONFIG_VIDEO_DEV),m) MX_OBJS += videodev.o @@ -388,7 +419,7 @@ endif ifeq ($(CONFIG_VIDEO_BT848),y) -L_OBJS += bttv.o tuner.o +O_OBJS += bttv.o tuner.o L_I2C=y else ifeq ($(CONFIG_VIDEO_BT848),m) @@ -398,7 +429,7 @@ endif ifeq ($(CONFIG_VIDEO_MSP3400),y) -L_OBJS += msp3400.o +O_OBJS += msp3400.o L_I2C=y else ifeq ($(CONFIG_VIDEO_MSP3400),m) @@ -408,7 +439,7 @@ endif ifeq ($(CONFIG_VIDEO_SAA5249),y) -L_OBJS += saa5249.o +O_OBJS += saa5249.o L_I2C=y else ifeq ($(CONFIG_VIDEO_SAA5249),m) @@ -418,7 +449,7 @@ endif ifeq ($(CONFIG_VIDEO_BWQCAM),y) -L_OBJS += bw-qcam.o +O_OBJS += bw-qcam.o else ifeq ($(CONFIG_VIDEO_BWQCAM),m) M_OBJS += bw-qcam.o @@ -426,7 +457,7 @@ endif ifeq ($(CONFIG_VIDEO_CQCAM),y) -L_OBJS += c-qcam.o +O_OBJS += c-qcam.o else ifeq ($(CONFIG_VIDEO_CQCAM),m) M_OBJS += c-qcam.o @@ -434,7 +465,7 @@ endif ifeq ($(CONFIG_VIDEO_ZORAN),y) -L_OBJS += buz.o +O_OBJS += buz.o L_I2C=y else ifeq ($(CONFIG_VIDEO_ZORAN),m) @@ -444,7 +475,7 @@ endif ifeq ($(CONFIG_VIDEO_LML33),y) -L_OBJS += bt856.o bt819.o +O_OBJS += bt856.o bt819.o else ifeq ($(CONFIG_VIDEO_LML33),m) M_OBJS += bt856.o bt819.o @@ -452,7 +483,7 @@ endif ifeq ($(CONFIG_VIDEO_BUZ),y) -L_OBJS += saa7111.o saa7185.o +O_OBJS += saa7111.o saa7185.o else ifeq ($(CONFIG_VIDEO_BUZ),m) M_OBJS += saa7111.o saa7185.o @@ -460,7 +491,7 @@ endif ifeq ($(CONFIG_VIDEO_PMS),y) -L_OBJS += pms.o +O_OBJS += pms.o else ifeq ($(CONFIG_VIDEO_PMS),m) M_OBJS += pms.o @@ -468,7 +499,7 @@ endif ifeq ($(CONFIG_VIDEO_PLANB),y) -L_OBJS += planb.o +O_OBJS += planb.o else ifeq ($(CONFIG_VIDEO_PLANB),m) M_OBJS += planb.o @@ -476,7 +507,7 @@ endif ifeq ($(CONFIG_VIDEO_VINO),y) -L_OBJS += vino.o +O_OBJS += vino.o else ifeq ($(CONFIG_VIDEO_VINO),m) M_OBJS += vino.o @@ -484,7 +515,7 @@ endif ifeq ($(CONFIG_VIDEO_CPIA),y) -LX_OBJS += cpia.o +OX_OBJS += cpia.o else ifeq ($(CONFIG_VIDEO_CPIA),m) MX_OBJS += cpia.o @@ -492,15 +523,23 @@ endif ifeq ($(CONFIG_VIDEO_CPIA_PP),y) -L_OBJS += cpia_pp.o +O_OBJS += cpia_pp.o else ifeq ($(CONFIG_VIDEO_CPIA_PP),m) M_OBJS += cpia_pp.o endif endif +ifeq ($(CONFIG_VIDEO_CPIA_USB),y) +O_OBJS += cpia_usb.o +else + ifeq ($(CONFIG_VIDEO_CPIA_USB),m) + M_OBJS += cpia_usb.o + endif +endif + ifeq ($(CONFIG_RADIO_AZTECH),y) -L_OBJS += radio-aztech.o +O_OBJS += radio-aztech.o else ifeq ($(CONFIG_RADIO_AZTECH),m) M_OBJS += radio-aztech.o @@ -508,7 +547,7 @@ endif ifeq ($(CONFIG_RADIO_SF16FMI),y) -L_OBJS += radio-sf16fmi.o +O_OBJS += radio-sf16fmi.o else ifeq ($(CONFIG_RADIO_SF16FMI),m) M_OBJS += radio-sf16fmi.o @@ -516,7 +555,7 @@ endif ifeq ($(CONFIG_RADIO_RTRACK),y) -L_OBJS += radio-aimslab.o +O_OBJS += radio-aimslab.o else ifeq ($(CONFIG_RADIO_RTRACK),m) M_OBJS += radio-aimslab.o @@ -524,7 +563,7 @@ endif ifeq ($(CONFIG_RADIO_RTRACK2),y) -L_OBJS += radio-rtrack2.o +O_OBJS += radio-rtrack2.o else ifeq ($(CONFIG_RADIO_RTRACK2),m) M_OBJS += radio-rtrack2.o @@ -532,7 +571,7 @@ endif ifeq ($(CONFIG_RADIO_TYPHOON),y) -L_OBJS += radio-typhoon.o +O_OBJS += radio-typhoon.o else ifeq ($(CONFIG_RADIO_TYPHOON),m) M_OBJS += radio-typhoon.o @@ -540,7 +579,7 @@ endif ifeq ($(CONFIG_RADIO_ZOLTRIX),y) -L_OBJS += radio-zoltrix.o +O_OBJS += radio-zoltrix.o else ifeq ($(CONFIG_RADIO_ZOLTRIX),m) M_OBJS += radio-zoltrix.o @@ -548,7 +587,7 @@ endif ifeq ($(CONFIG_RADIO_CADET),y) -L_OBJS += radio-cadet.o +O_OBJS += radio-cadet.o else ifeq ($(CONFIG_RADIO_CADET),m) M_OBJS += radio-cadet.o @@ -556,15 +595,23 @@ endif ifeq ($(CONFIG_RADIO_MIROPCM20),y) -L_OBJS += radio-miropcm20.o +O_OBJS += radio-miropcm20.o else ifeq ($(CONFIG_RADIO_MIROPCM20),m) M_OBJS += radio-miropcm20.o endif endif +ifeq ($(CONFIG_RADIO_MAESTRO),y) +O_OBJS += radio-maestro.o +else + ifeq ($(CONFIG_RADIO_MAESTRO),m) + M_OBJS += radio-maestro.o + endif +endif + ifeq ($(CONFIG_RADIO_GEMTEK),y) -L_OBJS += radio-gemtek.o +O_OBJS += radio-gemtek.o else ifeq ($(CONFIG_RADIO_GEMTEK),m) M_OBJS += radio-gemtek.o @@ -572,7 +619,7 @@ endif ifeq ($(CONFIG_RADIO_TRUST),y) -L_OBJS += radio-trust.o +O_OBJS += radio-trust.o else ifeq ($(CONFIG_RADIO_TRUST),m) M_OBJS += radio-trust.o @@ -580,7 +627,7 @@ endif ifeq ($(CONFIG_QIC02_TAPE),y) -L_OBJS += tpqic02.o +O_OBJS += tpqic02.o else ifeq ($(CONFIG_QIC02_TAPE),m) M_OBJS += tpqic02.o @@ -588,7 +635,7 @@ endif ifeq ($(CONFIG_FTAPE),y) -L_OBJS += ftape/ftape.o +O_OBJS += ftape/ftape.o SUB_DIRS += ftape ifneq ($(CONFIG_ZFTAPE),n) MOD_SUB_DIRS += ftape @@ -600,11 +647,11 @@ endif ifdef CONFIG_H8 -LX_OBJS += h8.o +OX_OBJS += h8.o endif ifeq ($(L_I2C),y) -LX_OBJS += i2c.o +OX_OBJS += i2c.o else ifeq ($(M_I2C),y) MX_OBJS += i2c.o @@ -613,29 +660,35 @@ ifeq ($(CONFIG_HFMODEM),y) -ALL_SUB_DIRS += hfmodem SUB_DIRS += hfmodem -L_OBJS += hfmodem/hfmodem.o +O_OBJS += hfmodem/hfmodem.o else ifeq ($(CONFIG_HFMODEM),m) - ALL_SUB_DIRS += hfmodem MOD_SUB_DIRS += hfmodem endif - endif ifeq ($(CONFIG_DZ),y) - L_OBJS += dz.o + O_OBJS += dz.o endif ifeq ($(CONFIG_TOSHIBA),y) -L_OBJS += toshiba.o +O_OBJS += toshiba.o else ifeq ($(CONFIG_TOSHIBA),m) M_OBJS += toshiba.o endif endif + +# remove objects from modular that are also built in +obj-m := $(filter-out $(obj-y), $(obj-m)) + +# Translate to Rules.make lists. + +O_OBJS += $(filter-out $(export-objs), $(obj-y)) +OX_OBJS += $(filter $(export-objs), $(obj-y)) +M_OBJS += $(sort $(filter $(module-list), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/README.computone linux/drivers/char/README.computone --- v2.2.17/drivers/char/README.computone Sun Jun 11 21:44:12 2000 +++ linux/drivers/char/README.computone Sat Nov 18 18:01:23 2000 @@ -92,7 +92,7 @@ to update the character drivers' makefile and configuration file, and other kernel source files. A build script (ip2build) was included which applies the patches if needed, and build any utilities needed. -What you recieve may be a single patch file in conventional kernel +What you receive may be a single patch file in conventional kernel patch format build script. That form can also be applied by running patch -p1 < ThePatchFile. Otherwise the drivers source may be a tar file, then untar and run ip2build if a new installation. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/agp/Makefile linux/drivers/char/agp/Makefile --- v2.2.17/drivers/char/agp/Makefile Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/agp/Makefile Fri Sep 1 14:06:07 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h --- v2.2.17/drivers/char/agp/agp.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/agp/agp.h Tue Nov 28 17:15:12 2000 @@ -0,0 +1,287 @@ +/* + * 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, + LVL2_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_lvl2 { + int size; + int num_entries; + u32 size_value; +} aper_size_info_lvl2; + +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 *); +}; + +#define OUTREG32(mmap, addr, val) writel((val),(mmap + (addr))) +#define OUTREG16(mmap, addr, val) writew((val),(mmap + (addr))) +#define OUTREG8 (mmap, addr, val) writeb((val),(mmap + (addr))) + +#define INREG32(mmap, addr) readl(mmap + (addr)) +#define INREG16(mmap, addr) readw(mmap + (addr)) +#define INREG8 (mmap, addr) 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_LVL2(x) ((aper_size_info_lvl2 *) 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_IDXLVL2() (A_SIZE_LVL2(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 arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define AGPGART_MODULE_NAME "agpgart" +#define PFX AGPGART_MODULE_NAME ": " + +#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_840_0 +#define PCI_DEVICE_ID_INTEL_840_0 0x1a21 +#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_815_0 +#define PCI_DEVICE_ID_INTEL_815_0 0x1130 +#endif +#ifndef PCI_DEVICE_ID_INTEL_815_1 +#define PCI_DEVICE_ID_INTEL_815_1 0x1132 +#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 +#ifndef PCI_DEVICE_ID_SI_630 +#define PCI_DEVICE_ID_SI_630 0x0630 +#endif +#ifndef PCI_DEVICE_ID_SI_540 +#define PCI_DEVICE_ID_SI_540 0x0540 +#endif +#ifndef PCI_DEVICE_ID_SI_620 +#define PCI_DEVICE_ID_SI_620 0x0620 +#endif +#ifndef PCI_DEVICE_ID_SI_530 +#define PCI_DEVICE_ID_SI_530 0x0530 +#endif +#ifndef PCI_DEVICE_ID_VIA_8501_0 +#define PCI_DEVICE_ID_VIA_8501_0 0x0501 +#endif +#ifndef PCI_DEVICE_ID_VIA_8371_0 +#define PCI_DEVICE_ID_VIA_8371_0 0x0391 +#endif +#ifndef PCI_DEVICE_ID_VIA_8363_0 +#define PCI_DEVICE_ID_VIA_8363_0 0x0305 +#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 i840 registers */ +#define INTEL_I840_MCHCFG 0x50 +#define INTEL_I840_ERRSTS 0xc8 + +/* 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_MODECNTL2 0xb2 +#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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/agp/agp_backend.h linux/drivers/char/agp/agp_backend.h --- v2.2.17/drivers/char/agp/agp_backend.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/agp/agp_backend.h Fri Sep 1 14:14:15 2000 @@ -0,0 +1,231 @@ +/* + * 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_H +#define _AGP_BACKEND_H 1 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define AGPGART_VERSION_MAJOR 0 +#define AGPGART_VERSION_MINOR 99 + +enum chipset_type { + NOT_SUPPORTED, + INTEL_GENERIC, + INTEL_LX, + INTEL_BX, + INTEL_GX, + INTEL_I810, + INTEL_I840, + VIA_GENERIC, + VIA_VP3, + VIA_MVP3, + VIA_MVP4, + VIA_APOLLO_SUPER, + VIA_APOLLO_PRO, + SIS_GENERIC, + AMD_GENERIC, + AMD_IRONGATE, + ALI_M1541, + ALI_GENERIC +}; + +typedef struct _agp_version { + u16 major; + u16 minor; +} agp_version; + +typedef struct _agp_kern_info { + agp_version version; + struct pci_dev *device; + enum chipset_type chipset; + unsigned long mode; + off_t aper_base; + size_t aper_size; + int max_memory; /* In pages */ + int current_memory; +} agp_kern_info; + +/* + * The agp_memory structure has information + * about the block of agp memory allocated. + * A caller may manipulate the next and prev + * pointers to link each allocated item into + * a list. These pointers are ignored by the + * backend. Everything else should never be + * written to, but the caller may read any of + * the items to detrimine the status of this + * block of agp memory. + * + */ + +typedef struct _agp_memory { + int key; + struct _agp_memory *next; + struct _agp_memory *prev; + size_t page_count; + int num_scratch_pages; + unsigned long *memory; + off_t pg_start; + u32 type; + u32 physical; + u8 is_bound; + u8 is_flushed; +} agp_memory; + +#define AGP_NORMAL_MEMORY 0 + +extern void agp_free_memory(agp_memory *); + +/* + * agp_free_memory : + * + * This function frees memory associated with + * an agp_memory pointer. It is the only function + * that can be called when the backend is not owned + * by the caller. (So it can free memory on client + * death.) + * + * It takes an agp_memory pointer as an argument. + * + */ + +extern agp_memory *agp_allocate_memory(size_t, u32); + +/* + * agp_allocate_memory : + * + * This function allocates a group of pages of + * a certain type. + * + * It takes a size_t argument of the number of pages, and + * an u32 argument of the type of memory to be allocated. + * Every agp bridge device will allow you to allocate + * AGP_NORMAL_MEMORY which maps to physical ram. Any other + * type is device dependant. + * + * It returns NULL whenever memory is unavailable. + * + */ + +extern void agp_copy_info(agp_kern_info *); + +/* + * agp_copy_info : + * + * This function copies information about the + * agp bridge device and the state of the agp + * backend into an agp_kern_info pointer. + * + * It takes an agp_kern_info pointer as an + * argument. The caller should insure that + * this pointer is valid. + * + */ + +extern int agp_bind_memory(agp_memory *, off_t); + +/* + * agp_bind_memory : + * + * This function binds an agp_memory structure + * into the graphics aperture translation table. + * + * It takes an agp_memory pointer and an offset into + * the graphics aperture translation table as arguments + * + * It returns -EINVAL if the pointer == NULL. + * It returns -EBUSY if the area of the table + * requested is already in use. + * + */ + +extern int agp_unbind_memory(agp_memory *); + +/* + * agp_unbind_memory : + * + * This function removes an agp_memory structure + * from the graphics aperture translation table. + * + * It takes an agp_memory pointer as an argument. + * + * It returns -EINVAL if this piece of agp_memory + * is not currently bound to the graphics aperture + * translation table or if the agp_memory + * pointer == NULL + * + */ + +extern void agp_enable(u32); + +/* + * agp_enable : + * + * This function initializes the agp point-to-point + * connection. + * + * It takes an agp mode register as an argument + * + */ + +extern int agp_backend_acquire(void); + +/* + * agp_backend_acquire : + * + * This Function attempts to acquire the agp + * backend. + * + * returns -EBUSY if agp is in use, + * returns 0 if the caller owns the agp backend + */ + +extern void agp_backend_release(void); + +/* + * agp_backend_release : + * + * This Function releases the lock on the agp + * backend. + * + * The caller must insure that the graphics + * aperture translation table is read for use + * by another entity. (Ensure that all memory + * it bound is unbound.) + * + */ + +/* Don't call this directly!! used in initialization */ +extern int agp_init(void); + +#endif /* _AGP_BACKEND_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/agp/agpgart.h linux/drivers/char/agp/agpgart.h --- v2.2.17/drivers/char/agp/agpgart.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/agp/agpgart.h Sun Sep 3 00:12:57 2000 @@ -0,0 +1,224 @@ +/* + * 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_H +#define _AGP_H 1 + +#define AGPIOC_BASE 'A' +#define AGPIOC_INFO _IOR (AGPIOC_BASE, 0, agp_info*) +#define AGPIOC_ACQUIRE _IO (AGPIOC_BASE, 1) +#define AGPIOC_RELEASE _IO (AGPIOC_BASE, 2) +#define AGPIOC_SETUP _IOW (AGPIOC_BASE, 3, agp_setup*) +#define AGPIOC_RESERVE _IOW (AGPIOC_BASE, 4, agp_region*) +#define AGPIOC_PROTECT _IOW (AGPIOC_BASE, 5, agp_region*) +#define AGPIOC_ALLOCATE _IOWR(AGPIOC_BASE, 6, agp_allocate*) +#define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int) +#define AGPIOC_BIND _IOW (AGPIOC_BASE, 8, agp_bind*) +#define AGPIOC_UNBIND _IOW (AGPIOC_BASE, 9, agp_unbind*) + +#define AGP_DEVICE "/dev/agpgart" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef __KERNEL__ +#include +#include + +typedef struct _agp_version { + __u16 major; + __u16 minor; +} agp_version; + +typedef struct _agp_info { + agp_version version; /* version of the driver */ + __u32 bridge_id; /* bridge vendor/device */ + __u32 agp_mode; /* mode info of bridge */ + off_t aper_base; /* base of aperture */ + size_t aper_size; /* size of aperture */ + size_t pg_total; /* max pages (swap + system) */ + size_t pg_system; /* max pages (system) */ + size_t pg_used; /* current pages used */ +} agp_info; + +typedef struct _agp_setup { + __u32 agp_mode; /* mode info of bridge */ +} agp_setup; + +/* + * The "prot" down below needs still a "sleep" flag somehow ... + */ +typedef struct _agp_segment { + off_t pg_start; /* starting page to populate */ + size_t pg_count; /* number of pages */ + int prot; /* prot flags for mmap */ +} agp_segment; + +typedef struct _agp_region { + pid_t pid; /* pid of process */ + size_t seg_count; /* number of segments */ + struct _agp_segment *seg_list; +} agp_region; + +typedef struct _agp_allocate { + int key; /* tag of allocation */ + size_t pg_count; /* number of pages */ + __u32 type; /* 0 == normal, other devspec */ + __u32 physical; /* device specific (some devices + * need a phys address of the + * actual page behind the gatt + * table) */ +} agp_allocate; + +typedef struct _agp_bind { + int key; /* tag of allocation */ + off_t pg_start; /* starting page to populate */ +} agp_bind; + +typedef struct _agp_unbind { + int key; /* tag of allocation */ + __u32 priority; /* priority for paging out */ +} agp_unbind; + +#else /* __KERNEL__ */ + +#define AGPGART_MINOR 175 + +#define AGP_UNLOCK() up(&(agp_fe.agp_mutex)); +#define AGP_LOCK() down(&(agp_fe.agp_mutex)); +#define AGP_LOCK_INIT() sema_init(&(agp_fe.agp_mutex), 1) + +#ifndef _AGP_BACKEND_H +typedef struct _agp_version { + u16 major; + u16 minor; +} agp_version; + +#endif + +typedef struct _agp_info { + agp_version version; /* version of the driver */ + u32 bridge_id; /* bridge vendor/device */ + u32 agp_mode; /* mode info of bridge */ + off_t aper_base; /* base of aperture */ + size_t aper_size; /* size of aperture */ + size_t pg_total; /* max pages (swap + system) */ + size_t pg_system; /* max pages (system) */ + size_t pg_used; /* current pages used */ +} agp_info; + +typedef struct _agp_setup { + u32 agp_mode; /* mode info of bridge */ +} agp_setup; + +/* + * The "prot" down below needs still a "sleep" flag somehow ... + */ +typedef struct _agp_segment { + off_t pg_start; /* starting page to populate */ + size_t pg_count; /* number of pages */ + int prot; /* prot flags for mmap */ +} agp_segment; + +typedef struct _agp_segment_priv { + off_t pg_start; + size_t pg_count; + pgprot_t prot; +} agp_segment_priv; + +typedef struct _agp_region { + pid_t pid; /* pid of process */ + size_t seg_count; /* number of segments */ + struct _agp_segment *seg_list; +} agp_region; + +typedef struct _agp_allocate { + int key; /* tag of allocation */ + size_t pg_count; /* number of pages */ + u32 type; /* 0 == normal, other devspec */ + u32 physical; /* device specific (some devices + * need a phys address of the + * actual page behind the gatt + * table) */ +} agp_allocate; + +typedef struct _agp_bind { + int key; /* tag of allocation */ + off_t pg_start; /* starting page to populate */ +} agp_bind; + +typedef struct _agp_unbind { + int key; /* tag of allocation */ + u32 priority; /* priority for paging out */ +} agp_unbind; + +typedef struct _agp_client { + struct _agp_client *next; + struct _agp_client *prev; + pid_t pid; + int num_segments; + agp_segment_priv **segments; +} agp_client; + +typedef struct _agp_controller { + struct _agp_controller *next; + struct _agp_controller *prev; + pid_t pid; + int num_clients; + agp_memory *pool; + agp_client *clients; +} agp_controller; + +#define AGP_FF_ALLOW_CLIENT 0 +#define AGP_FF_ALLOW_CONTROLLER 1 +#define AGP_FF_IS_CLIENT 2 +#define AGP_FF_IS_CONTROLLER 3 +#define AGP_FF_IS_VALID 4 + +typedef struct _agp_file_private { + struct _agp_file_private *next; + struct _agp_file_private *prev; + pid_t my_pid; + u32 access_flags; +} agp_file_private; + +struct agp_front_data { + struct semaphore agp_mutex; + agp_controller *current_controller; + agp_controller *controllers; + agp_file_private *file_priv_list; + u8 used_by_controller; + u8 backend_acquired; +}; + +#endif /* __KERNEL__ */ + +#endif /* _AGP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.2.17/drivers/char/agp/agpgart_be.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/agp/agpgart_be.c Tue Sep 26 17:00:25 2000 @@ -0,0 +1,2493 @@ +/* + * 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 CONFIG_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(PFX "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 /* CONFIG_SMP */ +#define global_cache_flush flush_cache +#endif /* CONFIG_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); +#if 0 + wake_up(&mem_map[MAP_NR(pt)].wait); +#endif + 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); + 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; + } + /* We always increase the module count, since free auto-decrements + * it + */ + + MOD_INC_USE_COUNT; + + scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; + + new = agp_create_memory(scratch_pages); + + if (new == NULL) { + MOD_DEC_USE_COUNT; + 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++; + } + + 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 LVL2_APER_SIZE: + current_size = A_SIZE_LVL2(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; + } + 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; + + /* The generic routines can't handle 2 level gatt's */ + if (agp_bridge.size_type == LVL2_APER_SIZE) { + return -EINVAL; + } + + 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: + case LVL2_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: + case LVL2_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 = (unsigned long *) table; + agp_bridge.gatt_table_real = (unsigned long *) table; + 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; + case LVL2_APER_SIZE: + /* The generic routines can't deal with 2 level gatt's */ + return -EINVAL; + 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. + */ + + 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; + case LVL2_APER_SIZE: + /* The generic routines can't deal with 2 level gatt's */ + return -EINVAL; + 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++; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + agp_bridge.gatt_table[j] = mem->memory[i]; + } + /* Do cache flush all the time since the table is not + * mapped uncached */ + CACHE_FLUSH(); + 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 +#define AGP_PHYS_MEMORY 2 + +static gatt_mask intel_i810_masks[] = +{ + {I810_PTE_VALID, 0}, + {(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY}, + {I810_PTE_VALID, 0} +}; + +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(KERN_WARNING PFX "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 PFX "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 */ + CACHE_FLUSH(); + 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); + } + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + return 0; + } + if((type == AGP_PHYS_MEMORY) && + (mem->type == AGP_PHYS_MEMORY)) { + goto insert; + } + return -EINVAL; + } + +insert: + CACHE_FLUSH(); + 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]); + } + CACHE_FLUSH(); + + agp_bridge.tlb_flush(mem); + return 0; +} + +static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + + CACHE_FLUSH(); + 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); + } + CACHE_FLUSH(); + + 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); + MOD_INC_USE_COUNT; + return new; + } + if(type == AGP_PHYS_MEMORY) { + /* The I810 requires a physical address to program + * it's mouse pointer into hardware. However the + * Xserver still writes to it through the agp + * aperture + */ + if (pg_count != 1) { + return NULL; + } + new = agp_create_memory(1); + + if (new == NULL) { + return NULL; + } + MOD_INC_USE_COUNT; + new->memory[0] = agp_alloc_page(); + + if (new->memory[0] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[0] = + agp_bridge.mask_memory( + virt_to_phys((void *) new->memory[0]), + type); + new->page_count = 1; + new->num_scratch_pages = 1; + new->type = AGP_PHYS_MEMORY; + new->physical = virt_to_phys((void *) new->memory[0]); + return new; + } + + return NULL; +} + +static void intel_i810_free_by_type(agp_memory * curr) +{ + agp_free_key(curr->key); + if(curr->type == AGP_PHYS_MEMORY) { + agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[0])); + vfree(curr->memory); + } + kfree(curr); + MOD_DEC_USE_COUNT; +} + +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 int __init 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; + + return 0; +} + +#endif /* CONFIG_AGP_I810 */ + +#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 int intel_840_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_byte(agp_bridge.dev, INTEL_APSIZE, + (char)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, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000); + 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 int __init intel_generic_setup (struct pci_dev *pdev) +{ + 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; + + return 0; + + (void) pdev; /* unused */ +} + +static int __init intel_840_setup (struct pci_dev *pdev) +{ + 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_840_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; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_INTEL */ + +#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 int __init via_generic_setup (struct pci_dev *pdev) +{ + 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; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_VIA */ + +#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 int __init sis_generic_setup (struct pci_dev *pdev) +{ + 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; + + return 0; +} + +#endif /* CONFIG_AGP_SIS */ + +#ifdef CONFIG_AGP_AMD + +typedef struct _amd_page_map { + unsigned long *real; + unsigned long *remapped; +} amd_page_map; + +static struct _amd_irongate_private { + volatile u8 *registers; + amd_page_map **gatt_pages; + int num_tables; +} amd_irongate_private; + +static int amd_create_page_map(amd_page_map *page_map) +{ + int i; + + page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + if (page_map->real == NULL) { + return -ENOMEM; + } + set_bit(PG_reserved, &mem_map[MAP_NR(page_map->real)].flags); + page_map->remapped = page_map->real; + + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { + page_map->remapped[i] = agp_bridge.scratch_page; + } + CACHE_FLUSH(); + + return 0; +} + +static void amd_free_page_map(amd_page_map *page_map) +{ + clear_bit(PG_reserved, + &mem_map[MAP_NR(page_map->real)].flags); + free_page((unsigned long) page_map->real); +} + +static void amd_free_gatt_pages(void) +{ + int i; + amd_page_map **tables; + amd_page_map *entry; + + tables = amd_irongate_private.gatt_pages; + for(i = 0; i < amd_irongate_private.num_tables; i++) { + entry = tables[i]; + if (entry != NULL) { + if (entry->real != NULL) { + amd_free_page_map(entry); + } + kfree(entry); + } + } + kfree(tables); +} + +static int amd_create_gatt_pages(int nr_tables) +{ + amd_page_map **tables; + amd_page_map *entry; + int retval = 0; + int i; + + tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *), + GFP_KERNEL); + if (tables == NULL) { + return -ENOMEM; + } + memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { + entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL); + if (entry == NULL) { + retval = -ENOMEM; + break; + } + memset(entry, 0, sizeof(amd_page_map)); + tables[i] = entry; + retval = amd_create_page_map(entry); + if (retval != 0) break; + } + amd_irongate_private.num_tables = nr_tables; + amd_irongate_private.gatt_pages = tables; + + if (retval != 0) amd_free_gatt_pages(); + + return retval; +} + +/* Since we don't need contigious memory we just try + * to get the gatt table once + */ + +#define GET_PAGE_DIR_OFF(addr) (addr >> 22) +#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ + GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) +#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) +#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\ + GET_PAGE_DIR_IDX(addr)]->remapped) + +static int amd_create_gatt_table(void) +{ + aper_size_info_lvl2 *value; + amd_page_map page_dir; + unsigned long addr; + int retval; + u32 temp; + int i; + + value = A_SIZE_LVL2(agp_bridge.current_size); + retval = amd_create_page_map(&page_dir); + if (retval != 0) { + return retval; + } + + retval = amd_create_gatt_pages(value->num_entries / 1024); + if (retval != 0) { + amd_free_page_map(&page_dir); + return retval; + } + + agp_bridge.gatt_table_real = page_dir.real; + agp_bridge.gatt_table = page_dir.remapped; + agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real); + + /* Get the address for the gart region. + * This is a bus address even on the alpha, b/c its + * used to program the agp master not the cpu + */ + + pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); + addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + agp_bridge.gart_bus_addr = addr; + + /* Calculate the agp offset */ + for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = + virt_to_bus(amd_irongate_private.gatt_pages[i]->real); + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + } + + return 0; +} + +static int amd_free_gatt_table(void) +{ + amd_page_map page_dir; + + page_dir.real = agp_bridge.gatt_table_real; + page_dir.remapped = agp_bridge.gatt_table; + + amd_free_gatt_pages(); + amd_free_page_map(&page_dir); + return 0; +} + +static int amd_irongate_fetch_size(void) +{ + int i; + u32 temp; + aper_size_info_lvl2 *values; + + pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); + temp = (temp & 0x0000000e); + values = A_SIZE_LVL2(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_lvl2 *current_size; + u32 temp; + u16 enable_reg; + + current_size = A_SIZE_LVL2(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); + + /* Set indexing mode */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00); + + /* 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); + + return 0; +} + +static void amd_irongate_cleanup(void) +{ + aper_size_info_lvl2 *previous_size; + u32 temp; + u16 enable_reg; + + previous_size = A_SIZE_LVL2(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 int amd_insert_memory(agp_memory * mem, + off_t pg_start, int type) +{ + int i, j, num_entries; + unsigned long *cur_gatt; + unsigned long addr; + + num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + mem->page_count)) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + return -EBUSY; + } + j++; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + } + + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + return 0; +} + +static int amd_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned long *cur_gatt; + unsigned long addr; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = + (unsigned long) agp_bridge.scratch_page; + } + + CACHE_FLUSH(); + agp_bridge.tlb_flush(mem); + return 0; +} + +static aper_size_info_lvl2 amd_irongate_sizes[7] = +{ + {2048, 524288, 0x0000000c}, + {1024, 262144, 0x0000000a}, + {512, 131072, 0x00000008}, + {256, 65536, 0x00000006}, + {128, 32768, 0x00000004}, + {64, 16384, 0x00000002}, + {32, 8192, 0x00000000} +}; + +static gatt_mask amd_irongate_masks[] = +{ + {0x00000001, 0} +}; + +static int __init amd_irongate_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = amd_irongate_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; + agp_bridge.size_type = LVL2_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 = amd_create_gatt_table; + agp_bridge.free_gatt_table = amd_free_gatt_table; + agp_bridge.insert_memory = amd_insert_memory; + agp_bridge.remove_memory = amd_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_AMD */ + +#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 int __init ali_generic_setup (struct pci_dev *pdev) +{ + 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; + + return 0; + + (void) pdev; /* unused */ +} + +#endif /* CONFIG_AGP_ALI */ + + +/* per-chipset initialization data. + * note -- all chipsets for a single vendor MUST be grouped together + */ +static struct { + unsigned short device_id; /* first, to make table easier to read */ + unsigned short vendor_id; + enum chipset_type chipset; + const char *vendor_name; + const char *chipset_name; + int (*chipset_setup) (struct pci_dev *pdev); +} agp_bridge_info[] __initdata = { + +#ifdef CONFIG_AGP_ALI + { PCI_DEVICE_ID_AL_M1541_0, + PCI_VENDOR_ID_AL, + ALI_M1541, + "Ali", + "M1541", + ali_generic_setup }, + { 0, + PCI_VENDOR_ID_AL, + ALI_GENERIC, + "Ali", + "Generic", + ali_generic_setup }, +#endif /* CONFIG_AGP_ALI */ + +#ifdef CONFIG_AGP_AMD + { PCI_DEVICE_ID_AMD_IRONGATE_0, + PCI_VENDOR_ID_AMD, + AMD_IRONGATE, + "AMD", + "Irongate", + amd_irongate_setup }, + { 0, + PCI_VENDOR_ID_AMD, + AMD_GENERIC, + "AMD", + "Generic", + amd_irongate_setup }, +#endif /* CONFIG_AGP_AMD */ + +#ifdef CONFIG_AGP_INTEL + { PCI_DEVICE_ID_INTEL_82443LX_0, + PCI_VENDOR_ID_INTEL, + INTEL_LX, + "Intel", + "440LX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443BX_0, + PCI_VENDOR_ID_INTEL, + INTEL_BX, + "Intel", + "440BX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443GX_0, + PCI_VENDOR_ID_INTEL, + INTEL_GX, + "Intel", + "440GX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_840_0, + PCI_VENDOR_ID_INTEL, + INTEL_I840, + "Intel", + "i840", + intel_840_setup }, + { 0, + PCI_VENDOR_ID_INTEL, + INTEL_GENERIC, + "Intel", + "Generic", + intel_generic_setup }, +#endif /* CONFIG_AGP_INTEL */ + +#ifdef CONFIG_AGP_SIS + { PCI_DEVICE_ID_SI_630, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "630", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_540, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "540", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_620, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "620", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_530, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "530", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_630, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "Generic", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_540, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "Generic", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_620, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "Generic", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_530, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "Generic", + sis_generic_setup }, + { 0, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "Generic", + sis_generic_setup }, +#endif /* CONFIG_AGP_SIS */ + +#ifdef CONFIG_AGP_VIA + { PCI_DEVICE_ID_VIA_8501_0, + PCI_VENDOR_ID_VIA, + VIA_MVP4, + "Via", + "MVP4", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C597_0, + PCI_VENDOR_ID_VIA, + VIA_VP3, + "Via", + "VP3", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C598_0, + PCI_VENDOR_ID_VIA, + VIA_MVP3, + "Via", + "MVP3", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_8371_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_KX133, + "Via", + "Apollo KX133", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_8363_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_KT133, + "Via", + "Apollo KT133", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C691_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_PRO, + "Via", + "Apollo Pro", + via_generic_setup }, + { 0, + PCI_VENDOR_ID_VIA, + VIA_GENERIC, + "Via", + "Generic", + via_generic_setup }, +#endif /* CONFIG_AGP_VIA */ + + { 0, }, /* dummy final entry, always present */ +}; + + +/* scan table above for supported devices */ +static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +{ + int i; + + for (i = 0; i < arraysize (agp_bridge_info); i++) + if (pdev->vendor == agp_bridge_info[i].vendor_id) + break; + + if (i >= arraysize (agp_bridge_info)) { + printk (KERN_DEBUG PFX "unsupported bridge\n"); + return -ENODEV; + } + + while ((i < arraysize (agp_bridge_info)) && + (agp_bridge_info[i].vendor_id == pdev->vendor)) { + if (pdev->device == agp_bridge_info[i].device_id) { + printk (KERN_INFO PFX "Detected %s %s chipset\n", + agp_bridge_info[i].vendor_name, + agp_bridge_info[i].chipset_name); + agp_bridge.type = agp_bridge_info[i].chipset; + return agp_bridge_info[i].chipset_setup (pdev); + } + + i++; + } + + i--; /* point to vendor generic entry (device_id == 0) */ + + /* try init anyway, if user requests it AND + * there is a 'generic' bridge entry for this vendor */ + if (agp_try_unsupported && agp_bridge_info[i].device_id == 0) { + printk(KERN_WARNING PFX "Trying generic %s routines" + " for device id: %x\n", + agp_bridge_info[i].vendor_name, pdev->device); + agp_bridge.type = agp_bridge_info[i].chipset; + return agp_bridge_info[i].chipset_setup (pdev); + } + + printk(KERN_ERR PFX "Unsupported %s chipset," + " you might want to try " + "agp_try_unsupported=1.\n", + agp_bridge_info[i].vendor_name); + return -ENODEV; +} + + +/* Supported Device Scanning routine */ + +static int __init 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) + return -ENODEV; + + 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(KERN_ERR PFX "Detected an Intel i810," + " but could not find the secondary" + " device.\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected an Intel " + "i810 Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup (i810_dev); + + 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(KERN_ERR PFX "Detected an Intel i810 " + "DC100, but could not find the " + "secondary device.\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected an Intel i810 " + "DC100 Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup(i810_dev); + + 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(KERN_ERR PFX "Detected an Intel i810 E" + ", but could not find the secondary " + "device.\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected an Intel i810 E " + "Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup(i810_dev); + case PCI_DEVICE_ID_INTEL_815_0: + /* The i815 can operate either as an i810 style + * integrated device, or as an AGP4X motherboard. + * + * This only addresses the first mode: + */ + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_815_1, + NULL); + if (i810_dev == NULL) { + printk(KERN_ERR PFX "agpgart: Detected an " + "Intel i815, but could not find the" + " secondary device.\n"); + agp_bridge.type = NOT_SUPPORTED; + return -ENODEV; + } + printk(KERN_INFO PFX "agpgart: Detected an Intel i815 " + "Chipset.\n"); + agp_bridge.type = INTEL_I810; + return intel_i810_setup(i810_dev); + + default: + break; + } + } +#endif /* CONFIG_AGP_I810 */ + + /* find capndx */ + pci_read_config_dword(dev, 0x04, &scratch); + if (!(scratch & 0x00100000)) + return -ENODEV; + + 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) + return -ENODEV; + agp_bridge.capndx = cap_ptr; + + /* Fill in the mode register */ + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + 4, + &agp_bridge.mode); + + /* probe for known chipsets */ + return agp_lookup_host_bridge (dev); +} + +struct agp_max_table { + int mem; + int agp; +}; + +static struct agp_max_table maxes_table[9] __initdata = +{ + {0, 0}, + {32, 4}, + {64, 28}, + {128, 96}, + {256, 204}, + {512, 440}, + {1024, 942}, + {2048, 1920}, + {4096, 3932} +}; + +static int __init agp_find_max (void) +{ + long memory, index, result; + + memory = virt_to_phys(high_memory) >> 20; + index = 1; + + while ((memory > maxes_table[index].mem) && + (index < 8)) { + index++; + } + + result = maxes_table[index - 1].agp + + ( (memory - maxes_table[index - 1].mem) * + (maxes_table[index].agp - maxes_table[index - 1].agp)) / + (maxes_table[index].mem - maxes_table[index - 1].mem); + + printk(KERN_INFO PFX "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 __init agp_backend_initialize(void) +{ + int size_value, rc, got_gatt=0, got_keylist=0; + + memset(&agp_bridge, 0, sizeof(struct agp_bridge_data)); + agp_bridge.type = NOT_SUPPORTED; + agp_bridge.max_memory_agp = agp_find_max(); + agp_bridge.version = &agp_current_version; + + rc = agp_find_supported_device(); + if (rc) { + /* not KERN_ERR because error msg should have already printed */ + printk(KERN_DEBUG PFX "no supported devices found.\n"); + return rc; + } + + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page = agp_alloc_page(); + + if (agp_bridge.scratch_page == 0) { + printk(KERN_ERR PFX "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); + } + + size_value = agp_bridge.fetch_size(); + + if (size_value == 0) { + printk(KERN_ERR PFX "unable to detrimine aperture size.\n"); + rc = -EINVAL; + goto err_out; + } + if (agp_bridge.create_gatt_table()) { + printk(KERN_ERR PFX "unable to get memory for graphics " + "translation table.\n"); + rc = -ENOMEM; + goto err_out; + } + got_gatt = 1; + + agp_bridge.key_list = vmalloc(PAGE_SIZE * 4); + if (agp_bridge.key_list == NULL) { + printk(KERN_ERR PFX "error allocating memory for key lists.\n"); + rc = -ENOMEM; + goto err_out; + } + got_keylist = 1; + + /* FIXME vmalloc'd memory not guaranteed contiguous */ + memset(agp_bridge.key_list, 0, PAGE_SIZE * 4); + + if (agp_bridge.configure()) { + printk(KERN_ERR PFX "error configuring host chipset.\n"); + rc = -EINVAL; + goto err_out; + } + + printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n", + size_value, agp_bridge.gart_bus_addr); + + return 0; + +err_out: + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page &= ~(0x00000fff); + agp_destroy_page((unsigned long) + phys_to_virt(agp_bridge.scratch_page)); + } + if (got_gatt) + agp_bridge.free_gatt_table(); + if (got_keylist) + vfree(agp_bridge.key_list); + return rc; +} + + +/* cannot be __exit b/c as it could be called from __init code */ +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); + +__initfunc(int 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) + return ret_val; + + ret_val = agp_frontend_initialize(); + if (ret_val) { + agp_backend_cleanup(); + return ret_val; + } + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return agp_init(); +} + +void cleanup_module(void) +{ + agp_frontend_cleanup(); + agp_backend_cleanup(); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c --- v2.2.17/drivers/char/agp/agpgart_fe.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/agp/agpgart_fe.c Tue Sep 26 17:00:25 2000 @@ -0,0 +1,1098 @@ +/* + * 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 "agpgart.h" +#include +#include +#include +#include +#include + +#include "agp.h" + +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); + printk(KERN_DEBUG "memory : %p\n", memory); + 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_offset; + + 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; + int rc = -ENXIO; + + AGP_LOCK(); + MOD_INC_USE_COUNT; + + if (minor != AGPGART_MINOR) + goto err_out; + + priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL); + if (priv == NULL) + goto err_out_nomem; + + 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); + AGP_UNLOCK(); + return 0; + +err_out_nomem: + rc = -ENOMEM; +err_out: + MOD_DEC_USE_COUNT; + AGP_UNLOCK(); + return rc; +} + + +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; + alloc.physical = memory->physical; + + 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 = -ENOTTY; + + AGP_LOCK(); + + if ((agp_fe.current_controller == NULL) && + (cmd != AGPIOC_ACQUIRE)) { + ret_val = -EINVAL; + goto ioctl_out; + } + if ((agp_fe.backend_acquired != TRUE) && + (cmd != AGPIOC_ACQUIRE)) { + ret_val = -EBUSY; + goto ioctl_out; + } + if (cmd != AGPIOC_ACQUIRE) { + if (!(test_bit(AGP_FF_IS_CONTROLLER, + &curr_priv->access_flags))) { + ret_val = -EPERM; + goto ioctl_out; + } + /* Use the original pid of the controller, + * in case it's threaded */ + + if (agp_fe.current_controller->pid != curr_priv->my_pid) { + ret_val = -EBUSY; + goto ioctl_out; + } + } + switch (cmd) { + case AGPIOC_INFO: + { + ret_val = agpioc_info_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_ACQUIRE: + { + ret_val = agpioc_acquire_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_RELEASE: + { + ret_val = agpioc_release_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_SETUP: + { + ret_val = agpioc_setup_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_RESERVE: + { + ret_val = agpioc_reserve_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_PROTECT: + { + ret_val = agpioc_protect_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_ALLOCATE: + { + ret_val = agpioc_allocate_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_DEALLOCATE: + { + ret_val = agpioc_deallocate_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_BIND: + { + ret_val = agpioc_bind_wrap(curr_priv, arg); + goto ioctl_out; + } + case AGPIOC_UNBIND: + { + ret_val = agpioc_unbind_wrap(curr_priv, arg); + goto ioctl_out; + } + } + +ioctl_out: + AGP_UNLOCK(); + return ret_val; +} + +static struct file_operations agp_fops = +{ + llseek: agp_lseek, + read: agp_read, + write: agp_write, + ioctl: agp_ioctl, + mmap: agp_mmap, + open: agp_open, + release: agp_release, +}; + +static struct miscdevice agp_miscdev = +{ + AGPGART_MINOR, + AGPGART_MODULE_NAME, + &agp_fops +}; + +int __init agp_frontend_initialize(void) +{ + memset(&agp_fe, 0, sizeof(struct agp_front_data)); + AGP_LOCK_INIT(); + + if (misc_register(&agp_miscdev)) { + printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR); + return -EIO; + } + return 0; +} + +void agp_frontend_cleanup(void) +{ + misc_deregister(&agp_miscdev); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/amiga_ser.c linux/drivers/char/amiga_ser.c --- v2.2.17/drivers/char/amiga_ser.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/amiga_ser.c Fri Oct 13 23:57:54 2000 @@ -0,0 +1,558 @@ +/* + * drivers/char/amiga_ser.c: Amiga built-in serial port driver. + * + * Copyright 1994 Roman Hodek, 1994 Hamish Macdonald + * Based on the Atari MFP driver by Roman Hodek + * + * Modifications by Matthias Welwarsky + * - fixed reentrancy problem in ser_tx_int() + * + * 20/02/99 - Jesper Skov: Added mb() calls and KGDB support. + * 27/04/96 - Jes Soerensen: Upgraded for Linux-1.3.x. + * 02/09/96 - Jes Soerensen: Moved the {request,free}_irq call for + * AMIGA_VERTB interrupts into the init/deinit funtions as + * there is no reason to service the ser_vbl_int when the + * serial port is not in use. + * 30/04/96 - Geert Uytterhoeven: Added incoming BREAK detection + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + + +/* + * This file implements the driver for the Amiga built-in serial port. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* some serial hardware definitions */ +#define SDR_OVRUN (1<<15) +#define SDR_RBF (1<<14) +#define SDR_TBE (1<<13) +#define SDR_TSRE (1<<12) + +#define AC_SETCLR (1<<15) +#define AC_UARTBRK (1<<11) + +#define SER_DTR (1<<7) +#define SER_RTS (1<<6) +#define SER_DCD (1<<5) +#define SER_CTS (1<<4) +#define SER_DSR (1<<3) + +/***************************** Prototypes *****************************/ + +static void ser_rx_int( int irq, void *data, struct pt_regs *fp); +static void ser_tx_int( int irq, void *data, struct pt_regs *fp); +static void ser_vbl_int( int irq, void *data, struct pt_regs *fp); +static void ser_init( struct m68k_async_struct *info ); +static void ser_deinit( struct m68k_async_struct *info, int leave_dtr ); +static void ser_enab_tx_int( struct m68k_async_struct *info, int enab_flag ); +static int ser_check_custom_divisor (struct m68k_async_struct *info, + int baud_base, int divisor); +static void ser_change_speed( struct m68k_async_struct *info ); +static void ser_throttle( struct m68k_async_struct *info, int status ); +static void ser_set_break( struct m68k_async_struct *info, int break_flag ); +static void ser_get_serial_info( struct m68k_async_struct *info, + struct serial_struct *retinfo ); +static unsigned int ser_get_modem_info( struct m68k_async_struct *info ); +static int ser_set_modem_info( struct m68k_async_struct *info, int new_dtr, + int new_rts ); +static void ser_stop_receive( struct m68k_async_struct *info ); +static int ser_trans_empty( struct m68k_async_struct *info ); + +/************************* End of Prototypes **************************/ + + + +/* SERIALSWITCH structure for the Amiga serial port + */ + +static SERIALSWITCH amiga_ser_switch = { + ser_init, ser_deinit, ser_enab_tx_int, + ser_check_custom_divisor, ser_change_speed, + ser_throttle, ser_set_break, + ser_get_serial_info, ser_get_modem_info, + ser_set_modem_info, NULL, ser_stop_receive, ser_trans_empty, NULL +}; + +/* Standard speeds table */ +static int baud_table[19] = { + /* B0 */ 0, + /* B50 */ 50, + /* B75 */ 75, + /* B110 */ 110, + /* B134 */ 134, + /* B150 */ 150, + /* B200 */ 200, + /* B300 */ 300, + /* B600 */ 600, + /* B1200 */ 1200, + /* B1800 */ 1800, + /* B2400 */ 2400, + /* B4800 */ 4800, + /* B9600 */ 9600, + /* B19200 */ 19200, + /* B38400 */ 38400, + /* B57600 */ 57600, + /* B115200*/ 115200, + /* B230400*/ 230400 +}; + +static __inline__ void ser_DTRoff(void) +{ + ciab.pra |= SER_DTR; /* active low */ +} + +static __inline__ void ser_DTRon(void) +{ + ciab.pra &= ~SER_DTR; /* active low */ +} + +static __inline__ void ser_RTSoff(void) +{ + ciab.pra |= SER_RTS; /* active low */ +} + +static __inline__ void ser_RTSon(void) +{ + ciab.pra &= ~SER_RTS; /* active low */ +} + +static int line; /* the serial line assigned by register_serial() */ +/* use this value in isr's to get rid of the data pointer in the future */ +/* This variable holds the current state of the DCD/CTS bits */ +static unsigned char current_ctl_bits; + +static __inline__ void check_modem_status(struct m68k_async_struct *info) +{ + unsigned char bits; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + bits = ciab.pra & (SER_DCD | SER_CTS); + + if (bits ^ current_ctl_bits) { + if ((bits ^ current_ctl_bits) & SER_DCD) { + rs_dcd_changed(info, !(bits & SER_DCD)); + } + + if ((bits ^ current_ctl_bits) & SER_CTS) + rs_check_cts(info, !(bits & SER_CTS)); + } + current_ctl_bits = bits; +} + +static struct m68k_async_struct *amiga_info; + +int amiga_serinit( void ) +{ + unsigned long flags; + struct serial_struct req; + struct m68k_async_struct *info; + + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL)) + return -ENODEV; + + req.line = -1; /* first free ttyS? device */ + req.type = SER_AMIGA; + req.port = (int) &custom.serdatr; /* dummy value */ + if ((line = m68k_register_serial( &req )) < 0) { + printk( "Cannot register built-in serial port: no free device\n" ); + return -EBUSY; + } + info = &rs_table[line]; + + save_flags (flags); + cli(); + + /* set ISRs, and then disable the rx interrupts */ + request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", info); + request_irq(IRQ_AMIGA_RBF, ser_rx_int, 0, "serial RX", info); + + amiga_info = info; + + /* turn off Rx and Tx interrupts */ + custom.intena = IF_RBF | IF_TBE; + + /* clear any pending interrupt */ + custom.intreq = IF_RBF | IF_TBE; + restore_flags (flags); + + /* + * set the appropriate directions for the modem control flags, + * and clear RTS and DTR + */ + ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ + ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ + + info->sw = &amiga_ser_switch; + +#ifdef CONFIG_KGDB + /* turn Rx interrupts on for GDB */ + custom.intena = IF_SETCLR | IF_RBF; + ser_RTSon(); +#endif + + return 0; +} + +static void ser_rx_int(int irq, void *data, struct pt_regs *fp) +{ +#ifdef CONFIG_KGDB + extern void breakpoint (void); + int ch; + + ch = custom.serdatr; + mb(); + + custom.intreq = IF_RBF; + + /* Break signal from GDB? */ + if (0x03 == (ch & 0xff)) { + /* FIXME: This way of doing a breakpoint sucks + big time. I will fix it later. */ + breakpoint (); + } +#else + struct m68k_async_struct *info = data; + int ch, err; + + ch = custom.serdatr; + mb(); + + custom.intreq = IF_RBF; + + if ((ch & 0x1ff) == 0) + err = TTY_BREAK; + else if (ch & SDR_OVRUN) + err = TTY_OVERRUN; + else + err = 0; + rs_receive_char(info, ch & 0xff, err); +#endif +} + +static void ser_tx_int( int irq, void *data, struct pt_regs *fp) +{ +#ifndef CONFIG_KGDB + struct m68k_async_struct *info = data; + int ch; + + if (custom.serdatr & SDR_TBE) { + if ((ch = rs_get_tx_char(info)) >= 0) + /* write next char */ + custom.serdat = ch | 0x100; + if (ch == -1 || rs_no_more_tx( info )) + /* disable tx interrupts */ + custom.intena = IF_TBE; + } +#endif +} + + +static void ser_vbl_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + + check_modem_status(info); +} + + +static void ser_init( struct m68k_async_struct *info ) +{ +#ifndef CONFIG_KGDB + request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, + "serial status", amiga_info); + + /* enable both Rx and Tx interrupts */ + custom.intena = IF_SETCLR | IF_RBF | IF_TBE; + + /* turn on DTR and RTS */ + ser_DTRon(); + ser_RTSon(); + + /* remember current state of the DCD and CTS bits */ + current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS); + + MOD_INC_USE_COUNT; +#endif +} + + +static void ser_enab_tx_int (struct m68k_async_struct *info, int enab_flag) +{ +#ifndef CONFIG_KGDB + if (enab_flag) { + unsigned long flags; + save_flags(flags); + cli(); + custom.intena = IF_SETCLR | IF_TBE; + mb(); + /* set a pending Tx Interrupt, transmitter should restart now */ + custom.intreq = IF_SETCLR | IF_TBE; + mb(); + restore_flags(flags); + } else { + /* disable Tx interrupt and remove any pending interrupts */ + custom.intena = IF_TBE; + custom.intreq = IF_TBE; + } +#endif +} + + +static void ser_deinit( struct m68k_async_struct *info, int leave_dtr ) +{ +#ifndef CONFIG_KGDB + /* disable Rx and Tx interrupt */ + custom.intena = IF_RBF | IF_TBE; + mb(); + + /* wait for last byte to be completely shifted out */ + while( !(custom.serdatr & SDR_TSRE) ) + barrier(); + + /* drop RTS and DTR if required */ + ser_RTSoff(); + if (!leave_dtr) + ser_DTRoff(); + + free_irq(IRQ_AMIGA_VERTB, amiga_info); + MOD_DEC_USE_COUNT; +#endif +} + + +static int ser_check_custom_divisor (struct m68k_async_struct *info, + int baud_base, int divisor) +{ + /* allow any divisor */ + return 0; +} + + +static void ser_change_speed( struct m68k_async_struct *info ) +{ +#ifndef CONFIG_KGDB + unsigned cflag, baud, chsize, stopb, parity, aflags; + unsigned div = 0; + int realbaud; + + if (!info->tty || !info->tty->termios) return; + + cflag = info->tty->termios->c_cflag; + baud = cflag & CBAUD; + chsize = cflag & CSIZE; + stopb = cflag & CSTOPB; + parity = cflag & (PARENB | PARODD); + aflags = info->flags & ASYNC_SPD_MASK; + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + if (baud & CBAUDEX) + baud = baud - (B57600 - B38400 - 1); + + + if (baud == 15) { + switch (aflags) { + case ASYNC_SPD_HI: + baud += 1; + break; + case ASYNC_SPD_VHI: + baud += 2; + break; + case ASYNC_SPD_SHI: + baud += 3; + break; + case ASYNC_SPD_WARP: + baud += 4; + break; + case ASYNC_SPD_CUST: + div = info->custom_divisor; + break; + } + } + if (!div){ + /* Maximum speed is 230400 :-) */ + if (baud > 18) baud = 18; + realbaud = baud_table[baud]; + if (realbaud) + div = (amiga_colorclock+realbaud/2)/realbaud - 1; + } + + if (div) { + /* turn on DTR */ + ser_DTRon(); + } else { + /* speed == 0 -> drop DTR */ + ser_DTRoff(); + return; + } + + /* setup the serial port period register */ + custom.serper = div; +#endif +} + + +static void ser_throttle( struct m68k_async_struct *info, int status ) +{ +#ifndef CONFIG_KGDB + if (status) + ser_RTSoff(); + else + ser_RTSon(); +#endif +} + + +static void ser_set_break( struct m68k_async_struct *info, int break_flag ) +{ +#ifndef CONFIG_KGDB + if (break_flag) + custom.adkcon = AC_SETCLR | AC_UARTBRK; + else + custom.adkcon = AC_UARTBRK; +#endif +} + + +static void ser_get_serial_info( struct m68k_async_struct *info, + struct serial_struct *retinfo ) +{ + retinfo->baud_base = amiga_colorclock; + retinfo->custom_divisor = info->custom_divisor; +} + + +static unsigned int ser_get_modem_info( struct m68k_async_struct *info ) +{ + unsigned int minfo = ciab.pra; + + return( + ((minfo & SER_DTR) ? 0 : TIOCM_DTR) | + ((minfo & SER_RTS) ? 0 : TIOCM_RTS) | + ((minfo & SER_DCD) ? 0 : TIOCM_CAR) | + ((minfo & SER_CTS) ? 0 : TIOCM_CTS) | + ((minfo & SER_DSR) ? 0 : TIOCM_DSR) | + /* TICM_RNG */ 0 + ); +} + + +static int ser_set_modem_info( struct m68k_async_struct *info, + int new_dtr, int new_rts ) +{ +#ifndef CONFIG_KGDB + if (new_dtr == 0) + ser_DTRoff(); + else if (new_dtr == 1) + ser_DTRon(); + + if (new_rts == 0) + ser_RTSoff(); + else if (new_rts == 1) + ser_RTSon(); + + return 0; +#endif +} + +static void ser_stop_receive( struct m68k_async_struct *info ) +{ +#ifndef CONFIG_KGDB + /* disable receive interrupts */ + custom.intena = IF_RBF; + /* clear any pending receive interrupt */ + custom.intreq = IF_RBF; +#endif +} + +static int ser_trans_empty( struct m68k_async_struct *info ) +{ + return (custom.serdatr & SDR_TSRE); +} + +#ifdef CONFIG_KGDB +int amiga_ser_out( unsigned char c ) +{ + custom.serdat = c | 0x100; + mb(); + while (!(custom.serdatr & 0x2000)) + barrier(); + return 1; +} + +unsigned char amiga_ser_in( void ) +{ + unsigned char c; + + /* XXX: is that ok?? derived from amiga_ser.c... */ + while( !(custom.intreqr & IF_RBF) ) + barrier(); + c = custom.serdatr; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + return c; +} +#endif + +#ifdef MODULE +int init_module(void) +{ + return amiga_serinit(); +} + +void cleanup_module(void) +{ + m68k_unregister_serial(line); + custom.intena = IF_RBF | IF_TBE; /* forbid interrupts */ + custom.intreq = IF_RBF | IF_TBE; /* clear pending interrupts */ + mb(); + free_irq(IRQ_AMIGA_TBE, amiga_info); + free_irq(IRQ_AMIGA_RBF, amiga_info); +} +#endif + + +/* ------------------------------------ + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * End: + * ------------------------------------ + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c --- v2.2.17/drivers/char/amikeyb.c Fri Apr 21 12:45:51 2000 +++ linux/drivers/char/amikeyb.c Fri Oct 13 23:58:25 2000 @@ -257,7 +257,7 @@ amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); } - handle_scancode(scancode, !break_flag); + handle_scancode(keycode, !break_flag); } else switch (keycode) { case 0x78: @@ -340,9 +340,4 @@ k->rate = key_repeat_rate * 1000 / HZ; return( 0 ); -} - -/* for "kbd-reset" cmdline param */ -__initfunc(void amiga_kbd_reset_setup(char *str, int *ints)) -{ } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/atari_MFPser.c linux/drivers/char/atari_MFPser.c --- v2.2.17/drivers/char/atari_MFPser.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/atari_MFPser.c Sat Oct 14 00:06:42 2000 @@ -0,0 +1,946 @@ +/* + * drivers/char/atari_MFPser.c: Atari MFP serial ports implementation + * + * Copyright 1994 Roman Hodek + * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o + * + * Special thanks to Harun Scheutzow (developer of RSVE, RSFI, ST_ESCC and + * author of hsmoda-package) for the code to detect RSVE/RSFI. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + + +/* This file implements the MFP serial ports. These come in two + * flavors: with or without control lines (RTS, CTS, DTR, ...). They + * are distinguished by having two different types, MFP_CTRL and + * MFP_BARE, resp. Most of the low-level functions are the same for + * both, but some differ. + * + * Note that some assumptions are made about where to access the + * control lines. If the port type is MFP_CTRL, the input lines (CTS + * and DCD) are assumed to be in the MFP GPIP register, bits 1 and 2. + * The output lines (DTR and RTS) have to be in the Soundchip Port A, + * bits 3 and 4. This is the standard ST/TT assigment. If Atari will + * build a serial port in future, that uses other registers, you have + * to rewrite this code. But if the port type is MFP_BARE, no such + * assumptions are necessary. All registers needed are fixed by the + * MFP hardware. The only parameter is the MFP base address. This is + * used to implement Serial1 for the TT and the (not connected) MFP + * port of the Falcon. + * + * Juergen: changes based on Harun Scheutzows code + * o added detection of RSVE, RSFI and possible PLL's + * o set info->hub6 to identify speeder-hardware + * o changed Tx output-level when transmitter is disabled + * o no need for CONFIG_ATARI_MFPSER_EXT + * + * + * o add delays for baudrate-setting to lock PLLs (RSFI, RSVE) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "atari_MFPser.h" + +#define RSFI_DEBUG /* undefine to get rid of "detect_MFP_speeder: clock[x] = y" */ +#define RSFI_PLL_LOCK_DELAY /* use delay to allow PLL settling */ + +/***************************** Prototypes *****************************/ + +static void MFPser_init_port( struct m68k_async_struct *info, int type, + int tt_flag ); +#ifdef MODULE +static void MFPser_deinit_port( struct m68k_async_struct *info, int tt_flag ); +#endif +static void MFPser_rx_int (int irq, void *data, struct pt_regs *fp); +static void MFPser_rxerr_int (int irq, void *data, struct pt_regs *fp); +static void MFPser_tx_int (int irq, void *data, struct pt_regs *fp); +static void MFPctrl_dcd_int (int irq, void *data, struct pt_regs *fp); +static void MFPctrl_cts_int (int irq, void *data, struct pt_regs *fp); +static void MFPctrl_ri_int (int irq, void *data, struct pt_regs *fp); +static void MFPser_init( struct m68k_async_struct *info ); +static void MFPser_deinit( struct m68k_async_struct *info, int leave_dtr ); +static void MFPser_enab_tx_int( struct m68k_async_struct *info, int enab_flag ); +static int MFPser_check_custom_divisor (struct m68k_async_struct *info, + int baud_base, int divisor); +static void MFPser_change_speed( struct m68k_async_struct *info ); +static void MFPctrl_throttle( struct m68k_async_struct *info, int status ); +static void MFPbare_throttle( struct m68k_async_struct *info, int status ); +static void MFPser_set_break( struct m68k_async_struct *info, int break_flag ); +static void MFPser_get_serial_info( struct m68k_async_struct *info, struct + serial_struct *retinfo ); +static unsigned int MFPctrl_get_modem_info( struct m68k_async_struct *info ); +static unsigned int MFPbare_get_modem_info( struct m68k_async_struct *info ); +static int MFPctrl_set_modem_info( struct m68k_async_struct *info, int new_dtr, + int new_rts ); +static int MFPbare_set_modem_info( struct m68k_async_struct *info, int new_dtr, + int new_rts ); +static void MFPser_stop_receive (struct m68k_async_struct *info); +static int MFPser_trans_empty (struct m68k_async_struct *info); + +/************************* End of Prototypes **************************/ + + +/* SERIALSWITCH structures for MFP ports + * Most functions are common to MFP ports with or without control lines + */ + +static SERIALSWITCH MFPctrl_switch = { + MFPser_init, MFPser_deinit, MFPser_enab_tx_int, + MFPser_check_custom_divisor, MFPser_change_speed, + MFPctrl_throttle, MFPser_set_break, + MFPser_get_serial_info, MFPctrl_get_modem_info, + MFPctrl_set_modem_info, NULL, MFPser_stop_receive, MFPser_trans_empty, + NULL +}; + +static SERIALSWITCH MFPbare_switch = { + MFPser_init, MFPser_deinit, MFPser_enab_tx_int, + MFPser_check_custom_divisor, MFPser_change_speed, + MFPbare_throttle, MFPser_set_break, + MFPser_get_serial_info, MFPbare_get_modem_info, + MFPbare_set_modem_info, NULL, MFPser_stop_receive, MFPser_trans_empty, + NULL +}; + + /* MFP Timer Modes divided by 2 (this already done in the BAUD_BASE + * The real 68901 prescaler factors are twice these values! + * prescaler_factor[] = {4, 10, 16, 50, 64, 100, 200} + */ +int MFP_timer_modes[] = { 2, 5, 8, 25, 32, 50, 100 }; + + /* RSVE or RSSPEED will only recognize the 3 frequencies for + * 110, 134, 150 Baud, if the prescaler is 4 and the counter value does + * the rest. The divisors 350 and 256 can be built in multiple ways. + * This driver tries to use the largest prescaler factor possible and + * uses small counter values. TOS uses a prescaler factor of 4 + * ==> MFP_timer_mode = 2 ==> Index 0. Then RSVE replaces the clock + * correctly. Since the absolute frequencies don't have to be so accurate + * but the the prescaler factor has to be 4 we have to make sure that the + * divisors for the 'real' 110, 134, 150 baud can be built with a + * prescaler factor > 4 and the divisors for the replaced 110, 134, 150 + * baud can only be built with a prescaler factor of 4 and a larger + * counter value. Accuracy is not so important here, since RSVE catches + * the values by ignoring the lower 3 bits. + */ + + /* Added support for RSFI + * RSFI is a hardware-FIFO with the following features: + * o 2048bit Rx-FIFO + * o baudrates: 38400, 57600, 76800, 115200, 153600, 230400 + * baudrate-selection and FIFO-enable is done by setting + * the effective baudrate to 50 .. 200. In contrast to the + * RSVE the clockselection is independend from the prescale- + * factor. Instead, the MFP must be in x1 clockmode. + * o the FIFO is only enabled when speeds are above 19k2 + * + * Relationship between MFP-baudrate and RSFI-baudrate + * MFP mode RSFI + * 50 x1 76.8K *) + * 75 x1 153.6K *) + * 110 x1 38.4K + * 134 x1 57.6K + * 150 x1 115.2K + * 200 x1 230.4K + * + * *) Non-standard baudrates, not supported. + * + * We keep the speeder-type in info->hub6. This flag is unused on + * non-Intel architectures. + * + */ + +int MFP_baud_table[22] = { /* Divisors for standard speeds, RSVE & RSFI */ + /* B0 */ 0, + /* B50 */ 768, + /* B75 */ 512, + /* B110 */ 350, /* really 109.71 bps */ /* MFP_mode 50 != 2 */ + /* B134 */ 288, /* really 133.33 bps */ /* MFP_mode 8 != 2 */ + /* B150 */ 256, /* MFP_mode 32 != 2 */ + /* B200 */ 192, + /* B300 */ 128, + /* B600 */ 64, + /* B1200 */ 32, + /* B1800 */ 21, + /* B2400 */ 16, + /* B4800 */ 8, + /* B9600 */ 4, + /* B19200 */ 2, + /* B38400 */ 348, /* 38.4K with RSVE/RSFI, prescaler 4 = MFP_mode 2 */ + /* B57600 */ 286, /* 57.6K with RSVE/RSFI, prescaler 4 = MFP_mode 2 */ + /* B115200 */ 258, /* 115.2K with RSVE/RSFI, prescaler 4 = MFP_mode 2 */ + /* --------------- the following values are ignored in RSVE-mode */ + /* B230400 */ 192, /* 230.4K with RSFI */ + /* B460800 */ 0, /* illegal */ +}; + + +#define DEFAULT_STMFP_LINE 0 /* ttyS0 */ +#define DEFAULT_TTMFP_LINE 2 /* ttyS2 */ + +static int stmfp_line = -1, ttmfp_line = -1; + +extern int atari_MFP_init_done; + + +int atari_MFPser_init( void ) + +{ struct serial_struct req; + int nr = 0; + extern char m68k_debug_device[]; + + if (!MACH_IS_ATARI) + return( -ENODEV ); + + if (ATARIHW_PRESENT(ST_MFP)) { + if (!strcmp( m68k_debug_device, "ser1" )) + printk(KERN_NOTICE "ST-MFP serial port used as debug device\n" ); + else { + req.line = DEFAULT_STMFP_LINE; + req.type = SER_MFP_CTRL; + req.port = (int)&mfp; + if ((stmfp_line = register_serial( &req )) >= 0) { + MFPser_init_port( &rs_table[stmfp_line], req.type, 0 ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for ST-MFP\n", req.line ); + } + } + + if (ATARIHW_PRESENT(TT_MFP)) { + req.line = DEFAULT_TTMFP_LINE; + req.type = SER_MFP_BARE; + req.port = (int)&tt_mfp; + if ((ttmfp_line = register_serial( &req )) >= 0) { + MFPser_init_port( &rs_table[ttmfp_line], req.type, 1 ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for TT-MFP\n", req.line ); + } + + return( nr > 0 ? 0 : -ENODEV ); +} + +static void __inline__ set_timer_D(volatile struct MFP *thismfp, + int baud, int prescale) { +/* set timer d to given value, prescale 4 + * allow PLL-settling (3 bit-times) + */ + + int count; + + thismfp->tim_ct_cd &= 0xf8; /* disable timer D */ + thismfp->tim_dt_d = baud; /* preset baudrate */ + thismfp->tim_ct_cd |= prescale; /* enable timer D, prescale N */ + + for( count = 6; count; --count ) { + thismfp->int_pn_b = ~0x10; + while( !(thismfp->int_pn_b & 0x10) ) + ; + } +} + +static int detect_MFP_speeder(volatile struct MFP *currMFP) { +/* try to autodetect RSVE, RSFI or similiar RS232 speeders + * + * (c) Harun Scheutzow + * developer of RSVE, RSFI, ST_ESCC and author of hsmoda-package + * + * integrated by Juergen Orschiedt + * + * noise-free detection of Tx/Rx baudrate + * - set MFP to loopback, syncmode, 8bpc, syncchar=0xff + * - enable transmitter and measure time between syncdetect + * depending on the relationship between measured time and + * timer-d setting we can tell which (if any) speeder we have. + * + * returncodes: + * 0 something wrong (1200 too slow) + * 1 no speeder detected + * 2 RSVE detected + * 3 RSFI detected + * 4 PLL or fixed Baudrate (Hardware-hack) + */ + + int count, speeder; + unsigned int flags; + int imra, imrb; + + /* prepare IRQ registers for measurement */ + + save_flags(flags); + cli(); + + imra = currMFP->int_mk_a; + imrb = currMFP->int_mk_b; + + currMFP->int_mk_a = imra & 0xe1; /* mask off all Rx/Tx ints */ + currMFP->int_mk_b = imrb & 0xef; /* disable timer d int in IMRB */ + currMFP->int_en_b |= 0x10; /* enable in IERB (to see pending ints) */ + restore_flags(flags); + + (void)currMFP->par_dt_reg; /* consume some cycles */ + (void)currMFP->par_dt_reg; + + /* initialize MFP */ + currMFP->rcv_stat = 0x00; /* disable Rx */ + currMFP->trn_stat = TSR_SOMODE_HIGH; /* disable Tx, output-level high */ + currMFP->sync_char= 0xff; /* syncchar = 0xff */ + currMFP->usart_ctr= (UCR_PARITY_OFF | UCR_SYNC_MODE | UCR_CHSIZE_8); + currMFP->trn_stat = (TSR_TX_ENAB | TSR_SOMODE_LOOP); + + /* look at 1200 baud setting (== effective 19200 in syncmode) */ + set_timer_D(currMFP, 0x10, 0x01); + save_flags(flags); + cli(); + + /* check for fixed speed / bad speed */ + currMFP->rcv_stat = RSR_RX_ENAB; + count = -1; + do { + continue_outer: + ++count; + currMFP->int_pn_b = ~0x10; + do { + if (currMFP->int_pn_b & 0x10) + goto continue_outer; + } while( !(currMFP->rcv_stat & RSR_SYNC_SEARCH) && count <= 22 ); + } while(0); + restore_flags(flags); + + /* for RSxx or standard MFP we have 8 bittimes (count=16) */ +#ifdef RSFI_DEBUG + printk(KERN_INFO " detect_MFP_speeder: count[1200]=%d\n", count); +#endif + + if (count < 10) + speeder = MFP_WITH_PLL; /* less than 5 bittimes: primitive speeder */ + else + if (count >22) + speeder = MFP_WITH_WEIRED_CLOCK; /* something wrong - too slow! */ + else { + /* 1200 baud is working, we neither have fixed clock nor simple PLL */ + set_timer_D(currMFP, 0xaf, 0x01); + save_flags(flags); + cli(); + + /* check for RSxx or Standard MFP with 110 baud + * timer D toggles each 290us + * bps sync char count + * RSVE: 614400 22.33 13uS + * RSFI: 38400 1.39 208us + * Standard: 1720 0.06 + * + */ + currMFP->int_pn_b = ~0x10; + /* syncronize to timer D */ + while( !(currMFP->int_pn_b & 0x10) ) + ; + currMFP->int_pn_b = ~0x10; + count = -1; + do { + continue_outer2: + currMFP->rcv_stat = 0; /* disable Rx */ + ++count; + (void)currMFP->par_dt_reg; /* delay */ + currMFP->rcv_stat = RSR_RX_ENAB; /* enable Rx */ + nop(); + do { + /* increment counter if sync char detected */ + if (currMFP->rcv_stat & RSR_SYNC_SEARCH) + goto continue_outer2; + } while( !(currMFP->int_pn_b & 0x10) ); + } while(0); + +#ifdef RSFI_DEBUG + printk(KERN_INFO " detect_MFP_speeder: count[110]=%d\n", count); +#endif + + if (count < 1) speeder = MFP_STANDARD; /* no speeder detected */ + else + if (count > 4) speeder = MFP_WITH_RSVE; + else + speeder = MFP_WITH_RSFI; + } + + restore_flags(flags); + currMFP->rcv_stat = 0x00; /* disable Rx */ + currMFP->trn_stat = TSR_SOMODE_HIGH; /* disable Tx, output-level high */ + currMFP->usart_ctr= (UCR_PARITY_OFF | UCR_ASYNC_2 | UCR_CHSIZE_8); + currMFP->int_mk_a = imra; + currMFP->int_mk_b = imrb; + currMFP->int_en_b &= 0xef; + currMFP->int_pn_a = 0xe1; /* mask off pending Rx/Tx */ + currMFP->int_pn_b = 0xef; /* mask off pending Timer D */ + return speeder; + +} + +static void MFPser_init_port( struct m68k_async_struct *info, int type, int tt_flag) +{ + INIT_currMFP(info); + int speeder; + static char *speeder_name[]= {"", "", "PLL or fixed clock", "RSVE", "RSFI" }; + + /* look for possible speeders */ + info->hub6 = speeder = detect_MFP_speeder((struct MFP *)currMFP); + if (speeder > MFP_STANDARD) + printk(KERN_INFO "ttyS%d: Detected %s extension\n", + info->line, speeder_name[speeder]); + + + /* set ISRs, but don't enable interrupts yet (done in init()); + * all ints are choosen of type FAST, and they're really quite fast. + * Furthermore, we have to account for the fact that these are three ints, + * and one can interrupt another. So better protect them against one + * another... + */ + request_irq(tt_flag ? IRQ_TT_MFP_SEREMPT : IRQ_MFP_SEREMPT, + MFPser_tx_int, IRQ_TYPE_FAST, + tt_flag ? "TT-MFP TX" : "ST-MFP TX", info); + request_irq(tt_flag ? IRQ_TT_MFP_RECFULL : IRQ_MFP_RECFULL, + MFPser_rx_int, IRQ_TYPE_FAST, + tt_flag ? "TT-MFP RX" : "ST-MFP RX", info); + request_irq(tt_flag ? IRQ_TT_MFP_RECERR : IRQ_MFP_RECERR, + MFPser_rxerr_int, IRQ_TYPE_FAST, + tt_flag ? "TT-MFP RX error" : "ST-MFP RX error", info); + /* Tx_err interrupt unused (it signals only that the Tx shift reg + * is empty) + */ + + if (type == SER_MFP_CTRL && !tt_flag) { + /* The DCD, CTS and RI ints are slow ints, because I + see no races with the other ints */ + request_irq(IRQ_MFP_DCD, MFPctrl_dcd_int, IRQ_TYPE_SLOW, + "ST-MFP DCD", info); + request_irq(IRQ_MFP_CTS, MFPctrl_cts_int, IRQ_TYPE_SLOW, + "ST-MFP CTS", info); + request_irq(IRQ_MFP_RI, MFPctrl_ri_int, IRQ_TYPE_SLOW, + "ST-MFP RI", info); + /* clear RTS and DTR */ + if (!atari_MFP_init_done) + /* clear RTS and DTR */ + GIACCESS( GI_RTS | GI_DTR ); + } + + info->sw = (type == SER_MFP_CTRL ? &MFPctrl_switch : &MFPbare_switch); + + info->custom_divisor = 4; /* 9600 Baud */ + info->baud_base = MFP_BAUD_BASE; + + if (tt_flag || !atari_MFP_init_done) { + currMFP->rcv_stat = 0; /* disable Rx */ + currMFP->trn_stat = TSR_SOMODE_HIGH; /* disable Tx */ + } +} + + +#ifdef MODULE +static void MFPser_deinit_port( struct m68k_async_struct *info, int tt_flag ) +{ + free_irq(tt_flag ? IRQ_TT_MFP_SEREMPT : IRQ_MFP_SEREMPT, info); + free_irq(tt_flag ? IRQ_TT_MFP_RECFULL : IRQ_MFP_RECFULL, info); + free_irq(tt_flag ? IRQ_TT_MFP_RECERR : IRQ_MFP_RECERR, info); + if (info->type == SER_MFP_CTRL && !tt_flag) { + free_irq(IRQ_MFP_DCD, info ); + free_irq(IRQ_MFP_CTS, info ); + free_irq(IRQ_MFP_RI, info); + } +} +#endif + + +static void MFPser_rx_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + int ch, stat, err; + INIT_currMFP(info); + + stat = currMFP->rcv_stat; + ch = currMFP->usart_dta; + /* Frame Errors don't cause a RxErr IRQ! */ + err = (stat & RSR_FRAME_ERR) ? TTY_FRAME : 0; + + rs_receive_char (info, ch, err); +} + + +static void MFPser_rxerr_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + int ch, stat, err; + INIT_currMFP(info); + + stat = currMFP->rcv_stat; + ch = currMFP->usart_dta; /* most probably junk data */ + + if (stat & RSR_PARITY_ERR) + err = TTY_PARITY; + else if (stat & RSR_OVERRUN_ERR) + err = TTY_OVERRUN; + else if (stat & RSR_BREAK_DETECT) + err = TTY_BREAK; + else if (stat & RSR_FRAME_ERR) /* should not be needed */ + err = TTY_FRAME; + else + err = 0; + + rs_receive_char (info, ch, err); +} + + +static void MFPser_tx_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + int ch; + INIT_currMFP(info); + + if (currMFP->trn_stat & TSR_BUF_EMPTY) { + if ((ch = rs_get_tx_char( info )) >= 0) + currMFP->usart_dta = ch; + if (ch == -1 || rs_no_more_tx( info )) + /* disable tx interrupts */ + currMFP->int_en_a &= ~0x04; + } +} + + +static void MFPctrl_dcd_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + INIT_currMFP(info); + + /* Toggle active edge to get next change of DCD! */ + currMFP->active_edge ^= GPIP_DCD; + + rs_dcd_changed( info, !(currMFP->par_dt_reg & GPIP_DCD) ); +} + + +static void MFPctrl_cts_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + INIT_currMFP(info); + + /* Toggle active edge to get next change of CTS! */ + currMFP->active_edge ^= GPIP_CTS; + + rs_check_cts( info, !(currMFP->par_dt_reg & GPIP_CTS) ); +} + + +static void MFPctrl_ri_int(int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + /* update input line counter */ + info->icount.rng++; + wake_up_interruptible(&info->delta_msr_wait); +} + + +static void MFPser_init( struct m68k_async_struct *info ) +{ + INIT_currMFP(info); + + /* base value for UCR */ + if (info->type != SER_MFP_CTRL || !atari_MFP_init_done) + currMFP->usart_ctr = (UCR_PARITY_OFF | UCR_ASYNC_1 | + UCR_CHSIZE_8 | UCR_PREDIV); + + /* enable Rx and clear any error conditions */ + currMFP->rcv_stat = RSR_RX_ENAB; + + /* enable Tx */ + currMFP->trn_stat = (TSR_TX_ENAB | TSR_SOMODE_HIGH); + + /* enable Rx, RxErr and Tx interrupts */ + currMFP->int_en_a |= 0x1c; + currMFP->int_mk_a |= 0x1c; + + if (info->type == SER_MFP_CTRL) { + + int status; + + /* set RTS and DTR (low-active!) */ + GIACCESS( ~(GI_RTS | GI_DTR) ); + + /* Set active edge of CTS and DCD signals depending on their + * current state. + * If the line status changes between reading the status and + * enabling the interrupt, this won't work :-( How could it be + * done better?? + * ++andreas: do it better by looping until stable + */ + do { + status = currMFP->par_dt_reg & GPIP_CTS; + if (status) + currMFP->active_edge &= ~GPIP_CTS; + else + currMFP->active_edge |= GPIP_CTS; + } while ((currMFP->par_dt_reg & GPIP_CTS) != status); + + do { + status = currMFP->par_dt_reg & GPIP_DCD; + if (status) + currMFP->active_edge &= ~GPIP_DCD; + else + currMFP->active_edge |= GPIP_DCD; + } while ((currMFP->par_dt_reg & GPIP_DCD) != status); + + /* enable CTS and DCD interrupts */ + currMFP->int_en_b |= 0x06; + currMFP->int_mk_b |= 0x06; + } + MOD_INC_USE_COUNT; +} + + +static void MFPser_deinit( struct m68k_async_struct *info, int leave_dtr ) +{ + INIT_currMFP(info); + + /* disable Rx, RxErr and Tx interrupts */ + currMFP->int_en_a &= ~0x1c; + + if (info->type == SER_MFP_CTRL) { + /* disable CTS and DCD interrupts */ + currMFP->int_en_b &= ~0x06; + } + + /* disable Rx and Tx */ + currMFP->rcv_stat = 0; + currMFP->trn_stat = TSR_SOMODE_HIGH; + + /* wait for last byte to be completely shifted out */ + while( !(currMFP->trn_stat & TSR_LAST_BYTE_SENT) ) + ; + + if (info->type == SER_MFP_CTRL) { + /* drop RTS and DTR if required */ + MFPser_RTSoff(); + if (!leave_dtr) + MFPser_DTRoff(); + } + + /* read Rx status and data to clean up */ + (void)currMFP->rcv_stat; + (void)currMFP->usart_dta; + MOD_DEC_USE_COUNT; +} + + +static void MFPser_enab_tx_int( struct m68k_async_struct *info, int enab_flag ) +{ + INIT_currMFP(info); + + if (enab_flag) { + unsigned long flags; + currMFP->int_en_a |= 0x04; + save_flags(flags); + cli(); + MFPser_tx_int (0, info, 0); + restore_flags(flags); + } + else + currMFP->int_en_a &= ~0x04; +} + + +static int MFPser_check_custom_divisor (struct m68k_async_struct *info, + int baud_base, int divisor) +{ + int i; + + if (baud_base != MFP_BAUD_BASE) + return -1; + + /* divisor must be a multiple of 2 or 5 (because of timer modes) */ + if (divisor == 0 || ((divisor & 1) && (divisor % 5) != 0)) return( -1 ); + + /* Determine what timer mode would be selected and look if the + * timer value would be greater than 256 + */ + for( i = sizeof(MFP_timer_modes)/sizeof(*MFP_timer_modes)-1; i >= 0; --i ) + if (divisor % MFP_timer_modes[i] == 0) break; + if (i < 0) return( -1 ); /* no suitable timer mode found */ + + return (divisor / MFP_timer_modes[i] > 256); +} + + +static void MFPser_change_speed( struct m68k_async_struct *info ) +{ + unsigned cflag, baud, chsize, stopb, parity, aflags; + unsigned div = 0, timer_val; + int timer_mode; + unsigned long ipl; + INIT_currMFP(info); + + if (!info->tty || !info->tty->termios) return; + + cflag = info->tty->termios->c_cflag; + baud = cflag & CBAUD; + chsize = cflag & CSIZE; + stopb = cflag & CSTOPB; + parity = cflag & (PARENB | PARODD); + aflags = info->flags & ASYNC_SPD_MASK; + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + if (baud < 1 || baud > 4) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + if (info->hub6 > MFP_WITH_PLL) /* speeder detected? */ + baud += 15; + } + if ((info->hub6 > MFP_WITH_PLL) && (baud == 15)) { + /* only for speeders... */ + switch (aflags) { + case ASYNC_SPD_HI: + baud += 1; /* 134 Baud, with RSVE = 57600 */ + break; + case ASYNC_SPD_VHI: + baud += 2; /* 150 Baud, with RSVE = 115200 */ + break; + case ASYNC_SPD_SHI: + baud += 3; /* with RSFI: 230400 Baud */ + break; + case ASYNC_SPD_WARP: + baud += 4; + break; + case ASYNC_SPD_CUST: + div = info->custom_divisor; + break; + } + } + if (!div) { + /* max. tableentries depending on speeder type */ + static int maxbaud[] = { 14, 14, 14, 17, 18}; + if (baud > maxbaud[info->hub6]) + baud = maxbaud[info->hub6]; + div = MFP_baud_table[baud]; + } + + if (div) { + /* turn on DTR */ + MFPser_DTRon (); + } else { + /* speed == 0 -> drop DTR */ + MFPser_DTRoff(); + return; + } + + /* compute timer value and timer mode (garuateed to succeed, because + * the divisor was checked before by check_custom_divisor(), if it + * is used-supplied) + */ + for( timer_mode = sizeof(MFP_timer_modes)/sizeof(*MFP_timer_modes)-1; + timer_mode >= 0; --timer_mode ) + if (div % MFP_timer_modes[timer_mode] == 0) break; + timer_val = div / MFP_timer_modes[timer_mode]; + + save_flags (ipl); + cli(); + /* disable Rx and Tx while changing parameters */ + currMFP->rcv_stat = 0; + currMFP->trn_stat = TSR_SOMODE_HIGH; + +#ifdef RSFI_PLL_LOCK_DELAY + currMFP->int_en_b |= 0x10; + set_timer_D(currMFP, timer_val, timer_mode+1); + currMFP->int_en_b &= 0xef; +#else + /* stop timer D to set new timer value immediatly after re-enabling */ + currMFP->tim_ct_cd &= ~0x07; + currMFP->tim_dt_d = timer_val; + currMFP->tim_ct_cd |= (timer_mode+1); +#endif + { + unsigned shadow_ctr; + + shadow_ctr = ((parity & PARENB) ? + ((parity & PARODD) ? UCR_PARITY_ODD : UCR_PARITY_EVEN) : + UCR_PARITY_OFF ) | + ( chsize == CS5 ? UCR_CHSIZE_5 : + chsize == CS6 ? UCR_CHSIZE_6 : + chsize == CS7 ? UCR_CHSIZE_7 : UCR_CHSIZE_8 ) | + ( stopb ? UCR_ASYNC_2 : UCR_ASYNC_1 ); + + if ((baud < 15) || (info->hub6 != MFP_WITH_RSFI)) + shadow_ctr |= UCR_PREDIV; + currMFP->usart_ctr = shadow_ctr; + } + + /* re-enable Rx and Tx */ + currMFP->rcv_stat = RSR_RX_ENAB; + currMFP->trn_stat = (TSR_TX_ENAB | TSR_SOMODE_HIGH); + restore_flags (ipl); +} + +static void MFPctrl_throttle( struct m68k_async_struct *info, int status ) +{ + if (status) + MFPser_RTSoff(); + else + MFPser_RTSon(); +} + + +static void MFPbare_throttle( struct m68k_async_struct *info, int status ) +{ + /* no-op */ +} + + +static void MFPser_set_break( struct m68k_async_struct *info, int break_flag ) +{ + INIT_currMFP(info); + + if (break_flag) + currMFP->trn_stat |= TSR_SEND_BREAK; + else + currMFP->trn_stat &= ~TSR_SEND_BREAK; +} + + +static void MFPser_get_serial_info( struct m68k_async_struct *info, + struct serial_struct *retinfo ) +{ + retinfo->baud_base = info->baud_base; + retinfo->custom_divisor = info->custom_divisor; +} + + +static unsigned int MFPctrl_get_modem_info( struct m68k_async_struct *info ) +{ + unsigned gpip, gi; + unsigned int ri; + unsigned long ipl; + INIT_currMFP(info); + + save_flags (ipl); + cli(); + gpip = currMFP->par_dt_reg; + gi = GIACCESS( 0 ); + restore_flags (ipl); + + /* DSR is not connected on the Atari, assume it to be set; + * RI is tested by the RI bitpos field of info, because the RI is + * signalled at different ports on TT and Falcon + * ++andreas: the signals are inverted! + */ + /* If there is a SCC but no TT_MFP then RI on the ST_MFP is + used for SCC channel b */ + if (ATARIHW_PRESENT (SCC) && !ATARIHW_PRESENT (TT_MFP)) + ri = 0; + else if (currMFP == &mfp) + ri = gpip & GPIP_RI ? 0 : TIOCM_RNG; + else + ri = 0; + return (((gi & GI_RTS ) ? 0 : TIOCM_RTS) | + ((gi & GI_DTR ) ? 0 : TIOCM_DTR) | + ((gpip & GPIP_DCD) ? 0 : TIOCM_CAR) | + ((gpip & GPIP_CTS) ? 0 : TIOCM_CTS) | + TIOCM_DSR | ri); +} + + +static unsigned int MFPbare_get_modem_info( struct m68k_async_struct *info ) +{ + return( TIOCM_RTS | TIOCM_DTR | TIOCM_CAR | TIOCM_CTS | TIOCM_DSR ); +} + + +static int MFPctrl_set_modem_info( struct m68k_async_struct *info, + int new_dtr, int new_rts ) +{ + if (new_dtr == 0) + MFPser_DTRoff(); + else if (new_dtr == 1) + MFPser_DTRon(); + + if (new_rts == 0) + MFPser_RTSoff(); + else if (new_rts == 1) + MFPser_RTSon(); + + return( 0 ); +} + + +static int MFPbare_set_modem_info( struct m68k_async_struct *info, + int new_dtr, int new_rts ) +{ + /* no-op */ + + /* Is it right to return an error or should the attempt to change + * DTR or RTS be silently ignored? + */ + return( -EINVAL ); +} + +static void MFPser_stop_receive (struct m68k_async_struct *info) +{ + INIT_currMFP(info); + + /* disable rx and rxerr interrupt */ + currMFP->int_en_a &= ~0x18; + + /* disable receiver */ + currMFP->rcv_stat = 0; + /* disable transmitter */ + currMFP->trn_stat = TSR_SOMODE_HIGH; +} + +static int MFPser_trans_empty (struct m68k_async_struct *info) +{ + INIT_currMFP(info); + return (currMFP->trn_stat & TSR_LAST_BYTE_SENT) != 0; +} + +#ifdef MODULE +int init_module(void) +{ + return( atari_MFPser_init() ); +} + +void cleanup_module(void) +{ + if (stmfp_line >= 0) { + MFPser_deinit_port( &rs_table[stmfp_line], 0 ); + unregister_serial( stmfp_line ); + } + if (ttmfp_line >= 0) { + MFPser_deinit_port( &rs_table[ttmfp_line], 1 ); + unregister_serial( ttmfp_line ); + } +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/atari_MFPser.h linux/drivers/char/atari_MFPser.h --- v2.2.17/drivers/char/atari_MFPser.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/atari_MFPser.h Sat Oct 14 00:06:42 2000 @@ -0,0 +1,131 @@ + +/* + * atari_MFPser.h: Definitions for MFP serial ports + * + * Copyright 1994 Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + + +#ifndef _ATARI_MFPSER_H +#define _ATARI_MFPSER_H + +#define INIT_currMFP(info) \ + volatile struct MFP *currMFP = (volatile struct MFP *)(info->port) + +/* MFP input frequency, divided by 16 (USART prediv for async modes) + * and 2 because of each timer run _toggles_ the output, resulting in + * half the frequency, and 2 as greatest common divisor of all timer + * modes. + */ +#define MFP_BAUD_BASE (2457600/16/2/2) + +/* USART Control Register */ + +#define UCR_PARITY_MASK 0x06 +#define UCR_PARITY_OFF 0x00 +#define UCR_PARITY_ODD 0x04 +#define UCR_PARITY_EVEN 0x06 + +#define UCR_MODE_MASK 0x18 +#define UCR_SYNC_MODE 0x00 +#define UCR_ASYNC_1 0x08 +#define UCR_ASNYC_15 0x10 +#define UCR_ASYNC_2 0x18 + +#define UCR_CHSIZE_MASK 0x60 +#define UCR_CHSIZE_8 0x00 +#define UCR_CHSIZE_7 0x20 +#define UCR_CHSIZE_6 0x40 +#define UCR_CHSIZE_5 0x60 + +#define UCR_PREDIV 0x80 + +/* Receiver Status Register */ + +#define RSR_RX_ENAB 0x01 +#define RSR_STRIP_SYNC 0x02 +#define RSR_SYNC_IN_PRGR 0x04 /* sync mode only */ +#define RSR_CHAR_IN_PRGR 0x04 /* async mode only */ +#define RSR_SYNC_SEARCH 0x08 /* sync mode only */ +#define RSR_BREAK_DETECT 0x08 /* async mode only */ +#define RSR_FRAME_ERR 0x10 +#define RSR_PARITY_ERR 0x20 +#define RSR_OVERRUN_ERR 0x40 +#define RSR_CHAR_AVAILABLE 0x80 + +/* Transmitter Status Register */ + +#define TSR_TX_ENAB 0x01 + +#define TSR_SOMODE_MASK 0x06 +#define TSR_SOMODE_OPEN 0x00 +#define TSR_SOMODE_LOW 0x02 +#define TSR_SOMODE_HIGH 0x04 +#define TSR_SOMODE_LOOP 0x06 + +#define TSR_SEND_BREAK 0x08 +#define TSR_LAST_BYTE_SENT 0x10 +#define TSR_HALF_DUPLEX 0x20 +#define TSR_UNDERRUN 0x40 +#define TSR_BUF_EMPTY 0x80 + +/* Control signals in the GPIP */ + +#define GPIP_DCD 0x02 +#define GPIP_CTS 0x04 +#define GPIP_RI 0x40 + +/* MFP speeders */ +#define MFP_WITH_WEIRED_CLOCK 0x00 +#define MFP_STANDARD 0x01 +#define MFP_WITH_PLL 0x02 +#define MFP_WITH_RSVE 0x03 +#define MFP_WITH_RSFI 0x04 + + +/* Convenience routine to access RTS and DTR in the Soundchip: It sets + * the register to (oldvalue & mask) if mask is negative or (oldvalue + * | mask) if positive. It returns the old value. I guess the + * parameters will be constants most of the time, so gcc can throw + * away the if statement if it isn't needed. + */ + +static __inline__ unsigned char GIACCESS( int mask ) +{ + unsigned long cpu_status; + unsigned char old; + + save_flags(cpu_status); + cli(); + + sound_ym.rd_data_reg_sel = 14; + old = sound_ym.rd_data_reg_sel; + + if (mask) { + if (mask < 0) + sound_ym.wd_data = old & mask; + else + sound_ym.wd_data = old | mask; + } + + restore_flags(cpu_status); + return( old ); +} + +#define GI_RTS 0x08 +#define GI_DTR 0x10 + +#define MFPser_RTSon() GIACCESS( ~GI_RTS ) +#define MFPser_RTSoff() GIACCESS( GI_RTS ) +#define MFPser_DTRon() GIACCESS( ~GI_DTR ) +#define MFPser_DTRoff() GIACCESS( GI_DTR ) + + +int atari_MFPser_init( void ); + +#endif /* _ATARI_MFPSER_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/atari_MIDI.c linux/drivers/char/atari_MIDI.c --- v2.2.17/drivers/char/atari_MIDI.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/atari_MIDI.c Sat Oct 14 00:06:42 2000 @@ -0,0 +1,567 @@ +/* + * drivers/char/atari_MIDI.c: Atari MIDI driver as serial port + * + * Copyright 1994 Roman Hodek + * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * Modified for midi by Martin Schaller + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "atari_MIDI.h" + + +/* Defines */ + +/* #define _DEBUG_MIDI_ */ + +#define DEFAULT_MIDI_LINE 5 /* ttyS5 */ +#define MIDI_BAUD_BASE 500000 /* 31250 */ + +#define STOP_SHIFT 0 +#define PAR_SHIFT 4 +#define CS_SHIFT 8 + +/* Prototypes */ +static void MIDI_init_port(struct m68k_async_struct* info, int type, int tt_flag); +static void MIDI_int(void); /* called from keyboard int handler */ +static void MIDI_init( struct m68k_async_struct * info ); +static void MIDI_deinit( struct m68k_async_struct * info, int leave_dtr ); +static void MIDI_enab_tx_int( struct m68k_async_struct * info, int enab_flag ); +static int MIDI_check_custom_divisor(struct m68k_async_struct* info, int baud_base, int divisor); +static void MIDI_change_speed( struct m68k_async_struct * info ); +static void MIDI_throttle( struct m68k_async_struct * info, int status ); +static void MIDI_set_break( struct m68k_async_struct * info, int break_flag ); +static unsigned int MIDI_get_modem_info( struct m68k_async_struct * info ); +static void MIDI_get_serial_info( struct m68k_async_struct* info, struct serial_struct* retinfo); +static int MIDI_set_modem_info( struct m68k_async_struct* info, int new_dtr, int new_rts ); +static void MIDI_stop_receive(struct m68k_async_struct * info); +static int MIDI_trans_empty(struct m68k_async_struct * info); + + +struct m68k_async_struct* midi_info; +static unsigned char mid_ctrl_shadow; /* Bernd Harries, 960525 */ +static unsigned char mid_stat_shadow; /* Bernd Harries, 961207 */ + + +#ifdef _BHA_MIDI_CHAR_FMT +static int MIDI_char_fmt[8] = { + (CS7 << CS_SHIFT) | (PARENB << PAR_SHIFT) | (2 << STOP_SHIFT), + (CS7 << CS_SHIFT) | ((PARENB | PARODD) << PAR_SHIFT) | (2 << STOP_SHIFT), + (CS7 << CS_SHIFT) | (PARENB << PAR_SHIFT) | (1 << STOP_SHIFT), + (CS7 << CS_SHIFT) | ((PARENB | PARODD) << PAR_SHIFT) | (1 << STOP_SHIFT), + (CS8 << CS_SHIFT) | (0 << PAR_SHIFT) | (2 << STOP_SHIFT), + (CS8 << CS_SHIFT) | (0 << PAR_SHIFT) | (1 << STOP_SHIFT), + (CS8 << CS_SHIFT) | (PARENB << PAR_SHIFT) | (1 << STOP_SHIFT), + (CS8 << CS_SHIFT) | ((PARENB | PARODD) << PAR_SHIFT) | (1 << STOP_SHIFT), +}; +#endif + + /* index = P * 4 + L * 2 + S * 1 */ + /* S = (2 == Stopbits) */ + /* L = (8 == Databits) */ + /* P = Parity {Odd, Even, None} */ + +static char ACIA_char_fmt[16] = { + ACIA_D7O1S, + ACIA_D7O2S, + ACIA_D8O1S, + -1, + ACIA_D7E1S, + ACIA_D7E2S, + ACIA_D8E1S, + -1, + -1, + -1, + ACIA_D8N1S, + ACIA_D8N2S, + -2 +}; + +/* Divisors for standard speeds & RSVE Bernd Harries 961127 */ +static int MIDI_baud_table[20] = { + /* B0 */ 0, /* invalid */ + /* B50 */ 0, + /* B75 */ 0, + /* B110 */ 0, + /* B134 */ 0, + /* B150 */ 0, + /* B200 */ 0, + /* B300 */ 0, + /* B600 */ 0, + /* B1200 */ 0, + /* B1800 */ 0, + /* B2400 */ 0, + /* B4800 */ 0, /* invalid */ + /* B9600 */ 64, /* really 7812.5 bps */ + /* B19200 */ 0, /* invalid */ + /* B38400 */ 16, /* really 31250 bps */ + /* B57600 */ 0, /* invalid */ + /* B115200 */ 0, /* invalid */ + /* B230400 */ 0, /* invalid */ + /* B460800 */ 1 /* really 500000 bps */ +}; + + /* The following 2 arrays must be congruent! */ +static int ACIA_prescaler_modes[] = { 1, 16, 64 }; +static char ACIA_baud_masks[] = { ACIA_DIV1, ACIA_DIV16, ACIA_DIV64 }; + + /* + * SERIALSWITCH structures for MIDI port + */ + +static SERIALSWITCH MIDI_switch = { + MIDI_init, + MIDI_deinit, + MIDI_enab_tx_int, + MIDI_check_custom_divisor, + MIDI_change_speed, + MIDI_throttle, + MIDI_set_break, + MIDI_get_serial_info, + MIDI_get_modem_info, + MIDI_set_modem_info, + NULL, /* MIDI_ioctl, */ + MIDI_stop_receive, + MIDI_trans_empty, + NULL /* MIDI_check_open */ +}; + + +__initfunc(int atari_MIDI_init( void )) +{ + extern char m68k_debug_device[]; + static struct serial_struct req; + int midi_line; + int nr = 0; + +#ifdef _DEBUG_MIDI_ + printk(" atari_MIDI_init() \n"); +#endif + + if (!strcmp( m68k_debug_device, "midi" )) + printk(KERN_NOTICE "MIDI serial port used as debug device\n" ); + else { + req.line = DEFAULT_MIDI_LINE; + req.type = SER_MIDI; + req.port = (int) &acia.mid_ctrl; + + midi_line = register_serial( &req ); + if (midi_line >= 0) { + MIDI_init_port(&rs_table[midi_line], req.type, 0); + ++nr; + } + else { + printk(KERN_WARNING "Cannot allocate ttyS%d for MIDI\n", req.line ); + } + } + return( nr > 0 ? 0 : -ENODEV ); +} + + +static void MIDI_init_port(struct m68k_async_struct * info, int type, int tt_flag) +{ + midi_info = info; /* modulglobal !!!!! */ + + info->sw = &MIDI_switch; + info->custom_divisor = 16; /* 31250 Baud */ + info->baud_base = MIDI_BAUD_BASE; + info->sw = &MIDI_switch; + + + /* set ISRs, but don't enable interrupts yet (done in init()); + * all ints are choosen of type FAST, and they're really quite fast. + * Furthermore, we have to account for the fact that these are three ints, + * and one can interrupt another. So better protect them against one + * another... + */ + /* + request_irq(IRQ_MIDI_SEREMPT, MIDI_tx_int, IRQ_TYPE_FAST, "MIDI TX", info); + request_irq(IRQ_MIDI_RECFULL, MIDI_rx_int, IRQ_TYPE_FAST, "MIDI RX", info); + request_irq(IRQ_MIDI_RECERR, + MIDI_rxerr_int, + IRQ_TYPE_FAST, + "MIDI RX error", + info); + */ + + /* Tx_err interrupt unused (it signals only that the Tx shift reg + * is empty) + */ + /* Leave RTS high for now if selected as a switch, so that it's still valid + * as long as the port isn't opened. + */ + mid_ctrl_shadow = ACIA_DIV16 | ACIA_D8N1S | + ((atari_switches&ATARI_SWITCH_MIDI) ? + ACIA_RHTID : ACIA_RLTID); + acia.mid_ctrl = mid_ctrl_shadow; + + atari_MIDI_interrupt_hook = MIDI_int; +} + + +static void MIDI_int(void) /* called from keyboard int handler */ +{ + static int err; +/* register int stat; */ + register int ch; + + mid_stat_shadow = acia.mid_ctrl; + + /* if == Rx Data Reg Full -> Interrupt */ + if (mid_stat_shadow & (ACIA_RDRF | ACIA_FE | ACIA_OVRN)) { + ch = acia.mid_data; + err = 0; + if(mid_stat_shadow & ACIA_FE) err = TTY_FRAME; + if(mid_stat_shadow & ACIA_OVRN) err = TTY_OVERRUN; + rs_receive_char(midi_info, ch, err); + /* printk("R"); */ + } + + if (acia.mid_ctrl & ACIA_TDRE) { /* Tx Data Reg Empty Transmit Interrupt */ + ch = rs_get_tx_char( midi_info ); + + if (ch >= 0) { /* 32 Bit */ + acia.mid_data = ch; + /* printk("_%c", ch); */ + } + + if (ch == -1 || rs_no_more_tx( midi_info )) { + /* disable tx interrupts %x01xxxxx ==> %x00xxxxx */ + /* RTS Low, Tx IRQ Disabled */ + mid_ctrl_shadow &= ~ACIA_RLTIE; + acia.mid_ctrl = mid_ctrl_shadow; + /* printk("T"); */ + } + } +} + +static void MIDI_init( struct m68k_async_struct * info ) +{ +#ifdef _DEBUG_MIDI_ + printk(" MIDI_init() \n"); +#endif + /* Baud = DIV16, 8N1, denable rx interrupts */ + mid_ctrl_shadow = ACIA_DIV16 | ACIA_D8N1S | ACIA_RIE; + acia.mid_ctrl = mid_ctrl_shadow; + + MOD_INC_USE_COUNT; +} + +static void MIDI_deinit( struct m68k_async_struct *info, int leave_dtr ) +{ +#ifdef _DEBUG_MIDI_ + printk(" MIDI_deinit() \n"); +#endif + + /* seems like the status register changes on read */ +#ifdef _MIDI_WAIT_FOR_TX_EMPTY_ + while(!(mid_stat_shadow & ACIA_TDRE)) { /* wait for TX empty */ + ; + /* printk("m"); */ + } +#endif + + /* Baud = DIV16, 8N1, disable Rx and Tx interrupts */ + mid_ctrl_shadow = ACIA_DIV16 | ACIA_D8N1S; + acia.mid_ctrl = mid_ctrl_shadow; + + /* read Rx status and data to clean up */ + (void)acia.mid_ctrl; + (void)acia.mid_data; + + MOD_DEC_USE_COUNT; +} + + +/* + * ACIA Control Register can only be written! Read accesses Status Register! + * Shadowing may be nescessary here like for SCC + * + * Bernd Harries, 960525 Tel.: +49-421-804309 + * harries@asrv01.atlas.de + * Bernd_Harries@hb2.maus.de + */ + +static void MIDI_enab_tx_int( struct m68k_async_struct * info, int enab_flag ) +{ + unsigned long cpu_status; + + if (enab_flag) { + register int ch; + + save_flags(cpu_status); + cli(); + /* RTS Low, Tx IRQ Enabled */ + mid_ctrl_shadow |= ACIA_RLTIE; + acia.mid_ctrl = mid_ctrl_shadow; + /* restarted the transmitter */ + /* + * These extensions since 0.9.5 are only allowed, if the + * Tx Data Register is Empty! + * In 1.2.13pl10 this did not work. So I added the if(). + * + * Bernd Harries 960530 + * harries@atlas.de + * harries@asrv01.atlas.de + * Bernd_Harries@hb2.maus.de + */ + if (acia.mid_ctrl & ACIA_TDRE) { /* If last Char since disabling is gone */ + ch = rs_get_tx_char( midi_info ); + if (ch >= 0) { + acia.mid_data = ch; + /* printk("=%c", ch); */ + } + + if (ch == -1 || rs_no_more_tx( midi_info )) { + /* disable tx interrupts */ + /* RTS Low, Tx IRQ Disabled */ + mid_ctrl_shadow &= ~ACIA_RLTIE; + acia.mid_ctrl = mid_ctrl_shadow; + + } + } + restore_flags(cpu_status); + } else { + save_flags(cpu_status); + cli(); + /* RTS Low, Tx IRQ Disabled */ + mid_ctrl_shadow &= ~ACIA_RLTIE; + acia.mid_ctrl = mid_ctrl_shadow; + restore_flags(cpu_status); + } +} + + +static int MIDI_check_custom_divisor(struct m68k_async_struct* info, int baud_base, int divisor) +{ +#ifdef _DEBUG_MIDI_ + printk(" MIDI_check_custom_divisor() \n"); +#endif + + if (baud_base != MIDI_BAUD_BASE) return -1; + + /* divisor must be a multiple of 1, 16, 64 */ + + switch (divisor) { + case 1: + case 16: + case 64: return(0); + } + + return(-1); +} + + +static void MIDI_change_speed( struct m68k_async_struct *info ) +{ + unsigned long cpu_status; + unsigned int baud, stopb, parity, aflags; + unsigned int div, cflag, chsize; + int timer_mode; + int index; + + unsigned char mid_ctrl_new; + unsigned char baud_mask; + unsigned char chsize_mask; + unsigned char fmt_mask; + +#ifdef _DEBUG_MIDI_ + printk(" MIDI_change_speed() \n"); +#endif + + div = 0; + cflag = info->tty->termios->c_cflag; + baud = cflag & CBAUD; + chsize = cflag & CSIZE; + stopb = cflag & CSTOPB; + parity = cflag & (PARENB | PARODD); + aflags = info->flags & ASYNC_SPD_MASK; + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + if (baud < 1 || baud > 4) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; + } + if (baud == 15) { + switch (aflags) { + case ASYNC_SPD_HI: + baud = 16; /* 134 Baud, with RSVE = 57600 */ + break; + case ASYNC_SPD_VHI: + baud = 17; /* 150 Baud, with RSVE = 115200 */ + break; + case ASYNC_SPD_SHI: + baud = 18; + break; + case ASYNC_SPD_WARP: + baud = 19; + break; + case ASYNC_SPD_CUST: + div = info->custom_divisor; + break; + } + } + + if (!div) { + /* Maximum MIDI speed is 500000 */ + if (baud > 19) baud = 19; + div = MIDI_baud_table[baud]; + } + + if (div) { + /* turn on DTR */ + /* MIDI_DTRon(); */ + } else { + /* speed == 0 -> drop DTR */ + /* MIDI_DTRoff(); */ + return; + } + + mid_ctrl_new = 0; + for (timer_mode = 2; timer_mode >= 0; timer_mode--) + if (ACIA_prescaler_modes[timer_mode] == div) + break; + + baud_mask = ACIA_baud_masks[timer_mode]; + + chsize_mask = 0; + if (chsize == CS8) chsize_mask = ACIA_D8N2S; + + index = 0; + if (stopb) index |= (1 << 0); + if (chsize == CS8) index |= (1 << 1); + if (parity == 0) + index |= (2 << 2); + else if (parity == PARENB) + index |= (1 << 2); + else { /* if(parity == PARENB | PARODD) */ + /* index |= (0 << 2); */ + } + + fmt_mask = ACIA_char_fmt[index]; + + /* Now we have all parameters and can go to set them: */ + save_flags(cpu_status); + cli(); + + /* disable Rx and Tx while changing parameters + * stop timer D to set new timer value immediatly after re-enabling + */ + mid_ctrl_shadow &= ~ACIA_RESET; /* MASK_OUT significant bits */ + mid_ctrl_shadow |= baud_mask; + mid_ctrl_shadow &= ~ACIA_D8O1S; + mid_ctrl_shadow |= fmt_mask; + + acia.mid_ctrl = mid_ctrl_shadow; /* Write only */ + restore_flags(cpu_status); + +#ifdef _DEBUG_MIDI_ + printk(" MIDI_change_speed() done. \n"); +#endif +} + + +static void MIDI_throttle( struct m68k_async_struct * info, int status ) +{ + if (status) ; /* MIDI_RTSoff(); */ + else ; /* MIDI_RTSon(); */ +} + + +static void MIDI_set_break( struct m68k_async_struct * info, int break_flag ) +{ +} + + +static unsigned int MIDI_get_modem_info( struct m68k_async_struct *info ) +{ + return( TIOCM_RTS | TIOCM_DTR | TIOCM_CAR | TIOCM_CTS | TIOCM_DSR ); +} + + +static void MIDI_get_serial_info( struct m68k_async_struct* info, struct serial_struct* retinfo ) +{ +#ifdef _DEBUG_MIDI_ + printk(" MIDI_get_serial_info() \n"); +#endif + + retinfo->baud_base = info->baud_base; + retinfo->custom_divisor = info->custom_divisor; +} + + +static int MIDI_set_modem_info( struct m68k_async_struct *info, int new_dtr, int new_rts ) +{ + /* Is it right to return an error or should the attempt to change + * DTR or RTS be silently ignored? + */ + return( -EINVAL ); +} + + +static void MIDI_stop_receive (struct m68k_async_struct *info) +{ + unsigned long cpu_status; + + save_flags(cpu_status); + cli(); + + /* disable receive interrupts */ + mid_ctrl_shadow &= ~ACIA_RIE; + acia.mid_ctrl = mid_ctrl_shadow; + restore_flags(cpu_status); +} + + +static int MIDI_trans_empty (struct m68k_async_struct *info) +{ + return (acia.mid_ctrl & ACIA_TDRE) != 0; +} + + +#ifdef MODULE +int init_module(void) +{ + return( atari_MIDI_init() ); +} + +void cleanup_module(void) +{ + atari_MIDI_interrupt_hook = NULL; + unregister_serial( midi_info->line ); +} +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/atari_MIDI.h linux/drivers/char/atari_MIDI.h --- v2.2.17/drivers/char/atari_MIDI.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/atari_MIDI.h Sat Oct 14 00:06:42 2000 @@ -0,0 +1,32 @@ +/* + * atari_MIDI.h: Definitions for the MIDI serial port + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + +#ifndef _ATARI_MIDI_H +#define _ATARI_MIDI_H + +int atari_MIDI_init( void ); + + +#ifdef _MIDI_HSK_LINES_ + +#define MIDI_RTSon() +#define MIDI_RTSoff() +#define MIDI_DTRon() +#define MIDI_DTRoff() + +else + +#define MIDI_RTSon +#define MIDI_RTSoff +#define MIDI_DTRon +#define MIDI_DTRoff + +#endif + +#endif /* _ATARI_MIDI_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/atari_SCC.README linux/drivers/char/atari_SCC.README --- v2.2.17/drivers/char/atari_SCC.README Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/atari_SCC.README Sat Oct 14 00:06:42 2000 @@ -0,0 +1,194 @@ +atari_SCC.README +================ + + This is the README covering the new DMA features of the Atari SCC driver. It +works reasonably well for me, but you may disagree. If so, please contact: + +TeSche (Torsten Scherer) +itschere@techfak.uni-bielefeld.de + + +0) Intro + + As a funny intro let me cite the AMD Am8530H technical manual: "Use of a DMA +controller is suggested for any system that transmits above 500 kb/s". Harhar, +good joke... + + +1) Supported Hardware / Software + + That's simple to answer: Currently only the TT is supported, and since all +other Atari machines lack DMA support for the SCC this isn't likely to +change. There have been reports about some Falcons with Afterburner card(?) +claiming they have DMA, but they don't, believe me. I've strengthened the +condition to try DMA to 'DMA available and TT-MFP available', so you should be +on the safer side. However, for the severe cases it can be completely disabled +by a config option. + + With the same hardware reason all numbers or ratings you may occasionally read +in this file are measured on a stock TT with monochrome monitor. + + The SCC_DMA driver has been tested with speeds up to 115k2 baud. It may work +with something higher, but I'm not sure about the 230k4 and 560k8 that have +recently been added, meaning, I haven't tested it because I can't. In theory it +should work with 230k4 baud with the default parameters (see below), but not +with 560k8. + + +2) Basic Principle of Operation + + This driver uses DMA to support receiving of data. It does not use DMA to +transmit data. Roman Hodek once philosophized about doing a little statistic +comparing how much data was received and how much was transmitted to decide +whether to use DMA for the next receive or the next transmit each time it +becomes vacant. That's a) horribly complicated and b) discards the fact that we +all have problems with receiver overruns, and not with transmit underruns. So +only DMA receive is supported. And, hey, I said he philosophized, I didn't say +he was thinking about it seriously. :) + + There's another problem with general purpose communication: You don't know in +advance how many data will arrive. Ok, in case of IP you do after you've read +the header, but that's just a special case. In general this leads to that the +driver doesn't know how many data is to be expected and thus can't set up the +DMA for exactly that amount of data. What it does is set up DMA on a buffer +that it thinks it large enough and let a timer routine flush this buffer +asyncronously. + + This timer routine must stop DMA, read restbytes and restart DMA on another +buffer very, very quickly. It doesn't even flush the buffers on its own, but +uses a bottom half handler for this. Since this one can be delayed for many +reasons it's not enough to have just two buffers to switch between (like TTY +flip buffers), but instead you need more. + + These buffers are directly flushed to the TTY's receive function, may that be +a PPP line discipline or whatever. The whole concept of flip buffers is totally +circumvented, as these buffers are very likely to run over when switching VTYs, +in fact I'd say you can regard this as a law. :( + + A nice little side effect of DMA support is that you save a lot of +cycles. When the whole stuff of delivering data (avoiding the byte-oriented +flip buffer interface) and waking up listening programs has only to be done +once for every 1k of data that saves you an awful lot of computing power. You +can easily see that if you compare DMA supported download with uploads, which +still operate the normal way. + + If you should see a message like: + +Sep 25 22:27:26 zaphod kernel: SCC-A: 1 overrun, 0 parity, 0 frame errors + + that means there have been errors in the serial link. Since 99% of all +possible errors (given a correct serial parameter setting) are likely to be +overrun errors and the main task of DMA support is exactly to get rid of them I +chosed to print these information unconditionally each time an error +occurs. You shouldn't really see a lot of them, in theory: None. If you see +*some* be happy that they're less than with ordinary serial ports. If you don't +think they're less, complain. + + If you should see a message like: + +Sep 25 22:26:08 zaphod kernel: SCC-A: fatal buffer overflow, data lost! + + that means that execution of the bottom half flusher was delayed so long that +the timer routine didn't find a free buffer. This can only be caused by +exhaustive VTY switching I guess, all other things that could happen are +unlikely to block your system for so long. However, if it happens there's not +very much to do besides increasing the number of buffers (see below). + + If you should see a message like: + +Sep 26 10:39:32 zaphod kernel: SCC-A: DMA-INT occured, data lost! + + that means that the timer routine itself has been delayed so long that the DMA +counter went to zero already. There's not very much to do about this, because +since both the timer and the end-of-dma INT are IPL6 the latter one is probably +also delayed and thus data is already lost. The only thing you can do is +increase the size of the buffers. + + So there are three basic parameters: The number of buffers to use, their size +and the flushing frequency. + + +3) Operating Parameters + + Somewhere at the beginning of atari_SCC.c you'll find a short section that +defines some parameters of the DMA support, namely the number and size of +buffers. The flushing rate is encoded a bit more implicitly more downwards. My +defaults for a TT are 8 buffers of 2k and a flushing rate of 12Hz. + + 12Hz flushing rate at a receive speed of 115k2 baud leads to 960 chars per +buffer. Choosing 1k looked to be a good idea, but extensive SCSI activity +ruined that one. Since the buffer size must be a power of two I've chosen 2k. +If the bottom half flusher finds a buffer which is more than 95% full it prints +a warning. If you should see lots of these messages it can only mean you're +running something very much higher than 115k2 baud, in which case you should +increase the buffer size yet more (to 4k). If you're not running at higher +rates you've got the problem that the flusher gets extremely delayed. You can +still increase the buffer size, but you should better find out what's delaying +the flusher and fix that. + + The number of buffers is also experimental: I've seen that on a TT with +monochrome screen a VTY switching can 'use' 3 or 4 buffers, sometimes 5. So +with 8 buffers you should be on the safer side. You can activate the diagnostic +printk in SCC_flush() if you want to check that out. You may choose any number +of buffers, no restriction on this one. + + I might add code to dynamically select these parameters depending upon the +current speed later, but for the moment this should work nicely. + + +4) Debugging + + It is possible to define DEBUG_DMA at the beginning of atari_SCC.c. In that +case the driver will print lots of information about what it is doing with or +getting from the DMA. It then uses a flushing frequency of 0.48Hz to allow you +to follow the output with your eyes, but this also means that with a buffer +size of 1k you shouldn't use more than 19k2 baud or else you'll get problems. + + +5) Performance + + I've written a small program which opens a tty in raw mode and dumps all data +that arrives into a file while printing how fast data arrived. Using this +program I can receive data at 115k2 baud without a single error, even while +switching VTYs or SCSI disc accesses. This costs me almost no cycle. :) + + When being logged in via the SCC and downloading data at 115k2 baud with rz I +get an average transfer rate of 9800 cps over 10 megs, including 12 errors +(whilst heaviest disc activity). No disc activity yields 10600 cps and 0 +errors. This costs me nearly 40% of my cycles, probably because that version of +rz isn't very clever. + + On a 115k2 baud PPP link I get an average paket loss of less than 2%, yielding +at worst 7k/s. When dialing into our university network with a 28.8 modem +running 115k2 baud I get less than 1% paket loss, yielding at worst 2.5k/s +(best case so far: 3.2k/s). In either case you can verify that ftp download +only costs you some 5% of your cycles, whereas an upload costs you almost any +cycle you've got. + + +6) Problems + + There're a couple of words to say about why I still get paket loss: + + The paket loss is caused by 'bad fcs' fields, as you can see when you enable +'kdebug' in pppd. I've tried dumping the bad pakets in the PPP layer, and it +showed me that the normal data stream was interrupted by some trash data being +inserted. I've also tried dumping the data at SCC level, and the trash was +present there too. + + Numerous experiments have shown that these errors occur when the SCC *sends* +data while receiving, which is perfectly consistent with the fact that I don't +get a single error with my own just-dump-it program. Anything you do which +forces data to be send increases probability of these errors. In case of a PPP +link running ftp chose a big MTU/MRU rate, as this reduces the amount of +acknowledge packets to be send back and you can see that the error rate drops. + + Since I couldn't find anything in the tx_int function which might cause this I +think it's a hardware bug. It wouldn't be the first one my TT has got... :( + + BUT: Whereever these problems may come from, they're *far* less disturbing +than the SCC driver without DMA support, so I think this state is legal for the +moment. :) + +04.Dec.1966, +TeSche diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/atari_SCC.c linux/drivers/char/atari_SCC.c --- v2.2.17/drivers/char/atari_SCC.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/atari_SCC.c Sat Oct 14 00:06:42 2000 @@ -0,0 +1,2624 @@ +/* + * drivers/char/atari_SCC.c: Atari SCC serial ports implementation + * + * Copyright 1994-95 Roman Hodek + * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o + * + * Some parts were taken from the (incomplete) SCC driver by Lars Brinkhoff + * + * + * Adapted to 1.2 by Andreas Schwab + * + * Adapted to support MVME147, MVME162 and BVME6000 by Richard Hirst + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * Description/Notes: + * + * - This driver currently handles the asynchronous modes of the SCC ports + * only. Synchronous operation or packet modes aren't implemented yet. + * + * - Since there are many variations how the SCC can be integrated, the + * driver offers the possibility to provide the frequencies attached to the + * various clock inputs via an ioctl (along with an externally calculated + * baud table). + * + * - I haven't spent much time for optimizations yet... + * + * - Channel A is accessible via two different devices: ttyS3 and ttyS4. The + * former is the RS232 "Serial2" port, the latter the RS422 "LAN" port. + * Only one of these devices can be open at one time. + * + * - ++TeSche 12/96: DMA support for channel A, see atari_SCC.README for details + * send comments/problems to: itschere@techfak.uni-bielefeld.de + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef CONFIG_MVME147_SCC +#include +#endif +#ifdef CONFIG_MVME162_SCC +#include +#endif +#ifdef CONFIG_BVME6000_SCC +#include +#endif +#ifdef CONFIG_ATARI +#include +#include +#endif +#include +#include + +#include "atari_SCC.h" + + +#if defined CONFIG_ATARI_SCC || defined CONFIG_ATARI_SCC_MODULE +#define ENABLE_ATARI_SCC +#endif + +#define DEBUG_INT 0x01 +#define DEBUG_INIT 0x02 +#define DEBUG_THROTTLE 0x04 +#define DEBUG_INFO 0x08 +#define DEBUG_SPEED 0x10 +#define DEBUG_OPEN 0x20 +#define DEBUG_OVERRUNS 0x40 +/* warning: DEBUG_DMA will lead to a driver which is not able to operate at + * more than 19200 bps without causing overruns! + */ +#define DEBUG_DMA 0x80 + +#define DEBUG_ALL 0xffffffff +#define DEBUG_NONE 0 + +#define DEBUG DEBUG_NONE + +#define CHANNEL_A 0 +#define CHANNEL_B 1 + + +/* Shadows for all SCC write registers */ +static unsigned char SCC_shadow[2][16]; + +/* Location to access for SCC register access delay */ +static volatile unsigned char *scc_del; + +/* To keep track of STATUS_REG state for detection of Ext/Status int source */ +static unsigned char SCC_last_status_reg[2]; + +/* This array tells the clocks connected to RTxC or TRxC, resp., (2nd + * index) for each channel (1st index). + * + * This table is initialzed for the TT. If we run on another machine, + * the values are changed by the initialization function. + */ + +static unsigned SCC_clocks[2][2] = { + /* RTxC */ /* TRxC */ + { SCC_BAUD_BASE_PCLK4, SCC_BAUD_BASE_NONE }, /* Channel A */ + { SCC_BAUD_BASE_TIMC, SCC_BAUD_BASE_BCLK } /* Channel B */ +}; + +/* The SCC's master clock (as variable, in case someone has unusual + * hardware) + */ + +static unsigned SCC_PCLK = SCC_BAUD_BASE_PCLK; + + +/* BRG values for the standard speeds and the various clock sources */ + +typedef struct { + unsigned clksrc; /* clock source to use or -1 for not possible */ + unsigned div; /* divisor: 1, 2 and 4 correspond to + * direct 1:16, 1:32 and 1:64 modes, + * divisors >= 4 yield a BRG value of + * div/2-2 (in 1:16 mode) + */ +} BAUD_ENTRY; + +/* A pointer for each channel to the current baud table */ +static BAUD_ENTRY *SCC_baud_table[2]; + +/* Baud table format: + * + * Each entry consists of the clock source (CLK_RTxC, CLK_TRxC or + * CLK_PCLK) and a divisor. The following rules apply to the divisor: + * + * - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use + * the BRG) + * + * - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible) + * + * - CLK_PCLK: >= 4 and even (no direct modes, only BRG) + * + */ + +#ifdef ENABLE_ATARI_SCC +/* This table is used if RTxC = 3.672 MHz. This is the case for TT's + * channel A and for both channels on the Mega STE/Falcon. (TRxC is unused) + */ + +static BAUD_ENTRY bdtab_norm[20] = { + /* B0 */ { 0, 0 }, + /* B50 */ { CLK_RTxC, 4590 }, + /* B75 */ { CLK_RTxC, 3060 }, + /* B110 */ { CLK_PCLK, 4576 }, + /* B134 */ { CLK_PCLK, 3756 }, + /* B150 */ { CLK_RTxC, 1530 }, + /* B200 */ { CLK_PCLK, 2516 }, + /* B300 */ { CLK_PCLK, 1678 }, + /* B600 */ { CLK_PCLK, 838 }, + /* B1200 */ { CLK_PCLK, 420 }, + /* B1800 */ { CLK_PCLK, 280 }, + /* B2400 */ { CLK_PCLK, 210 }, + /* B4800 */ { CLK_RTxC, 48 }, + /* B9600 */ { CLK_RTxC, 24 }, + /* B19200 */ { CLK_RTxC, 12 }, + /* B38400 */ { CLK_RTxC, 6 }, /* #15 spd_extra */ + /* B57600 */ { CLK_RTxC, 4 }, /* #16 spd_hi */ + /* B115200 */ { CLK_RTxC, 2 }, /* #17 spd_vhi */ + /* B230400 */ { CLK_RTxC, 1 }, /* #18 spd_shi */ + /* B460800 */ { 0, 0 } /* #19 spd_warp: Impossible */ +}; + +/* This is a special table for the TT channel B with 307.2 kHz at RTxC + * and 2.4576 MHz at TRxC + */ +static BAUD_ENTRY bdtab_TTChB[20] = { + /* B0 */ { 0, 0 }, + /* B50 */ { CLK_RTxC, 384 }, + /* B75 */ { CLK_RTxC, 256 }, + /* B110 */ { CLK_PCLK, 4576 }, + /* B134 */ { CLK_PCLK, 3756 }, + /* B150 */ { CLK_RTxC, 128 }, + /* B200 */ { CLK_RTxC, 96 }, + /* B300 */ { CLK_RTxC, 64 }, + /* B600 */ { CLK_RTxC, 32 }, + /* B1200 */ { CLK_RTxC, 16 }, + /* B1800 */ { CLK_PCLK, 280 }, + /* B2400 */ { CLK_RTxC, 8 }, + /* B4800 */ { CLK_RTxC, 4 }, + /* B9600 */ { CLK_RTxC, 2 }, + /* B19200 */ { CLK_RTxC, 1 }, + /* B38400 */ { CLK_TRxC, 4 }, + /* B57600 */ { CLK_TRxC, 2 }, /* 57600 is not possible, use 76800 instead */ + /* B115200 */ { CLK_TRxC, 1 }, /* 115200 is not possible, use 153600 instead */ + /* B230400 */ { 0, 0 }, /* #18 spd_shi: Impossible */ + /* B460800 */ { 0, 0 } /* #19 spd_warp: Impossible */ +}; +#endif + +#ifdef CONFIG_MVME147_SCC +/* This table is used if RTxC = pCLK = 5 MHz. This is the case for MVME147 + */ +static BAUD_ENTRY bdtab_m147[19] = { + /* B0 */ { 0, 0 }, + /* B50 */ { CLK_PCLK, 6250 }, + /* B75 */ { CLK_PCLK, 4166 }, + /* B110 */ { CLK_PCLK, 2814 }, + /* B134 */ { CLK_PCLK, 2322 }, + /* B150 */ { CLK_PCLK, 2084 }, + /* B200 */ { CLK_PCLK, 1562 }, + /* B300 */ { CLK_PCLK, 1040 }, + /* B600 */ { CLK_PCLK, 520 }, + /* B1200 */ { CLK_PCLK, 260 }, + /* B1800 */ { CLK_PCLK, 194 }, + /* B2400 */ { CLK_PCLK, 130 }, + /* B4800 */ { CLK_PCLK, 64 }, + /* B9600 */ { CLK_PCLK, 32 }, + /* B19200 */ { CLK_PCLK, 16 }, + /* B38400 */ { CLK_PCLK, 8 }, + /* B57600 */ { CLK_PCLK, 4 }, + /* B115200 */ { CLK_PCLK, 2 }, + /* B230400 */ { CLK_PCLK, 1 }, /* #18 spd_shi */ +}; +#endif + +#ifdef CONFIG_MVME162_SCC +/* This table is used if RTxC = pCLK = 10 MHz. This is the case for MVME162 + */ +static BAUD_ENTRY bdtab_mvme[20] = { + /* B0 */ { 0, 0 }, + /* B50 */ { CLK_PCLK, 12500 }, + /* B75 */ { CLK_PCLK, 8332 }, + /* B110 */ { CLK_PCLK, 5682 }, + /* B134 */ { CLK_PCLK, 4646 }, + /* B150 */ { CLK_PCLK, 4166 }, + /* B200 */ { CLK_PCLK, 3124 }, + /* B300 */ { CLK_PCLK, 2082 }, + /* B600 */ { CLK_PCLK, 1042 }, + /* B1200 */ { CLK_PCLK, 520 }, + /* B1800 */ { CLK_PCLK, 390 }, + /* B2400 */ { CLK_PCLK, 260 }, + /* B4800 */ { CLK_PCLK, 130 }, + /* B9600 */ { CLK_PCLK, 64 }, + /* B19200 */ { CLK_PCLK, 32 }, + /* B38400 */ { CLK_PCLK, 16 }, + /* B57600 */ { CLK_PCLK, 8 }, + /* B115200 */ { CLK_PCLK, 4 }, + /* B230400 */ { CLK_PCLK, 2 }, /* #18 spd_shi */ + /* B460800 */ { CLK_PCLK, 1 } /* #19 spd_warp */ +}; +#endif + +#ifdef CONFIG_BVME6000_SCC + +/* This table is used if RTxC = 7.3728 MHz. This is the case for BVMs + */ +static BAUD_ENTRY bdtab_bvme[18] = { + /* B0 */ { 0, 0 }, + /* B50 */ { CLK_RTxC, 9216 }, + /* B75 */ { CLK_RTxC, 6144 }, + /* B110 */ { CLK_RTxC, 4188 }, + /* B134 */ { CLK_RTxC, 3424 }, + /* B150 */ { CLK_RTxC, 3072 }, + /* B200 */ { CLK_RTxC, 2304 }, + /* B300 */ { CLK_RTxC, 1536 }, + /* B600 */ { CLK_RTxC, 768 }, + /* B1200 */ { CLK_RTxC, 384 }, + /* B1800 */ { CLK_RTxC, 256 }, + /* B2400 */ { CLK_RTxC, 192 }, + /* B4800 */ { CLK_RTxC, 96 }, + /* B9600 */ { CLK_RTxC, 48 }, + /* B19200 */ { CLK_RTxC, 24 }, + /* B38400 */ { CLK_RTxC, 12 }, + /* B57600 */ { CLK_RTxC, 8 }, + /* B115200 */ { CLK_RTxC, 4 } +}; +#endif + + +/* User settable tables */ +static BAUD_ENTRY bdtab_usr[2][20]; + + +/* + Here are the values to compute the tables above. For each base + clock, the BRG values for the common bps rates are listed. The + divisor is (BRG+2)*2. For each clock, the 1:16 and 1:32 are also + usable (and the BRG isn't used). 1:64 is the same as BRG with + k==0. If more than clock source was possible for a bps rate I've + choosen the one with the smallest error. + + For 307.2 kHz == base 19200: + 50 bps -> 190 + 75 bps -> 126 + 110 bps -> 85 (really 110.34 bps, error 0.31 %) + 134 bps -> 70 (really 133.33 bps, error 0.49 %) + 150 bps -> 62 + 200 bps -> 46 + 300 bps -> 30 + 600 bps -> 14 + 1200 bps -> 6 + 1800 bps -> 3 (really 1920 bps, error 6.7 %) + 2400 bps -> 2 + 4800 bps -> 0 + + For 2.4576 MHz == base 153600: + 50 bps -> 1534 + 75 bps -> 1022 + 110 bps -> 696 (really 110.03 bps, error 0.027 %) + 134 bps -> 571 (really 134.03 bps, error 0.022 %) + 150 bps -> 510 + 200 bps -> 382 + 300 bps -> 254 + 600 bps -> 126 + 1200 bps -> 62 + 1800 bps -> 41 (really 1786.1 bps, error 0.77 %) + 2400 bps -> 30 + 4800 bps -> 14 + 9600 bps -> 6 + 19200 bps -> 2 + 38400 bps -> 0 + + For 3.672 MHz == base 229500: + 50 bps -> 2293 + 75 bps -> 1528 + 110 bps -> 1041 + 134 bps -> 854 + 150 bps -> 763 + 200 bps -> 572 + 300 bps -> 381 + 600 bps -> 189 + 1200 bps -> 94 + 1800 bps -> 62 + 2400 bps -> 46 + 4800 bps -> 22 + 9600 bps -> 10 + 19200 bps -> 4 + 38400 bps -> 1 + 57600 bps -> 0 + + For 8.053976 MHz == base 503374: + 0 bps -> 0 + 50 bps -> 5032 + 75 bps -> 3354 + 110 bps -> 2286 + 134 bps -> 1876 + 150 bps -> 1676 + 200 bps -> 1256 + 300 bps -> 837 + 600 bps -> 417 + 1200 bps -> 208 + 1800 bps -> 138 + 2400 bps -> 103 + 4800 bps -> 50 + 9600 bps -> 24 + 19200 bps -> 11 + 31500 bps -> 6 (really 31461 bps) + 50000 bps -> 3 + 125000 bps -> 0 + +*/ + + +/* Is channel A switchable between two hardware ports? (Serial2/LAN) */ + +#define SCCA_SWITCH_SERIAL2_ONLY 0 /* only connected to Serial2 */ +#define SCCA_SWITCH_LAN_ONLY 1 /* only connected to LAN */ +#define SCCA_SWITCH_BOTH 2 /* connected to both, switch by + * IO7 in the PSG */ + +static int SCC_chan_a_switchable; + +/* Is channel A (two ports!) already open? */ +static int SCC_chan_a_open; + +/* For which line has channel A been opened? */ +static int SCC_chan_a_line; + +/* info pointer for SCC_chan_a_line */ +static struct m68k_async_struct *SCC_chan_a_info; + +/* Are the register addresses for the channels reversed? (B before A). This is + * the case for the ST_ESCC. */ +static int ChannelsReversed; + +/* This macro sets up the 'info' pointer for the interrupt functions of + * channel A. It addresses the following problem: The isrs were registered + * with callback_data == &rs_table[3] (= Serial2). But they can also be for + * &rs_table[4] (LAN), if this port is the open one. SETUP_INFO() thus + * advances the pointer if info->line == 3. + */ + +#define DEFAULT_CHANNEL_B_LINE 1 /* ttyS1 */ +#define DEFAULT_CHANNEL_A232_LINE 3 /* ttyS3 */ +#define DEFAULT_CHANNEL_A422_LINE 4 /* ttyS4 */ + +static int chb_line = -1, cha232_line = -1, cha422_line = -1; + +#ifndef CONFIG_ATARI_SCC_DMA +#define scca_dma 0 /* No DMA support */ +#else +static int scca_dma = 0; /* whether DMA is supported at all */ + +/* ++TeSche: these next few things are for DMA support on channel A. both + * BUFFERS and BUFSIZE must be a power of two (because of speed reasons)! + */ +#define SCCA_DMA_BUFFERS 8 +#define SCCA_DMA_BUFSIZE 2048 +typedef struct { + u_char *buf, *pbuf, *err; + int inbuf; + short cntOver, cntPar, cntFrame; + unsigned active:1; /* whether a DMA transfer is using this buffer */ + unsigned needsFlushing:1; /* whether it's dirty (even when inbuf==0) */ +} DMABUF; +static DMABUF scca_dma_buf[SCCA_DMA_BUFFERS]; +static DMABUF *scca_dma_head, *scca_dma_tail; +static DMABUF *scca_dma_end = &scca_dma_buf[SCCA_DMA_BUFFERS]; + +#endif + +#define SETUP_INFO(info) \ + do { \ + if (info->line == cha232_line) \ + info = SCC_chan_a_info; \ + } while(0) + + +/***************************** Prototypes *****************************/ + +#ifdef ENABLE_ATARI_SCC +static void SCC_init_port( struct m68k_async_struct *info, int type, int channel ); +#endif +#ifdef CONFIG_MVME147_SCC +static void m147_init_port( struct m68k_async_struct *info, int type, int channel ); +#endif +#ifdef CONFIG_MVME162_SCC +static void mvme_init_port( struct m68k_async_struct *info, int type, int channel ); +#endif +#ifdef CONFIG_BVME6000_SCC +static void bvme_init_port( struct m68k_async_struct *info, int type, int channel ); +#endif +#ifdef MODULE +static void SCC_deinit_port( struct m68k_async_struct *info, int channel ); +#endif +static void SCC_rx_int (int irq, void *data, struct pt_regs *fp); +static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp); +static void SCC_tx_int (int irq, void *data, struct pt_regs *fp); +static void SCC_stat_int (int irq, void *data, struct pt_regs *fp); +#ifdef ENABLE_ATARI_SCC +static void SCC_ri_int (int irq, void *data, struct pt_regs *fp); +#endif +static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct + *tty, struct file *file ); +static void SCC_init( struct m68k_async_struct *info ); +static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr ); +static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag ); +static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base, + int divisor ); +static void SCC_change_speed( struct m68k_async_struct *info ); +static int SCC_clocksrc( unsigned baud_base, unsigned channel ); +static void SCC_throttle( struct m68k_async_struct *info, int status ); +static void SCC_set_break( struct m68k_async_struct *info, int break_flag ); +static void SCC_get_serial_info( struct m68k_async_struct *info, struct + serial_struct *retinfo ); +static unsigned int SCC_get_modem_info( struct m68k_async_struct *info ); +static int SCC_set_modem_info( struct m68k_async_struct *info, int new_dtr, int + new_rts ); +static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct + m68k_async_struct *info, unsigned int cmd, unsigned long + arg ); +static void SCC_stop_receive (struct m68k_async_struct *info); +static int SCC_trans_empty (struct m68k_async_struct *info); +#ifdef CONFIG_ATARI_SCC_DMA +static void SCC_timer_int (int irq, void *data, struct pt_regs *fp); +static void SCC_dma_int (int irq, void *data, struct pt_regs *fp); +#endif + +/************************* End of Prototypes **************************/ + + +static SERIALSWITCH SCC_switch = { + SCC_init, SCC_deinit, SCC_enab_tx_int, + SCC_check_custom_divisor, SCC_change_speed, + SCC_throttle, SCC_set_break, + SCC_get_serial_info, SCC_get_modem_info, + SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty, + SCC_check_open +}; + +extern int atari_SCC_init_done; +extern int atari_SCC_reset_done; + + +#ifdef CONFIG_BVME6000_SCC + +int bvme_SCC_init( void ) +{ + struct serial_struct req; + int nr = 0; + + if (!MACH_IS_BVME6000) + return (-ENODEV); + + scc_del = (unsigned char *)0; + + SCC_chan_a_switchable = SCCA_SWITCH_SERIAL2_ONLY; + SCC_PCLK = SCC_BAUD_BASE_BVME_PCLK; + + /* General initialization */ + ChannelsReversed = 8; + SCC_chan_a_open = 0; + + req.line = DEFAULT_CHANNEL_B_LINE; + req.type = SER_SCC_BVME; + req.port = BVME_SCC_B_ADDR; + if ((chb_line = register_serial( &req )) >= 0) { + bvme_init_port( &rs_table[chb_line], req.type, CHANNEL_B ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel B\n", req.line ); + + /* Init channel A, RS232 part (Serial2) */ + req.line = 0; + req.type = SER_SCC_BVME; + req.port = BVME_SCC_A_ADDR; + if ((cha232_line = register_serial( &req )) >= 0) { + bvme_init_port( &rs_table[cha232_line], req.type, CHANNEL_A ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line ); + + return( nr > 0 ? 0 : -ENODEV ); +} + + +static void bvme_init_port( struct m68k_async_struct *info, int type, int channel ) +{ + static int called = 0, ch_a_inited = 0; + SCC_ACCESS_INIT(info); + + info->sw = &SCC_switch; + + /* set ISRs, but don't enable interrupts yet (done in init()); + */ + if (channel == CHANNEL_B || !ch_a_inited) { + request_irq(channel ? BVME_IRQ_SCCB_TX : BVME_IRQ_SCCA_TX, + SCC_tx_int, BVME_IRQ_TYPE_PRIO, + channel ? "SCC-B TX" : "SCC-A TX", info); + request_irq(channel ? BVME_IRQ_SCCB_STAT : BVME_IRQ_SCCA_STAT, + SCC_stat_int, BVME_IRQ_TYPE_PRIO, + channel ? "SCC-B status" : "SCC-A status", info); + request_irq(channel ? BVME_IRQ_SCCB_RX : BVME_IRQ_SCCA_RX, + SCC_rx_int, BVME_IRQ_TYPE_PRIO, + channel ? "SCC-B RX" : "SCC-A RX", info); + request_irq(channel ? BVME_IRQ_SCCB_SPCOND : BVME_IRQ_SCCA_SPCOND, + SCC_spcond_int, BVME_IRQ_TYPE_PRIO, + channel ? "SCC-B special cond" : "SCC-A special cond", info); + + } + + /* Hardware initialization */ + + if (!called) { + /* Set the interrupt vector */ + SCCwrite( INT_VECTOR_REG, BVME_IRQ_SCC_BASE ); + + /* Interrupt parameters: vector includes status, status low */ + SCCwrite( MASTER_INT_CTRL, MIC_VEC_INCL_STAT ); + + /* Set the baud tables */ + SCC_baud_table[CHANNEL_A] = bdtab_bvme; + SCC_baud_table[CHANNEL_B] = bdtab_bvme; + + /* Set the clocks */ + SCC_clocks[CHANNEL_A][CLK_RTxC] = SCC_BAUD_BASE_BVME; + SCC_clocks[CHANNEL_A][CLK_TRxC] = SCC_BAUD_BASE_NONE; + SCC_clocks[CHANNEL_B][CLK_RTxC] = SCC_BAUD_BASE_BVME; + SCC_clocks[CHANNEL_B][CLK_TRxC] = SCC_BAUD_BASE_NONE; + + SCCmod( MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB ); + } + + /* disable interrupts for this channel */ + SCCwrite( INT_AND_DMA_REG, 0 ); + + called = 1; + if (CHANNR(info) == CHANNEL_A) ch_a_inited = 1; +} + +#endif + + +#ifdef CONFIG_MVME147_SCC + +int m147_SCC_init( void ) +{ + struct serial_struct req; + int nr = 0; + + if (!MACH_IS_MVME147) + return (-ENODEV); + + scc_del = (unsigned char *)0; + + SCC_chan_a_switchable = SCCA_SWITCH_SERIAL2_ONLY; + SCC_PCLK = SCC_BAUD_BASE_M147_PCLK; + + /* General initialization */ + ChannelsReversed = 2; + SCC_chan_a_open = 0; + + req.line = DEFAULT_CHANNEL_B_LINE; + req.type = SER_SCC_MVME; + req.port = M147_SCC_B_ADDR; + if ((chb_line = register_serial( &req )) >= 0) { + m147_init_port( &rs_table[chb_line], req.type, CHANNEL_B ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel B\n", req.line ); + + /* Init channel A, RS232 part (Serial2) */ + req.line = 0; + req.type = SER_SCC_MVME; + req.port = M147_SCC_A_ADDR; + if ((cha232_line = register_serial( &req )) >= 0) { + m147_init_port( &rs_table[cha232_line], req.type, CHANNEL_A ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line ); + /* + * Ensure interrupts are enabled in the PCC chip + */ + m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB; + + return( nr > 0 ? 0 : -ENODEV ); +} + + +static void m147_init_port( struct m68k_async_struct *info, int type, int channel ) +{ + static int called = 0, ch_a_inited = 0; + SCC_ACCESS_INIT(info); + + info->sw = &SCC_switch; + + /* set ISRs, but don't enable interrupts yet (done in init()); + */ + if (channel == CHANNEL_B || !ch_a_inited) { + request_irq(channel ? MVME147_IRQ_SCCB_TX : MVME147_IRQ_SCCA_TX, + SCC_tx_int, MVME147_IRQ_TYPE_PRIO, + channel ? "SCC-B TX" : "SCC-A TX", info); + request_irq(channel ? MVME147_IRQ_SCCB_STAT : MVME147_IRQ_SCCA_STAT, + SCC_stat_int, MVME147_IRQ_TYPE_PRIO, + channel ? "SCC-B status" : "SCC-A status", info); + request_irq(channel ? MVME147_IRQ_SCCB_RX : MVME147_IRQ_SCCA_RX, + SCC_rx_int, MVME147_IRQ_TYPE_PRIO, + channel ? "SCC-B RX" : "SCC-A RX", info); + request_irq(channel ? MVME147_IRQ_SCCB_SPCOND : MVME147_IRQ_SCCA_SPCOND, + SCC_spcond_int, MVME147_IRQ_TYPE_PRIO, + channel ? "SCC-B special cond" : "SCC-A special cond", info); + + } + + /* Hardware initialization */ + + if (!called) { + /* Set the interrupt vector */ + SCCwrite( INT_VECTOR_REG, MVME147_IRQ_SCC_BASE ); + + /* Interrupt parameters: vector includes status, status low */ + SCCwrite( MASTER_INT_CTRL, MIC_VEC_INCL_STAT ); + + /* Set the baud tables */ + SCC_baud_table[CHANNEL_A] = bdtab_m147; + SCC_baud_table[CHANNEL_B] = bdtab_m147; + + /* Set the clocks */ + SCC_clocks[CHANNEL_A][CLK_RTxC] = SCC_BAUD_BASE_M147; + SCC_clocks[CHANNEL_A][CLK_TRxC] = SCC_BAUD_BASE_NONE; + SCC_clocks[CHANNEL_B][CLK_RTxC] = SCC_BAUD_BASE_M147; + SCC_clocks[CHANNEL_B][CLK_TRxC] = SCC_BAUD_BASE_NONE; + + SCCmod( MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB ); + } + + /* disable interrupts for this channel */ + SCCwrite( INT_AND_DMA_REG, 0 ); + + called = 1; + if (CHANNR(info) == CHANNEL_A) ch_a_inited = 1; +} + +#endif + +#ifdef CONFIG_MVME162_SCC + +int mvme_SCC_init( void ) +{ + struct serial_struct req; + int nr = 0; + + if (!MACH_IS_MVME16x || !(mvme16x_config & MVME16x_CONFIG_GOT_SCCA)) + return (-ENODEV); + + scc_del = (unsigned char *)0; + + SCC_chan_a_switchable = SCCA_SWITCH_SERIAL2_ONLY; + SCC_PCLK = SCC_BAUD_BASE_MVME_PCLK; + + /* General initialization */ + ChannelsReversed = 4; + SCC_chan_a_open = 0; + + req.line = DEFAULT_CHANNEL_B_LINE; + req.type = SER_SCC_MVME; + req.port = MVME_SCC_B_ADDR; + if ((chb_line = register_serial( &req )) >= 0) { + mvme_init_port( &rs_table[chb_line], req.type, CHANNEL_B ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel B\n", req.line ); + + /* Init channel A, RS232 part (Serial2) */ + req.line = 0; + req.type = SER_SCC_MVME; + req.port = MVME_SCC_A_ADDR; + if ((cha232_line = register_serial( &req )) >= 0) { + mvme_init_port( &rs_table[cha232_line], req.type, CHANNEL_A ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line ); + /* + * Ensure interrupts are enabled in the MC2 chip + */ + *(volatile char *)0xfff4201d = 0x14; + + return( nr > 0 ? 0 : -ENODEV ); +} + + +static void mvme_init_port( struct m68k_async_struct *info, int type, int channel ) +{ + static int called = 0, ch_a_inited = 0; + SCC_ACCESS_INIT(info); + + info->sw = &SCC_switch; + + /* set ISRs, but don't enable interrupts yet (done in init()); + */ + if (channel == CHANNEL_B || !ch_a_inited) { + request_irq(channel ? MVME162_IRQ_SCCB_TX : MVME162_IRQ_SCCA_TX, + SCC_tx_int, MVME162_IRQ_TYPE_PRIO, + channel ? "SCC-B TX" : "SCC-A TX", info); + request_irq(channel ? MVME162_IRQ_SCCB_STAT : MVME162_IRQ_SCCA_STAT, + SCC_stat_int, MVME162_IRQ_TYPE_PRIO, + channel ? "SCC-B status" : "SCC-A status", info); + request_irq(channel ? MVME162_IRQ_SCCB_RX : MVME162_IRQ_SCCA_RX, + SCC_rx_int, MVME162_IRQ_TYPE_PRIO, + channel ? "SCC-B RX" : "SCC-A RX", info); + request_irq(channel ? MVME162_IRQ_SCCB_SPCOND : MVME162_IRQ_SCCA_SPCOND, + SCC_spcond_int, MVME162_IRQ_TYPE_PRIO, + channel ? "SCC-B special cond" : "SCC-A special cond", info); + + } + + /* Hardware initialization */ + + if (!called) { + /* Set the interrupt vector */ + SCCwrite( INT_VECTOR_REG, MVME162_IRQ_SCC_BASE ); + + /* Interrupt parameters: vector includes status, status low */ + SCCwrite( MASTER_INT_CTRL, MIC_VEC_INCL_STAT ); + + /* Set the baud tables */ + SCC_baud_table[CHANNEL_A] = bdtab_mvme; + SCC_baud_table[CHANNEL_B] = bdtab_mvme; + + /* Set the clocks */ + SCC_clocks[CHANNEL_A][CLK_RTxC] = SCC_BAUD_BASE_MVME; + SCC_clocks[CHANNEL_A][CLK_TRxC] = SCC_BAUD_BASE_NONE; + SCC_clocks[CHANNEL_B][CLK_RTxC] = SCC_BAUD_BASE_MVME; + SCC_clocks[CHANNEL_B][CLK_TRxC] = SCC_BAUD_BASE_NONE; + + SCCmod( MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB ); + } + + /* disable interrupts for this channel */ + SCCwrite( INT_AND_DMA_REG, 0 ); + + called = 1; + if (CHANNR(info) == CHANNEL_A) ch_a_inited = 1; +} + +#endif + +#ifdef ENABLE_ATARI_SCC + +int atari_SCC_init( void ) +{ + struct serial_struct req; + int escc = ATARIHW_PRESENT(ST_ESCC); + int nr = 0; + extern char m68k_debug_device[]; + + /* SCC present at all? */ + if (!(ATARIHW_PRESENT(SCC) || ATARIHW_PRESENT(ST_ESCC))) + return( -ENODEV ); + + scc_del = &mfp.par_dt_reg; + +#ifdef CONFIG_ATARI_SCC_DMA + /* strengthen the condition a bit to be on the safer side... + */ + scca_dma = ATARIHW_PRESENT(SCC_DMA) && ATARIHW_PRESENT (TT_MFP); +#endif + + /* Channel A is switchable on the TT, MegaSTE and Medusa (extension), i.e. + * all machines with an SCC except the Falcon. If there's a machine where + * channel A is fixed to a RS-232 Serial2, add code to set to + * SCCA_SWITCH_SERIAL2_ONLY. + */ + if (MACH_IS_FALCON) + SCC_chan_a_switchable = SCCA_SWITCH_LAN_ONLY; + else if (ATARIHW_PRESENT(TT_MFP) || MACH_IS_MSTE) + SCC_chan_a_switchable = SCCA_SWITCH_BOTH; + else + SCC_chan_a_switchable = SCCA_SWITCH_SERIAL2_ONLY; + + /* General initialization */ + ChannelsReversed = escc ? 4 : 0; + SCC_chan_a_open = 0; + + /* Init channel B */ + if (!strcmp( m68k_debug_device, "ser2" )) + printk(KERN_NOTICE "SCC channel B: used as debug device\n" ); + else { + req.line = DEFAULT_CHANNEL_B_LINE; + req.type = SER_SCC_NORM; + req.port = (int)(escc ? &st_escc.cha_b_ctrl : &scc.cha_b_ctrl); + if ((chb_line = register_serial( &req )) >= 0) { + SCC_init_port( &rs_table[chb_line], req.type, CHANNEL_B ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel B\n", req.line ); + } + + /* Init channel A, RS232 part (Serial2) */ + if (SCC_chan_a_switchable != SCCA_SWITCH_LAN_ONLY) { + req.line = DEFAULT_CHANNEL_A232_LINE; + req.type = scca_dma ? SER_SCC_DMA : SER_SCC_NORM; + req.port = (int)(escc ? &st_escc.cha_a_ctrl : &scc.cha_a_ctrl); + if ((cha232_line = register_serial( &req )) >= 0) { + SCC_init_port( &rs_table[cha232_line], req.type, CHANNEL_A ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line ); + } + + /* Init channel A, RS422 part (LAN) */ + if (SCC_chan_a_switchable != SCCA_SWITCH_SERIAL2_ONLY) { + req.line = DEFAULT_CHANNEL_A422_LINE; + req.type = scca_dma ? SER_SCC_DMA : SER_SCC_NORM; + req.port = (int)(escc ? &st_escc.cha_a_ctrl : &scc.cha_a_ctrl); + if ((cha422_line = register_serial( &req )) >= 0) { + SCC_init_port( &rs_table[cha422_line], req.type, CHANNEL_A ); + ++nr; + } + else + printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line ); + } + + return( nr > 0 ? 0 : -ENODEV ); +} + + +static void SCC_init_port( struct m68k_async_struct *info, int type, int channel ) +{ + static int called = 0, ch_a_inited = 0; + SCC_ACCESS_INIT(info); + + info->sw = &SCC_switch; + + /* set ISRs, but don't enable interrupts yet (done in init()); + * All interrupts are of type PRIORITIZED, which means they can be + * interrupted by all level 6 ints, but not by another SCC (or other level + * 5) int. I see no races with any MFP int, but I'm not quite sure yet + * whether longer delays in between the two-stage SCC register access can + * break things... + */ + if (channel == CHANNEL_B || !ch_a_inited) { + request_irq(channel ? IRQ_SCCB_TX : IRQ_SCCA_TX, + SCC_tx_int, IRQ_TYPE_PRIO, + channel ? "SCC-B TX" : "SCC-A TX", info); + request_irq(channel ? IRQ_SCCB_STAT : IRQ_SCCA_STAT, + SCC_stat_int, IRQ_TYPE_PRIO, + channel ? "SCC-B status" : "SCC-A status", info); + request_irq(channel ? IRQ_SCCB_RX : IRQ_SCCA_RX, + SCC_rx_int, IRQ_TYPE_PRIO, + channel ? "SCC-B RX" : "SCC-A RX", info); + request_irq(channel ? IRQ_SCCB_SPCOND : IRQ_SCCA_SPCOND, + SCC_spcond_int, IRQ_TYPE_PRIO, + channel ? "SCC-B special cond" : "SCC-A special cond", info); + + if (channel != 0 && ATARIHW_PRESENT (TT_MFP)) + request_irq(IRQ_TT_MFP_RI, SCC_ri_int, IRQ_TYPE_SLOW, + "TT-MFP ring indicator (modem 2)", info); + +#ifdef CONFIG_ATARI_SCC_DMA + if (channel == CHANNEL_A && !ch_a_inited && type == SER_SCC_DMA && scca_dma) { + + int i, size = SCCA_DMA_BUFFERS * SCCA_DMA_BUFSIZE; + + if (!(scca_dma_buf[0].err = kmalloc (size, GFP_KERNEL))) { + printk ("SCC-A: Cannot allocate buffers, DMA support disabled\n"); + scca_dma = 0; + } + + if (scca_dma) { + size = (size + PAGE_SIZE - 1) >> 12; + if (!(scca_dma_buf[0].buf = (u_char *)__get_dma_pages (GFP_KERNEL, size))) { + printk ("SCC-A: Cannot allocate buffers, DMA support disabled\n"); + kfree (scca_dma_buf[0].err); + scca_dma = 0; + } + } + + if (scca_dma) + if (tt_mfp.int_en_a & tt_mfp.int_mk_a & 0x20) { + printk ("SCC-A: TT_MFP Timer A already in use, DMA support disabled\n"); + free_pages ((unsigned long)scca_dma_buf[0].buf, size); + kfree (scca_dma_buf[0].err); + scca_dma = 0; + } + + if (scca_dma) { + + printk ("SCC-A: using %d buffers a %d bytes for DMA\n", SCCA_DMA_BUFFERS, SCCA_DMA_BUFSIZE); + + size = SCCA_DMA_BUFSIZE; + for (i=1; i> 12); + kfree (scca_dma_buf[0].err); + } +#endif + } +#endif +#ifdef CONFIG_MVME147 + if (MACH_IS_MVME147) { + free_irq(channel ? MVME147_IRQ_SCCB_TX : MVME147_IRQ_SCCA_TX, info); + free_irq(channel ? MVME147_IRQ_SCCB_STAT : MVME147_IRQ_SCCA_STAT, info); + free_irq(channel ? MVME147_IRQ_SCCB_RX : MVME147_IRQ_SCCA_RX, info); + free_irq(channel ? MVME147_IRQ_SCCB_SPCOND : MVME147_IRQ_SCCA_SPCOND, + info); + } +#endif +#ifdef CONFIG_MVME16x + if (MACH_IS_MVME16x) { + free_irq(channel ? MVME162_IRQ_SCCB_TX : MVME162_IRQ_SCCA_TX, info); + free_irq(channel ? MVME162_IRQ_SCCB_STAT : MVME162_IRQ_SCCA_STAT, info); + free_irq(channel ? MVME162_IRQ_SCCB_RX : MVME162_IRQ_SCCA_RX, info); + free_irq(channel ? MVME162_IRQ_SCCB_SPCOND : MVME162_IRQ_SCCA_SPCOND, + info); + } +#endif +#ifdef CONFIG_BVME6000 + if (MACH_IS_BVME6000) { + free_irq(channel ? BVME_IRQ_SCCB_TX : BVME_IRQ_SCCA_TX, info); + free_irq(channel ? BVME_IRQ_SCCB_STAT : BVME_IRQ_SCCA_STAT, info); + free_irq(channel ? BVME_IRQ_SCCB_RX : BVME_IRQ_SCCA_RX, info); + free_irq(channel ? BVME_IRQ_SCCB_SPCOND : BVME_IRQ_SCCA_SPCOND, + info); + } +#endif +} +#endif + + +#ifdef CONFIG_ATARI_SCC_DMA + +/*****************************************************************************/ + +/* + * TeSche's high-speed debugging helpers. it has proven (not only at this + * place) that ordinary printk()s cause much more problems than they solve when + * debugging interrupt handlers. these ones are not nice, but fast. + */ + +#if DEBUG & DEBUG_DMA + +#define DEBUGBUFSIZE 1024 +static char debugBuf[DEBUGBUFSIZE]; +static char *debugPtr = &debugBuf[0]; +static char *debugEndPtr = &debugBuf[DEBUGBUFSIZE-1]; + +static inline void debugString (char *s) +{ + while (*s && (debugPtr != debugEndPtr)) + *debugPtr++ = *s++; +} + +static inline void debugInt (int i) +{ + char *tmp = "0123456789"; /* maxint (unsigned) = 4294967296, 10 digits */ + short cnt = 10; + + while (--cnt > 0) { + tmp[cnt] = '0' + (i % 10); + i /= 10; + } + + while (*tmp == '0') + tmp++; + + while (*tmp && (debugPtr != debugEndPtr)) + *debugPtr++ = *tmp++; +} + +static char int2hex[] = "0123456789abcdef"; + +static inline void debugHex (unsigned int h) +{ + char *tmp = "01234567"; + short cnt = 8; + + while (--cnt > 0) { + tmp[cnt] = int2hex[h & 15]; + h >>= 4; + } + + while (*tmp == '0') + tmp++; + + while (*tmp && (debugPtr != debugEndPtr)) + *debugPtr++ = *tmp++; +} + +static inline void debugFlush (void) +{ + if (debugPtr != &debugBuf[0]) { + *debugPtr = 0; + printk ("%s\n", debugBuf); + debugPtr = &debugBuf[0]; + } +} + +#endif /* DEBUG & DEBUG_DMA */ + + +/*****************************************************************************/ + +/* + * these functions are for DMA support. they all assume that they're called + * with INTs off so that they can play with their data structures undisturbed. + */ + +static ulong dmaStartAddr = 0; /* 0 means DMA not running */ +static ulong dmaSize; + + +/* start DMA on current (scca_head) write buffer + */ +static inline void dma_start (void) +{ + if ((dmaSize = SCCA_DMA_BUFSIZE - scca_dma_head->inbuf) > 0) { + dmaStartAddr = (ulong)(scca_dma_head->pbuf + scca_dma_head->inbuf); /* needs no virt_to_phys() */ +#if DEBUG & DEBUG_DMA + debugString ("[start@0x"); + debugHex (dmaStartAddr & 0xffff); + debugString ("/"); + debugInt (dmaSize); + debugString ("] "); +#endif + tt_scc_dma.dma_ctrl &= ~3; + __asm__ __volatile__ ("movep.l %0,%1@(0)\n\t" + "movep.l %2,%3@(0)\n\t" + : /* no outputs */ + : "d"(dmaStartAddr), "a"(&tt_scc_dma.dma_addr_hi), + "d"(dmaSize), "a"(&tt_scc_dma.dma_cnt_hi) + : "memory"); + tt_scc_dma.dma_ctrl |= 2; + } else { + dmaStartAddr = 0; + } +} + + +/* stop DMA, read restbytes and adjust buffer counters + */ +static inline void dma_stop (void) +{ + register short rest; + ulong size = 0, endaddr; + unsigned char *from = (unsigned char *)&tt_scc_dma.dma_restdata, *to; + + if (!dmaStartAddr) + return; + + tt_scc_dma.dma_ctrl &= ~3; /* stop DMA */ + + /* ++TeSche: I've had tremendous problems with looking at dma_addr to see + * how many bytes were received rather than looking at dma_cnt. To me it + * looks like there are cases when dma_addr is not properly updated when + * DMA is aborted, so I ended up with calculating less bytes than actually + * were received. Dma_cnt seems to be ok for me, so this is the way I go. + * + * sigh, yet one more unspecified hardware feature? is it at all anywhere + * specified what happens when a DMA is aborted before it ends? + */ + __asm__ __volatile__ ("movep.l %1@(0),%0\n\t" + : "=d"(size) + : "a"(&tt_scc_dma.dma_cnt_hi) + : "memory"); + size = dmaSize - size; + +#if DEBUG & DEBUG_DMA + __asm__ __volatile__ ("movep.l %1@(0),%0\n\t" + : "=d"(endaddr) + : "a"(&tt_scc_dma.dma_addr_hi) + : "memory"); + if (endaddr - dmaStartAddr != size) { + debugString ("[size="); + debugInt (size); + debugString (",addr="); + debugInt (endaddr-dmaStartAddr); + debugString ("] "); + } +#endif + + endaddr = dmaStartAddr + size; + + if ((dmaStartAddr & ~3) != (endaddr & ~3)) { + /* at least one long was written. lower two bits of endaddress are + * number of restbytes. write them left-justified to the long the + * endaddress is in. + */ + rest = endaddr & 3; + to = scca_dma_head->buf + (endaddr & (SCCA_DMA_BUFSIZE-1) & ~3); /* needs no PTOV */ + } else { + /* no long written. number of restbytes is endaddress - + * startaddress. write them to the startaddress. + */ + rest = size; /* must and will be 0..3 */ + from += dmaStartAddr & 3; + to = scca_dma_head->buf + (dmaStartAddr & (SCCA_DMA_BUFSIZE-1)); /* needs no PTOV */ + } + +#if DEBUG & DEBUG_DMA + debugString ("[stop@0x"); + debugHex (endaddr & 0xffff); + debugString ("/"); + debugInt (size); + if (rest) { + debugString (",rest="); + debugInt (rest); + debugString ("@0x"); + debugHex ((unsigned int)from); + debugString ("->"); + debugHex (((unsigned int)to) & 0xffff); + } + debugString ("] "); +#endif + + while (--rest >= 0) + *to++ = *from++; + + scca_dma_head->inbuf += size; +} + + +/* used by the SPCOND INT handler to deliver error codes. it's not very clean, + * maybe overwrites older values, but since that only happens when something + * has already gone wrong I don't consider this a problem. + */ +static inline void dma_fake_receive (u_char data, u_char err) +{ + scca_dma_head->buf[scca_dma_head->inbuf] = data; + scca_dma_head->err[scca_dma_head->inbuf] = err; + + if (scca_dma_head->inbuf < SCCA_DMA_BUFSIZE-1) + scca_dma_head->inbuf++; + + switch (err) { + case TTY_OVERRUN: + scca_dma_head->cntOver++; + break; + case TTY_PARITY: + scca_dma_head->cntPar++; + break; + case TTY_FRAME: + scca_dma_head->cntFrame++; + } +} + + +/*****************************************************************************/ + +/* + * these functions are for high-level DMA support. they make no assumptions + * about current INT status when called. + */ + +/* can't be called more than once due to tqueue handling + clever (?:) variable + * design -> no cli/sti. + */ +static void SCC_flush (struct tty_struct *tty) +{ + int loops = 0; + static int highWater = (95 * SCCA_DMA_BUFSIZE) / 100; + + /* a potential endless loop, but that's *really* unlikely... + */ + while (scca_dma_tail->needsFlushing) { + + /* ...anyway, be save + */ + if (++loops > SCCA_DMA_BUFFERS) { + printk ("SCC-A: flush loop overrun\n"); + break; + } + +#if DEBUG & DEBUG_DMA + if (scca_dma_tail->cntOver || scca_dma_tail->cntPar || scca_dma_tail->cntFrame) { + debugString ("[ovr="); + debugInt (scca_dma_tail->cntOver); + debugString (",par="); + debugInt (scca_dma_tail->cntPar); + debugString (",frm="); + debugInt (scca_dma_tail->cntFrame); + debugString ("] "); + } +#else + if (scca_dma_tail->cntOver || scca_dma_tail->cntPar || scca_dma_tail->cntFrame) + printk ("SCC-A: %d overrun, %d parity, %d frame errors\n", + scca_dma_tail->cntOver, scca_dma_tail->cntPar, scca_dma_tail->cntFrame); +#endif + + if (scca_dma_tail->inbuf > highWater) + printk ("SCC-A: warning: buffer usage: %d/%d chars\n", scca_dma_tail->inbuf, SCCA_DMA_BUFSIZE); + +#if 0 + if (scca_dma_tail->inbuf > 1) { + scca_dma_tail->buf[0] |= 0x1; + scca_dma_tail->buf[scca_dma_tail->inbuf-1] |= 0x2; + } +#endif + + tty->ldisc.receive_buf (tty, scca_dma_tail->buf, scca_dma_tail->err, scca_dma_tail->inbuf); + + scca_dma_tail->cntOver = 0; + scca_dma_tail->cntPar = 0; + scca_dma_tail->cntFrame = 0; + scca_dma_tail->inbuf = 0; + scca_dma_tail->needsFlushing = 0; + + if (++scca_dma_tail == scca_dma_end) + scca_dma_tail = scca_dma_buf; + } + +#if DEBUG & DEBUG_DMA + debugFlush (); +#endif +} + + +static struct tq_struct SCC_flush_tqueue = { + NULL, /* next */ + 0, /* sync */ + (void (*)(void*)) SCC_flush, /* routine, must have (void *) arg... */ + NULL /* data */ +}; + + +/* the 48Hz timer to flush data. runs in fact only every 4th call, say at 12Hz. + */ +static void SCC_timer_int (int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + static int delay = 4; + ulong flags; + SCC_ACCESS_INIT(info); + + /* if 'fp' is NULL we're called from SCC_dma_int, in which case we must + * respond immediately! + */ + if (fp && --delay > 0) + return; + +#if DEBUG & DEBUG_DMA + delay = 100; /* 0.48Hz for better debugging, no more than 19k2b! */ +#else + delay = 4; /* 12Hz delivery frequency (960 bytes / delivery @ 115k2b) */ +#endif + + if (!SCC_flush_tqueue.data) + return; /* no program listening... */ + + save_flags (flags); + cli (); + + if (scca_dma_head->active) { + SCCmod (INT_AND_DMA_REG, ~(IDR_RX_INT_MASK|IDR_WAITREQ_ENAB), 0x00); + dma_stop (); + scca_dma_head->needsFlushing = 1; + scca_dma_head->active = 0; + if (++scca_dma_head == scca_dma_end) + scca_dma_head = scca_dma_buf; + } + + if (!scca_dma_head->needsFlushing) { + scca_dma_head->active = 1; + dma_start (); + SCCmod (INT_AND_DMA_REG, 0xff, IDR_RX_INT_SPCOND|IDR_WAITREQ_ENAB); + /* this must *happen* after re-starting DMA for speed reasons. + */ + memset (scca_dma_head->err, 0x00, SCCA_DMA_BUFSIZE); + } else { + printk ("SCC-A: fatal buffer overflow, data lost!\n"); + } + + queue_task (&SCC_flush_tqueue, &tq_immediate); + mark_bh (IMMEDIATE_BH); + + restore_flags (flags); +} + + +/* DMA finished before timer occured? + */ +static void SCC_dma_int (int irq, void *data, struct pt_regs *fp) +{ + printk ("SCC-A: DMA-INT occured, data lost!\n"); +#if 0 + /* is there any reason why we should call this? if the timer INT was + * delayed so long that this happened then this INT was delayed too, so + * it's already too late. + */ + SCC_timer_int (irq, (struct m68k_async_struct *)data, NULL); +#endif +} + +/*****************************************************************************/ + +#endif + + +#if DEBUG & DEBUG_OVERRUNS +static int SCC_ch_cnt[2] = { 0, 0 }, SCC_ch_ovrrun[2] = { 0, 0 }; +#endif + +static void SCC_rx_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + unsigned char ch; + SCC_ACCESS_INIT(info); + + SETUP_INFO(info); + + ch = SCCread_NB( RX_DATA_REG ); +#if DEBUG & DEBUG_INT + printk( "SCC ch %d rx int: char %02x\n", CHANNR(info), ch ); +#endif + rs_receive_char (info, ch, 0); +#if DEBUG & DEBUG_OVERRUNS + { int channel = CHANNR(info); + if (++SCC_ch_cnt[channel] == 10000) { + printk( "SCC ch. %d: overrun rate %d.%02d\n", channel, + SCC_ch_ovrrun[channel] / 100, + SCC_ch_ovrrun[channel] % 100 ); + SCC_ch_cnt[channel] = SCC_ch_ovrrun[channel] = 0; + } + } +#endif + + /* Check if another character is already ready; in that case, the + * spcond_int() function must be used, because this character may have an + * error condition that isn't signalled by the interrupt vector used! + */ + if (SCCread( INT_PENDING_REG ) & + (CHANNR(info) == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { + SCC_spcond_int (0, info, 0); + return; + } + +#ifndef ATARI_USE_SOFTWARE_EOI + SCCwrite_NB( COMMAND_REG, CR_HIGHEST_IUS_RESET ); +#endif +} + + +static void SCC_spcond_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + unsigned char stat, ch, err; + int int_pending_mask = CHANNR(info) == CHANNEL_A ? + IPR_A_RX : IPR_B_RX; +#ifdef CONFIG_ATARI_SCC_DMA + int isdma = (CHANNR(info) == CHANNEL_A) && scca_dma; + ulong flags = 0; +#endif + SCC_ACCESS_INIT(info); + + SETUP_INFO(info); + +#ifdef CONFIG_ATARI_SCC_DMA + if (isdma) { + save_flags (flags); + cli (); + SCCmod (INT_AND_DMA_REG, ~(IDR_RX_INT_MASK|IDR_WAITREQ_ENAB), 0); + dma_stop (); + } +#endif + + do { + stat = SCCread( SPCOND_STATUS_REG ); + ch = SCCread_NB(RX_DATA_REG); +#if DEBUG & DEBUG_INT + printk( "SCC ch %d spcond int: char %02x stat %02x\n", + CHANNR(info), ch, stat ); +#endif + + if (stat & SCSR_RX_OVERRUN) + err = TTY_OVERRUN; + else if (stat & SCSR_PARITY_ERR) + err = TTY_PARITY; + else if (stat & SCSR_CRC_FRAME_ERR) + err = TTY_FRAME; + else + err = 0; + +#ifdef CONFIG_ATARI_SCC_DMA + if (isdma) + dma_fake_receive (ch, err); + else +#endif + rs_receive_char (info, ch, err); + + /* ++TeSche: *All* errors have to be cleared manually, + * else the condition persists for the next chars + */ + if (err) + SCCwrite(COMMAND_REG, CR_ERROR_RESET); + +#if DEBUG & DEBUG_OVERRUNS + { int channel = CHANNR(info); + if (err == TTY_OVERRUN) SCC_ch_ovrrun[channel]++; + if (++SCC_ch_cnt[channel] == 10000) { + printk( "SCC ch. %d: overrun rate %d.%02d %%\n", channel, + SCC_ch_ovrrun[channel] / 100, + SCC_ch_ovrrun[channel] % 100 ); + SCC_ch_cnt[channel] = SCC_ch_ovrrun[channel] = 0; + } + } +#endif + + } while( SCCread( INT_PENDING_REG ) & int_pending_mask ); + +#ifdef CONFIG_ATARI_SCC_DMA + if (isdma) { + dma_start (); + SCCmod (INT_AND_DMA_REG, 0xff, IDR_RX_INT_SPCOND|IDR_WAITREQ_ENAB); + restore_flags (flags); + } +#endif + +#ifndef ATARI_USE_SOFTWARE_EOI + SCCwrite_NB( COMMAND_REG, CR_HIGHEST_IUS_RESET ); +#endif +} + + +#ifdef ENABLE_ATARI_SCC +static void SCC_ri_int(int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + /* update input line counter */ + info->icount.rng++; + wake_up_interruptible(&info->delta_msr_wait); +} +#endif + + +static void SCC_tx_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + int ch; + SCC_ACCESS_INIT(info); + + SETUP_INFO(info); + + while( (SCCread_NB( STATUS_REG ) & SR_TX_BUF_EMPTY) && + (ch = rs_get_tx_char( info )) >= 0 ) { + SCCwrite( TX_DATA_REG, ch ); +#if DEBUG & DEBUG_INT + printk( "SCC ch. %d tx int: sent char %02x\n", CHANNR(info), ch ); +#endif + } + + if (rs_no_more_tx( info )) { + /* disable tx interrupts */ + SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); + SCCwrite( COMMAND_REG, CR_TX_PENDING_RESET ); /* disable tx_int on next tx underrun? */ +#if DEBUG & DEBUG_INT + printk ("SCC ch %d tx int: no more chars after %d sent\n", + CHANNR (info), total); +#endif + } + +#ifndef ATARI_USE_SOFTWARE_EOI + SCCwrite_NB( COMMAND_REG, CR_HIGHEST_IUS_RESET ); +#endif +} + + +static void SCC_stat_int( int irq, void *data, struct pt_regs *fp) +{ + struct m68k_async_struct *info = data; + unsigned channel = CHANNR(info); + unsigned char last_sr, sr, changed; + SCC_ACCESS_INIT(info); + + SETUP_INFO(info); + + last_sr = SCC_last_status_reg[channel]; + sr = SCC_last_status_reg[channel] = SCCread_NB( STATUS_REG ); + changed = last_sr ^ sr; +#if DEBUG & DEBUG_INT + printk( "SCC ch %d stat int: sr=%02x last_sr=%02x\n", + CHANNR(info), sr, last_sr ); +#endif + + if (changed & SR_DCD) + rs_dcd_changed( info, sr & SR_DCD ); + + if (changed & SR_CTS) { +#if DEBUG & DEBUG_THROTTLE + printk( "SCC ch. %d: now CTS=%d\n", CHANNR(info), !!(sr & SR_CTS) ); +#endif + rs_check_cts( info, sr & SR_CTS ); + } + + if (changed & SR_SYNC_ABORT) { /* Data Set Ready */ + /* update input line counter */ + info->icount.dsr++; + wake_up_interruptible(&info->delta_msr_wait); + } + + SCCwrite( COMMAND_REG, CR_EXTSTAT_RESET ); +#ifndef ATARI_USE_SOFTWARE_EOI + SCCwrite_NB( COMMAND_REG, CR_HIGHEST_IUS_RESET ); +#endif +} + + +static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty, + struct file *file ) +{ + /* If channel A is opened, check if one of the compounded ports (ttyS3 and + * ttyS4) is already open, else activate the appropriate port hardware. + */ + +#if DEBUG & DEBUG_OPEN + printk( "SCC: about to open channel %d as line %d\n", + CHANNR(info), info->line ); +#endif + + if (CHANNR(info) == CHANNEL_A) { + + if (SCC_chan_a_open) { + if (SCC_chan_a_line != info->line) { +#if DEBUG & DEBUG_OPEN + printk("SCC: channel 0 was already open\n"); +#endif + return -EBUSY; + } + else + return 0; + } + + if ((info->line == cha232_line && + SCC_chan_a_switchable == SCCA_SWITCH_LAN_ONLY) || + (info->line == cha422_line && + SCC_chan_a_switchable == SCCA_SWITCH_SERIAL2_ONLY)) + return( -ENODEV ); + + SCC_chan_a_open = 1; + SCC_chan_a_line = info->line; + SCC_chan_a_info = &rs_table[info->line]; +#ifdef ENABLE_ATARI_SCC + if (SCC_chan_a_switchable == SCCA_SWITCH_BOTH) { + unsigned long flags; + unsigned char tmp; + + save_flags(flags); + cli(); + sound_ym.rd_data_reg_sel = 14; + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = (info->line == cha232_line + ? tmp | 0x80 + : tmp & 0x7f); +#if DEBUG & DEBUG_OPEN + printk( "SCC: set PSG IO7 to %02x (was %02x)\n", + (info->line & 1) ? (tmp | 0x80) : (tmp & 0x7f), + tmp ); +#endif + restore_flags(flags); + } +#endif + } + return( 0 ); +} + + +static void SCC_init( struct m68k_async_struct *info ) +{ + int i, channel = CHANNR(info); + unsigned long flags; + SCC_ACCESS_INIT(info); +#ifdef ENABLE_ATARI_SCC + static const struct { + unsigned reg, val; + } init_tab[] = { + /* no parity, 1 stop bit, async, 1:16 */ + { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x64 }, + /* parity error is special cond, ints disabled, no DMA */ + { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, + /* Rx 8 bits/char, no auto enable, Rx off */ + { RX_CTRL_REG, RCR_CHSIZE_8 }, + /* DTR off, Tx 8 bits/char, RTS off, Tx off */ + { TX_CTRL_REG, TCR_CHSIZE_8 }, + /* special features off */ + { AUX2_CTRL_REG, 0 }, + /* RTxC is XTAL, TRxC is input, both clocks = RTxC */ + { CLK_CTRL_REG, CCR_TRxCOUT_XTAL | CCR_TXCLK_RTxC | CCR_RXCLK_RTxC }, + { DPLL_CTRL_REG, 0 }, + /* Start Rx */ + { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, + /* Start Tx */ + { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, + /* Ext/Stat ints: CTS, DCD, SYNC (DSR) */ + { INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT }, + /* Reset Ext/Stat ints */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* ...again */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* Rx int always, TX int off, Ext/Stat int on */ + { INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB | + IDR_PARERR_AS_SPCOND | IDR_RX_INT_ALL } + }; +#ifdef CONFIG_ATARI_SCC_DMA + static const struct { + unsigned reg, val; + } init_withdma_tab[] = { + /* no parity, 1 stop bit, async, 1:16 */ + { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x64 }, + /* parity error is special cond, ints disabled, DMA receive but disabled */ + { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB | + IDR_WAITREQ_RX | IDR_WAITREQ_IS_REQ}, + /* Rx 8 bits/char, no auto enable, Rx off */ + { RX_CTRL_REG, RCR_CHSIZE_8 }, + /* DTR off, Tx 8 bits/char, RTS off, Tx off */ + { TX_CTRL_REG, TCR_CHSIZE_8 }, + /* special features off */ + { AUX2_CTRL_REG, 0 }, + /* RTxC is XTAL, TRxC is input, both clocks = RTxC */ + { CLK_CTRL_REG, CCR_TRxCOUT_XTAL | CCR_TXCLK_RTxC | CCR_RXCLK_RTxC }, + { DPLL_CTRL_REG, 0 }, + /* Start Rx */ + { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, + /* Start Tx */ + { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, + /* Ext/Stat ints: CTS, DCD, SYNC (DSR) */ + { INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT }, + /* Reset Ext/Stat ints */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* ...again */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* parity error is special cond, Tx & SPcond ints enabled, Rx int disabled, DMA receive but disabled */ + { INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB | IDR_PARERR_AS_SPCOND | + IDR_RX_INT_DISAB | IDR_WAITREQ_RX | IDR_WAITREQ_IS_REQ} + }; +#endif +#endif +#ifdef CONFIG_MVME147_SCC + static const struct { + unsigned reg, val; + } m147_init_tab[] = { + /* Values for MVME147 */ + /* no parity, 1 stop bit, async, 1:16 */ + { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, + /* parity error is special cond, ints disabled, no DMA */ + { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, + /* Rx 8 bits/char, no auto enable, Rx off */ + { RX_CTRL_REG, RCR_CHSIZE_8 }, + /* DTR off, Tx 8 bits/char, RTS off, Tx off */ + { TX_CTRL_REG, TCR_CHSIZE_8 }, + /* special features off */ + { AUX2_CTRL_REG, 0 }, + { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG }, + { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK }, + /* Start Rx */ + { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, + /* Start Tx */ + { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, + /* Ext/Stat ints: CTS, DCD, SYNC (DSR) */ + { INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT }, + /* Reset Ext/Stat ints */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* ...again */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* Rx int always, TX int off, Ext/Stat int on */ + { INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB | + IDR_PARERR_AS_SPCOND | IDR_RX_INT_ALL } + }; +#endif +#ifdef CONFIG_MVME162_SCC + static const struct { + unsigned reg, val; + } mvme_init_tab[] = { + /* Values for MVME162 */ + /* no parity, 1 stop bit, async, 1:16 */ + { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, + /* parity error is special cond, ints disabled, no DMA */ + { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, + /* Rx 8 bits/char, no auto enable, Rx off */ + { RX_CTRL_REG, RCR_CHSIZE_8 }, + /* DTR off, Tx 8 bits/char, RTS off, Tx off */ + { TX_CTRL_REG, TCR_CHSIZE_8 }, + /* special features off */ + { AUX2_CTRL_REG, 0 }, + { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG }, + { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK }, + /* Start Rx */ + { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, + /* Start Tx */ + { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, + /* Ext/Stat ints: CTS, DCD, SYNC (DSR) */ + { INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT }, + /* Reset Ext/Stat ints */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* ...again */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* Rx int always, TX int off, Ext/Stat int on */ + { INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB | + IDR_PARERR_AS_SPCOND | IDR_RX_INT_ALL } + }; +#endif +#ifdef CONFIG_BVME6000_SCC + static const struct { + unsigned reg, val; + } bvme_init_tab[] = { + /* Values for BVME6000 */ + /* no parity, 1 stop bit, async, 1:16 */ + { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, + /* parity error is special cond, ints disabled, no DMA */ + { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, + /* Rx 8 bits/char, no auto enable, Rx off */ + { RX_CTRL_REG, RCR_CHSIZE_8 }, + /* DTR off, Tx 8 bits/char, RTS off, Tx off */ + { TX_CTRL_REG, TCR_CHSIZE_8 }, + /* special features off */ + { AUX2_CTRL_REG, 0 }, + { CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG }, + { DPLL_CTRL_REG, DCR_BRG_ENAB }, + /* Start Rx */ + { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, + /* Start Tx */ + { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, + /* Ext/Stat ints: CTS, DCD, SYNC (DSR) */ + { INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT }, + /* Reset Ext/Stat ints */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* ...again */ + { COMMAND_REG, CR_EXTSTAT_RESET }, + /* Rx int always, TX int off, Ext/Stat int on */ + { INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB | + IDR_PARERR_AS_SPCOND | IDR_RX_INT_ALL } + }; +#endif + save_flags(flags); + cli(); + + if (!MACH_IS_MVME16x && !MACH_IS_BVME6000 && !MACH_IS_MVME147) { + SCCmod( MASTER_INT_CTRL, 0x3f, + channel == 0 ? MIC_CH_A_RESET : MIC_CH_B_RESET ); + udelay(40); /* extra delay after a reset */ + } + +#ifdef ENABLE_ATARI_SCC + if (MACH_IS_ATARI) { +#ifdef CONFIG_ATARI_SCC_DMA + if (channel == CHANNEL_A && scca_dma) { + + for (i=0; iactive = 1; + dma_start (); + SCCmod (INT_AND_DMA_REG, 0xff, IDR_RX_INT_SPCOND|IDR_WAITREQ_ENAB); + + SCC_flush_tqueue.data = ((struct m68k_async_struct *)info)->tty; + + } else +#endif + { + for (i=0; i 65535) + return( -1 ); + + switch( clksrc ) { + + case CLK_PCLK: + /* The master clock can only be used with the BRG, divisors + * range from 4 and must be a multiple of 2 + */ + return( !(divisor >= 4 && (divisor & 1) == 0) ); + + case CLK_RTxC: + /* The RTxC clock can either be used for the direct 1:16, 1:32 + * or 1:64 modes (divisors 1, 2 or 4, resp.) or with the BRG + * (divisors from 4 and a multiple of 2) + */ + return( !(divisor >= 1 && (divisor == 1 || (divisor & 1) == 0)) ); + + case CLK_TRxC: + /* The TRxC clock can only be used for direct 1:16, 1:32 or + * 1:64 modes + */ + return( !(divisor == 1 || divisor == 2 || divisor == 4) ); + + } + return( -1 ); +} + + +static void SCC_change_speed( struct m68k_async_struct *info ) +{ + /* the SCC has char sizes 5,7,6,8 in that order! */ + static int chsize_map[4] = { 0, 2, 1, 3 }; + unsigned cflag, baud, chsize, aflags; + unsigned channel, div = 0, clkmode, brgmode, brgval; + int clksrc = 0; + unsigned long flags; + SCC_ACCESS_INIT(info); + + if (!info->tty || !info->tty->termios) return; + + channel = CHANNR(info); + + if (MACH_IS_MVME147 && channel == CHANNEL_A) + return; /* Settings controlled by 147Bug */ + if (MACH_IS_MVME16x && channel == CHANNEL_A) + return; /* Settings controlled by 162Bug */ + if (MACH_IS_BVME6000 && channel == CHANNEL_A) + return; /* Settings controlled by BVMBug */ + + cflag = info->tty->termios->c_cflag; + baud = cflag & CBAUD; + chsize = (cflag & CSIZE) >> 4; + aflags = info->flags & ASYNC_SPD_MASK; + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + +#if DEBUG & DEBUG_SPEED + printk( "SCC channel %d: doing new settings:\n", CHANNR(info) ); + printk( " baud=%d chsize=%d aflags=%04x base_baud=%d divisor=%d\n", + baud, chsize, aflags, info->baud_base, info->custom_divisor ); +#endif + + if (baud == 0 && !aflags) { + /* speed == 0 -> drop DTR */ + save_flags(flags); + cli(); + SCCmod( TX_CTRL_REG, ~TCR_DTR, 0 ); + restore_flags(flags); + return; + } + + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + if (baud < 1 || baud > (MACH_IS_MVME16x ? 2 : 4)) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; + } + if (baud == 15 && aflags) { + switch( aflags) { + case ASYNC_SPD_HI: + baud = 16; + break; + case ASYNC_SPD_VHI: + baud = 17; + break; + case ASYNC_SPD_SHI: + baud = 18; + break; + case ASYNC_SPD_WARP: + baud = 19; + break; + case ASYNC_SPD_CUST: + /* Custom divisor: Compute clock source from the base_baud + * field */ + if ((clksrc = SCC_clocksrc( info->baud_base, channel )) < 0) + /* This shouldn't happen... the baud_base has been checked + * before by check_custom_divisor() */ + return; + div = info->custom_divisor; + } + } + + if (!div) { + if (baud > 19) baud = 19; + clksrc = SCC_baud_table[channel][baud].clksrc; + div = SCC_baud_table[channel][baud].div; + if(!div) + { + printk(" SCC_change_speed: divisor = 0 !!!"); + return; + } + } + + /* compute the SCC's clock source, clock mode, BRG mode and BRG + * value from clksrc and div + */ + if (div <= 4) { + clkmode = (div == 1 ? A1CR_CLKMODE_x16 : + div == 2 ? A1CR_CLKMODE_x32 : + A1CR_CLKMODE_x64); + clksrc = (clksrc == CLK_RTxC + ? CCR_TXCLK_RTxC | CCR_RXCLK_RTxC + : CCR_TXCLK_TRxC | CCR_RXCLK_TRxC); + brgmode = 0; /* off */ + brgval = 0; + } + else { + brgval = div/2 - 2; + brgmode = (DCR_BRG_ENAB | + (clksrc == CLK_PCLK ? DCR_BRG_USE_PCLK : 0)); + clkmode = A1CR_CLKMODE_x16; + clksrc = CCR_TXCLK_BRG | CCR_RXCLK_BRG; + } + + /* Now we have all parameters and can go to set them: */ + save_flags(flags); + cli(); +#if DEBUG & DEBUG_SPEED + printk( " brgval=%d brgmode=%02x clkmode=%02x clksrc=%02x\n", + brgval, brgmode, clkmode, clksrc ); +#endif + + /* receiver's character size */ + SCCmod( RX_CTRL_REG, ~RCR_CHSIZE_MASK, chsize_map[chsize] << 6 ); +#if DEBUG & DEBUG_SPEED + printk( " RX_CTRL_REG <- %02x\n", SCCread( RX_CTRL_REG ) ); +#endif + + /* parity and stop bits (both, Tx and Rx) and clock mode */ + SCCmod (AUX1_CTRL_REG, + ~(A1CR_PARITY_MASK | A1CR_MODE_MASK | A1CR_CLKMODE_MASK), + ((cflag & PARENB + ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN) + : A1CR_PARITY_NONE) + | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1) + | clkmode)); +#if DEBUG & DEBUG_SPEED + printk( " AUX1_CTRL_REG <- %02x\n", SCCread( AUX1_CTRL_REG ) ); +#endif + + /* sender's character size */ + /* Set DTR for valid baud rates! Tnx to jds@kom.auc.dk */ + SCCmod( TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR ); +#if DEBUG & DEBUG_SPEED + printk( " TX_CTRL_REG <- %02x\n", SCCread( TX_CTRL_REG ) ); +#endif + + /* clock sources */ + SCCmod( CLK_CTRL_REG, ~(CCR_TXCLK_MASK | CCR_RXCLK_MASK), clksrc ); +#if DEBUG & DEBUG_SPEED + printk( " CLK_CTRL_REG <- %02x\n", SCCread( CLK_CTRL_REG ) ); +#endif + + /* disable BRG before changing the value */ + SCCmod( DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0 ); + + /* BRG value */ + SCCwrite( TIMER_LOW_REG, brgval & 0xff ); + SCCwrite( TIMER_HIGH_REG, (brgval >> 8) & 0xff ); + + /* BRG enable and clock source */ + SCCmod( DPLL_CTRL_REG, ~(DCR_BRG_ENAB | DCR_BRG_USE_PCLK), brgmode ); +#if DEBUG & DEBUG_SPEED + printk( " TIMER_LOW_REG <- %02x\n", SCCread( TIMER_LOW_REG ) ); + printk( " TIMER_HIGH_REG <- %02x\n", SCCread( TIMER_HIGH_REG ) ); +#endif +#if DEBUG & DEBUG_SPEED + printk( " DPLL_CTRL_REG <- %02x\n", SCCread( DPLL_CTRL_REG ) ); +#endif + + restore_flags(flags); +} + + +static int SCC_clocksrc( unsigned baud_base, unsigned channel ) +{ + if (baud_base == SCC_PCLK) + return( CLK_PCLK ); + else if (SCC_clocks[channel][CLK_RTxC] != SCC_BAUD_BASE_NONE && + baud_base == SCC_clocks[channel][CLK_RTxC]) + return( CLK_RTxC ); + else if (SCC_clocks[channel][CLK_TRxC] != SCC_BAUD_BASE_NONE && + baud_base == SCC_clocks[channel][CLK_TRxC]) + return( CLK_TRxC ); + else + return( -1 ); +} + +static void SCC_throttle( struct m68k_async_struct *info, int status ) +{ + unsigned long flags; + SCC_ACCESS_INIT(info); + +#if DEBUG & DEBUG_THROTTLE + printk( "SCC channel %d: throttle %s\n", + CHANNR(info), status ? "full" : "avail" ); +#endif + save_flags(flags); + cli(); + + if (status) + SCCmod( TX_CTRL_REG, ~TCR_RTS, 0 ); + else + SCCmod( TX_CTRL_REG, 0xff, TCR_RTS ); + +#if DEBUG & DEBUG_THROTTLE + printk( " now TX_CTRL_REG = %02x\n", SCCread( TX_CTRL_REG ) ); +#endif + + restore_flags(flags); +} + + +static void SCC_set_break( struct m68k_async_struct *info, int break_flag ) +{ + unsigned long flags; + SCC_ACCESS_INIT(info); + + save_flags(flags); + cli(); + + if (break_flag) { + SCCmod( TX_CTRL_REG, 0xff, TCR_SEND_BREAK ); + } else { + SCCmod( TX_CTRL_REG, ~TCR_SEND_BREAK, 0 ); + } + + restore_flags(flags); +} + + +static void SCC_get_serial_info( struct m68k_async_struct *info, + struct serial_struct *retinfo ) +{ + retinfo->baud_base = info->baud_base; + retinfo->custom_divisor = info->custom_divisor; +} + + +static unsigned int SCC_get_modem_info( struct m68k_async_struct *info ) +{ + unsigned sr, tcr, ri = 0, dsr = 0; + unsigned long flags; + SCC_ACCESS_INIT(info); + + save_flags(flags); + cli(); + sr = SCCread( STATUS_REG ); + tcr = SCCread( TX_CTRL_REG ); + restore_flags(flags); +#if DEBUG & DEBUG_INFO + printk( "SCC channel %d: get info, sr=%02x tcr=%02x\n", + CHANNR(info), sr, tcr ); +#endif +#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) + if (MACH_IS_MVME147 || MACH_IS_MVME16x || MACH_IS_BVME6000) { + ri = 0; + dsr = sr & SR_SYNC_ABORT ? TIOCM_DSR : 0; + } +#endif +#ifdef ENABLE_ATARI_SCC + if (MACH_IS_ATARI) { + if (CHANNR (info) == 0) + ri = 0; + else if (ATARIHW_PRESENT (TT_MFP)) + ri = tt_mfp.par_dt_reg & (1 << 3) ? 0 : TIOCM_RNG; + else + ri = mfp.par_dt_reg & (1 << 6) ? 0 : TIOCM_RNG; + + if (ATARIHW_PRESENT (ST_ESCC)) + dsr = st_escc_dsr & (1 << (3 - CHANNR(info))) ? TIOCM_DSR : 0; + else + dsr = sr & SR_SYNC_ABORT ? TIOCM_DSR : 0; + } +#endif + return (((tcr & TCR_RTS) ? TIOCM_RTS : 0) | + ((tcr & TCR_DTR) ? TIOCM_DTR : 0) | + ((sr & SR_DCD ) ? TIOCM_CAR : 0) | + ((sr & SR_CTS ) ? TIOCM_CTS : 0) | + dsr | ri); +} + + +static int SCC_set_modem_info( struct m68k_async_struct *info, + int new_dtr, int new_rts ) +{ + unsigned long flags; + SCC_ACCESS_INIT(info); + + save_flags(flags); + cli(); + + if (new_dtr == 0) { + SCCmod( TX_CTRL_REG, ~TCR_DTR, 0 ); + } else if (new_dtr == 1) { + SCCmod( TX_CTRL_REG, 0xff, TCR_DTR ); + } + + if (new_rts == 0) { + SCCmod( TX_CTRL_REG, ~TCR_RTS, 0 ); + } else if (new_rts == 1) { + SCCmod( TX_CTRL_REG, 0xff, TCR_RTS ); + } + +#if DEBUG & DEBUG_INFO + printk( "SCC channel %d: set info (dtr=%d,rts=%d), now tcr=%02x\n", + CHANNR(info), new_dtr, new_rts, SCCread( TX_CTRL_REG ) ); +#endif + + restore_flags(flags); + return( 0 ); +} + +static void SCC_stop_receive (struct m68k_async_struct *info) +{ + SCC_ACCESS_INIT(info); + +#ifdef CONFIG_ATARI_SCC_DMA + dma_stop (); +#endif + + /* disable Rx interrupts */ + SCCmod (INT_AND_DMA_REG, ~IDR_RX_INT_MASK, 0); + + /* disable Rx */ + if (!((MACH_IS_MVME16x || MACH_IS_BVME6000) && CHANNR(info) == CHANNEL_A)) + SCCmod (RX_CTRL_REG, ~RCR_RX_ENAB, 0); +} + +static int SCC_trans_empty (struct m68k_async_struct *info) +{ + SCC_ACCESS_INIT(info); + + return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) != 0; +} + +static int SCC_ioctl( struct tty_struct *tty, struct file *file, + struct m68k_async_struct *info, unsigned int cmd, + unsigned long arg ) +{ + struct atari_SCCserial *cp = (void *)arg; + int error; + unsigned channel = CHANNR(info), i, clk, div, rtxc, trxc, pclk; + + switch( cmd ) { + + case TIOCGATSCC: + + error = verify_area( VERIFY_WRITE, (void *)arg, + sizeof(struct atari_SCCserial) ); + if (error) + return error; + + put_user(SCC_clocks[channel][CLK_RTxC], &cp->RTxC_base); + put_user(SCC_clocks[channel][CLK_TRxC], &cp->TRxC_base); + put_user(SCC_PCLK, &cp->PCLK_base); + copy_to_user(cp->baud_table, SCC_baud_table[channel] + 1, + sizeof(cp->baud_table)); + + return( 0 ); + + case TIOCSATSCC: + + if (!suser()) return( -EPERM ); + + error = verify_area(VERIFY_READ, (void *)arg, + sizeof(struct atari_SCCserial) ); + if (error) + return error; + + get_user(rtxc, &cp->RTxC_base); + get_user(trxc, &cp->TRxC_base); + get_user(pclk, &cp->PCLK_base); + + if (pclk == SCC_BAUD_BASE_NONE) + /* This is really not possible :-) */ + return( -EINVAL ); + + /* Check the baud table for consistency */ + for( i = 0; i < sizeof(cp->baud_table)/sizeof(cp->baud_table[0]); ++i ) { + + get_user(clk, &cp->baud_table[i].clksrc); + get_user(div, &cp->baud_table[i].divisor); + + switch( clk ) { + case CLK_RTxC: + if (rtxc == SCC_BAUD_BASE_NONE) + return( -EINVAL ); + if (((div & 1) && div != 1) || + (div >= 4 && div/2-2 > 65535)) + return( -EINVAL ); + break; + case CLK_TRxC: + if (trxc == SCC_BAUD_BASE_NONE) + return( -EINVAL ); + if (div != 1 && div != 2 && div != 4) + return( -EINVAL ); + break; + case CLK_PCLK: + if (div < 4 || (div & 1) || div/2-2 > 65535) + return( -EINVAL ); + break; + default: + /* invalid valid clock source */ + return( -EINVAL ); + } + } + + /* After all the checks, set the values */ + + SCC_clocks[channel][CLK_RTxC] = rtxc; + SCC_clocks[channel][CLK_TRxC] = trxc; + SCC_PCLK = pclk; + + copy_from_user(bdtab_usr[channel] + 1, cp->baud_table, + sizeof(cp->baud_table)); + /* Now use the user supplied baud table */ + SCC_baud_table[channel] = bdtab_usr[channel]; + + return( 0 ); + + case TIOCDATSCC: + + if (!suser()) return( -EPERM ); +#ifdef ENABLE_ATARI_SCC + if (!MACH_IS_ATARI) + return 0; /* XXX */ + + if (ATARIHW_PRESENT(TT_MFP)) { + SCC_clocks[channel][CLK_RTxC] = + (channel == CHANNEL_A) ? + SCC_BAUD_BASE_PCLK4 : + SCC_BAUD_BASE_TIMC; + SCC_clocks[channel][CLK_TRxC] = + (channel == CHANNEL_A) ? + SCC_BAUD_BASE_NONE : + SCC_BAUD_BASE_BCLK; + } + else { + SCC_clocks[channel][CLK_RTxC] = SCC_BAUD_BASE_PCLK4; + SCC_clocks[channel][CLK_TRxC] = + (channel == CHANNEL_A) ? + SCC_BAUD_BASE_NONE : + SCC_BAUD_BASE_BCLK; + } + + SCC_PCLK = SCC_BAUD_BASE_PCLK; + SCC_baud_table[channel] = + ((ATARIHW_PRESENT(TT_MFP) && channel == 1) ? + bdtab_TTChB : bdtab_norm); +#endif + return( 0 ); + + } + return( -ENOIOCTLCMD ); +} + + + + +#ifdef MODULE +int init_module(void) +{ +#ifdef ENABLE_ATARI_SCC + if (MACH_IS_ATARI) + return atari_SCC_init(); +#endif + return -ENODEV; +} + +void cleanup_module(void) +{ + if (chb_line >= 0) { + SCC_deinit_port( &rs_table[chb_line], CHANNEL_B ); + unregister_serial( chb_line ); + } + + /* ++Juergen Starek: use proper structure to deinitialize port + * because atari_free_irq relies on the valid + * `dev_id` parameter! + * If we use only the cha232_line, unloading a + * module causes a damaged irq list! + */ + /* We must deinit channel A only once! ++Andreas. */ + if (cha232_line >= 0) + SCC_deinit_port(&rs_table[cha232_line], CHANNEL_A); + else if (cha422_line >= 0) + SCC_deinit_port(&rs_table[cha422_line], CHANNEL_A); + + if (cha232_line >= 0) + unregister_serial( cha232_line ); + if (cha422_line >= 0) + unregister_serial( cha422_line ); +} +#endif + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/atari_SCC.h linux/drivers/char/atari_SCC.h --- v2.2.17/drivers/char/atari_SCC.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/atari_SCC.h Sat Oct 14 00:06:42 2000 @@ -0,0 +1,616 @@ +/* + * atari_SCC.h: Definitions for the Am8530 Serial Communications Controller + * + * Copyright 1994 Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ + + +#ifndef _ATARI_SCC_H +#define _ATARI_SCC_H + +#include +#include + +#ifdef CONFIG_MVME147_SCC +#include +#endif +#ifdef CONFIG_MVME162_SCC +#include +#endif +#ifdef CONFIG_BVME6000_SCC +#include +#endif +#ifdef CONFIG_ATARI +#include +#endif + +/***********************************************************************/ +/* */ +/* Register Names */ +/* */ +/***********************************************************************/ + +/* The SCC documentation gives no explicit names to the registers, + * they're just called WR0..15 and RR0..15. To make the source code + * better readable and make the transparent write reg read access (see + * below) possible, I christen them here with self-invented names. + * Note that (real) read registers are assigned numbers 16..31. WR7' + * has number 33. + */ + +#define COMMAND_REG 0 /* wo */ +#define INT_AND_DMA_REG 1 /* wo */ +#define INT_VECTOR_REG 2 /* rw, common to both channels */ +#define RX_CTRL_REG 3 /* rw */ +#define AUX1_CTRL_REG 4 /* rw */ +#define TX_CTRL_REG 5 /* rw */ +#define SYNC_ADR_REG 6 /* wo */ +#define SYNC_CHAR_REG 7 /* wo */ +#define SDLC_OPTION_REG 33 /* wo */ +#define TX_DATA_REG 8 /* wo */ +#define MASTER_INT_CTRL 9 /* wo, common to both channels */ +#define AUX2_CTRL_REG 10 /* rw */ +#define CLK_CTRL_REG 11 /* wo */ +#define TIMER_LOW_REG 12 /* rw */ +#define TIMER_HIGH_REG 13 /* rw */ +#define DPLL_CTRL_REG 14 /* wo */ +#define INT_CTRL_REG 15 /* rw */ + +#define STATUS_REG 16 /* ro */ +#define SPCOND_STATUS_REG 17 /* wo */ +/* RR2 is WR2 for Channel A, Channel B gives vector + current status: */ +#define CURR_VECTOR_REG 18 /* Ch. B only, Ch. A for rw */ +#define INT_PENDING_REG 19 /* Channel A only! */ +/* RR4 is WR4, if b6(MR7') == 1 */ +/* RR5 is WR5, if b6(MR7') == 1 */ +#define FS_FIFO_LOW_REG 22 /* ro */ +#define FS_FIFO_HIGH_REG 23 /* ro */ +#define RX_DATA_REG 24 /* ro */ +/* RR9 is WR3, if b6(MR7') == 1 */ +#define DPLL_STATUS_REG 26 /* ro */ +/* RR11 is WR10, if b6(MR7') == 1 */ +/* RR12 is WR12 */ +/* RR13 is WR13 */ +/* RR14 not present */ +/* RR15 is WR15 */ + + +/***********************************************************************/ +/* */ +/* Register Values */ +/* */ +/***********************************************************************/ + + +/* WR0: COMMAND_REG "CR" */ + +#define CR_RX_CRC_RESET 0x40 +#define CR_TX_CRC_RESET 0x80 +#define CR_TX_UNDERRUN_RESET 0xc0 + +#define CR_EXTSTAT_RESET 0x10 +#define CR_SEND_ABORT 0x18 +#define CR_ENAB_INT_NEXT_RX 0x20 +#define CR_TX_PENDING_RESET 0x28 +#define CR_ERROR_RESET 0x30 +#define CR_HIGHEST_IUS_RESET 0x38 + + +/* WR1: INT_AND_DMA_REG "IDR" */ + +#define IDR_EXTSTAT_INT_ENAB 0x01 +#define IDR_TX_INT_ENAB 0x02 +#define IDR_PARERR_AS_SPCOND 0x04 + +#define IDR_RX_INT_DISAB 0x00 +#define IDR_RX_INT_FIRST 0x08 +#define IDR_RX_INT_ALL 0x10 +#define IDR_RX_INT_SPCOND 0x18 +#define IDR_RX_INT_MASK 0x18 + +#define IDR_WAITREQ_RX 0x20 +#define IDR_WAITREQ_IS_REQ 0x40 +#define IDR_WAITREQ_ENAB 0x80 + + +/* WR3: RX_CTRL_REG "RCR" */ + +#define RCR_RX_ENAB 0x01 +#define RCR_DISCARD_SYNC_CHARS 0x02 +#define RCR_ADDR_SEARCH 0x04 +#define RCR_CRC_ENAB 0x08 +#define RCR_SEARCH_MODE 0x10 +#define RCR_AUTO_ENAB_MODE 0x20 + +#define RCR_CHSIZE_MASK 0xc0 +#define RCR_CHSIZE_5 0x00 +#define RCR_CHSIZE_6 0x40 +#define RCR_CHSIZE_7 0x80 +#define RCR_CHSIZE_8 0xc0 + + +/* WR4: AUX1_CTRL_REG "A1CR" */ + +#define A1CR_PARITY_MASK 0x03 +#define A1CR_PARITY_NONE 0x00 +#define A1CR_PARITY_ODD 0x01 +#define A1CR_PARITY_EVEN 0x03 + +#define A1CR_MODE_MASK 0x0c +#define A1CR_MODE_SYNCR 0x00 +#define A1CR_MODE_ASYNC_1 0x04 +#define A1CR_MODE_ASYNC_15 0x08 +#define A1CR_MODE_ASYNC_2 0x0c + +#define A1CR_SYNCR_MODE_MASK 0x30 +#define A1CR_SYNCR_MONOSYNC 0x00 +#define A1CR_SYNCR_BISYNC 0x10 +#define A1CR_SYNCR_SDLC 0x20 +#define A1CR_SYNCR_EXTCSYNC 0x30 + +#define A1CR_CLKMODE_MASK 0xc0 +#define A1CR_CLKMODE_x1 0x00 +#define A1CR_CLKMODE_x16 0x40 +#define A1CR_CLKMODE_x32 0x80 +#define A1CR_CLKMODE_x64 0xc0 + + +/* WR5: TX_CTRL_REG "TCR" */ + +#define TCR_TX_CRC_ENAB 0x01 +#define TCR_RTS 0x02 +#define TCR_USE_CRC_CCITT 0x00 +#define TCR_USE_CRC_16 0x04 +#define TCR_TX_ENAB 0x08 +#define TCR_SEND_BREAK 0x10 + +#define TCR_CHSIZE_MASK 0x60 +#define TCR_CHSIZE_5 0x00 +#define TCR_CHSIZE_6 0x20 +#define TCR_CHSIZE_7 0x40 +#define TCR_CHSIZE_8 0x60 + +#define TCR_DTR 0x80 + + +/* WR7': SLDC_OPTION_REG "SOR" */ + +#define SOR_AUTO_TX_ENAB 0x01 +#define SOR_AUTO_EOM_RESET 0x02 +#define SOR_AUTO_RTS_MODE 0x04 +#define SOR_NRZI_DISAB_HIGH 0x08 +#define SOR_ALT_DTRREQ_TIMING 0x10 +#define SOR_READ_CRC_CHARS 0x20 +#define SOR_EXTENDED_REG_ACCESS 0x40 + + +/* WR9: MASTER_INT_CTRL "MIC" */ + +#define MIC_VEC_INCL_STAT 0x01 +#define MIC_NO_VECTOR 0x02 +#define MIC_DISAB_LOWER_CHAIN 0x04 +#define MIC_MASTER_INT_ENAB 0x08 +#define MIC_STATUS_HIGH 0x10 +#define MIC_IGN_INTACK 0x20 + +#define MIC_NO_RESET 0x00 +#define MIC_CH_A_RESET 0x40 +#define MIC_CH_B_RESET 0x80 +#define MIC_HARD_RESET 0xc0 + + +/* WR10: AUX2_CTRL_REG "A2CR" */ + +#define A2CR_SYNC_6 0x01 +#define A2CR_LOOP_MODE 0x02 +#define A2CR_ABORT_ON_UNDERRUN 0x04 +#define A2CR_MARK_IDLE 0x08 +#define A2CR_GO_ACTIVE_ON_POLL 0x10 + +#define A2CR_CODING_MASK 0x60 +#define A2CR_CODING_NRZ 0x00 +#define A2CR_CODING_NRZI 0x20 +#define A2CR_CODING_FM1 0x40 +#define A2CR_CODING_FM0 0x60 + +#define A2CR_PRESET_CRC_1 0x80 + + +/* WR11: CLK_CTRL_REG "CCR" */ + +#define CCR_TRxCOUT_MASK 0x03 +#define CCR_TRxCOUT_XTAL 0x00 +#define CCR_TRxCOUT_TXCLK 0x01 +#define CCR_TRxCOUT_BRG 0x02 +#define CCR_TRxCOUT_DPLL 0x03 + +#define CCR_TRxC_OUTPUT 0x04 + +#define CCR_TXCLK_MASK 0x18 +#define CCR_TXCLK_RTxC 0x00 +#define CCR_TXCLK_TRxC 0x08 +#define CCR_TXCLK_BRG 0x10 +#define CCR_TXCLK_DPLL 0x18 + +#define CCR_RXCLK_MASK 0x60 +#define CCR_RXCLK_RTxC 0x00 +#define CCR_RXCLK_TRxC 0x20 +#define CCR_RXCLK_BRG 0x40 +#define CCR_RXCLK_DPLL 0x60 + +#define CCR_RTxC_XTAL 0x80 + + +/* WR14: DPLL_CTRL_REG "DCR" */ + +#define DCR_BRG_ENAB 0x01 +#define DCR_BRG_USE_PCLK 0x02 +#define DCR_DTRREQ_IS_REQ 0x04 +#define DCR_AUTO_ECHO 0x08 +#define DCR_LOCAL_LOOPBACK 0x10 + +#define DCR_DPLL_EDGE_SEARCH 0x20 +#define DCR_DPLL_ERR_RESET 0x40 +#define DCR_DPLL_DISAB 0x60 +#define DCR_DPLL_CLK_BRG 0x80 +#define DCR_DPLL_CLK_RTxC 0xa0 +#define DCR_DPLL_FM 0xc0 +#define DCR_DPLL_NRZI 0xe0 + + +/* WR15: INT_CTRL_REG "ICR" */ + +#define ICR_OPTIONREG_SELECT 0x01 +#define ICR_ENAB_BRG_ZERO_INT 0x02 +#define ICR_USE_FS_FIFO 0x04 +#define ICR_ENAB_DCD_INT 0x08 +#define ICR_ENAB_SYNC_INT 0x10 +#define ICR_ENAB_CTS_INT 0x20 +#define ICR_ENAB_UNDERRUN_INT 0x40 +#define ICR_ENAB_BREAK_INT 0x80 + + +/* RR0: STATUS_REG "SR" */ + +#define SR_CHAR_AVAIL 0x01 +#define SR_BRG_ZERO 0x02 +#define SR_TX_BUF_EMPTY 0x04 +#define SR_DCD 0x08 +#define SR_SYNC_ABORT 0x10 +#define SR_CTS 0x20 +#define SR_TX_UNDERRUN 0x40 +#define SR_BREAK 0x80 + + +/* RR1: SPCOND_STATUS_REG "SCSR" */ + +#define SCSR_ALL_SENT 0x01 +#define SCSR_RESIDUAL_MASK 0x0e +#define SCSR_PARITY_ERR 0x10 +#define SCSR_RX_OVERRUN 0x20 +#define SCSR_CRC_FRAME_ERR 0x40 +#define SCSR_END_OF_FRAME 0x80 + + +/* RR3: INT_PENDING_REG "IPR" */ + +#define IPR_B_EXTSTAT 0x01 +#define IPR_B_TX 0x02 +#define IPR_B_RX 0x04 +#define IPR_A_EXTSTAT 0x08 +#define IPR_A_TX 0x10 +#define IPR_A_RX 0x20 + + +/* RR7: FS_FIFO_HIGH_REG "FFHR" */ + +#define FFHR_CNT_MASK 0x3f +#define FFHR_IS_FROM_FIFO 0x40 +#define FFHR_FIFO_OVERRUN 0x80 + + +/* RR10: DPLL_STATUS_REG "DSR" */ + +#define DSR_ON_LOOP 0x02 +#define DSR_ON_LOOP_SENDING 0x10 +#define DSR_TWO_CLK_MISSING 0x40 +#define DSR_ONE_CLK_MISSING 0x80 + + + +/***************************** Prototypes *****************************/ + +int atari_SCC_init( void ); + +/************************* End of Prototypes **************************/ + +/* Compute the channel number from the base address */ + +#define CHANNR(info) (((info)->port & (MACH_IS_BVME6000 ? 8 : (MACH_IS_MVME147 ? 2 : 4))) != ChannelsReversed) + + +/***********************************************************************/ +/* */ +/* Constants */ +/* */ +/***********************************************************************/ + + +/***********************************************************************/ +/* */ +/* Register Access */ +/* */ +/***********************************************************************/ + + +/* The SCC needs 3.5 PCLK cycles recovery time between to register + * accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 * + * 125 ns = 437.5 ns. Since this is too short for udelay(), it is + * implemented by some nop's. I think that a nop needs 4 cycles (but + * I'm not sure, correct me please!), that gives 4 nops for a TT (32 + * MHz) (2 would be sufficient for the Falcon (16 MHz), but looking at + * boot_info.bi_atari.model at runtime takes longer than 2 nop's...) + * ++andreas: nop needs only 2 cycles, seven of them are needed. + */ + +/* 10/16/95: A tstb mfp.par_dt_reg takes 600ns (sure?) and thus should be + * quite right + */ + +#define scc_reg_delay() \ + do { \ + if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) \ + udelay(1); \ + else \ + __asm__ __volatile__ ( "tstb %0" : : "g" (*_scc_del) : "cc" );\ + } while (0) + +/* Another version with only 3 nop's for cases when some other + * statement intervenes between the two SCC accesses + * ++andreas: 3 nop's added + * 10/16/95: use MFPDELAY, too. + */ + +#define scc_reg3_delay() \ + if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) \ + udelay(1); \ + else \ + __asm__ __volatile__ ( "tstb %0" : : "g" (*_scc_del) : "cc" ); + + +struct PARTIAL_SCC { /* just one channel */ + unsigned char ctrl; + unsigned char dummy; + unsigned char data; +}; + + +extern unsigned char SCC_shadow[2][16]; +extern int ChannelsReversed; + + +/* The following functions should relax the somehow complicated + * register access of the SCC. _SCCwrite() stores all written values + * (except for WR0 and WR8) in shadow registers for later recall. This + * removes the burden of remembering written values as needed. The + * extra work of storing the value doesn't count, since a delay is + * needed after a SCC access anyway. Additionally, _SCCwrite() manages + * writes to WR0 and WR8 differently, because these can be accessed + * directly with less overhead. Another special case are WR7 and WR7'. + * _SCCwrite automatically checks what of this registers is selected + * and changes b0 of WR15 if needed. + * + * _SCCread() for standard read registers is straightforward, except + * for RR2 (split into two "virtual" registers: one for the value + * written to WR2 (from the shadow) and one for the vector including + * status from RR2, Ch. B) and RR3. The latter must be read from + * Channel A, because it reads as all zeros on Ch. B. RR0 and RR8 can + * be accessed directly as before. + * + * The two inline function contain complicated switch statements. But + * I rely on regno and final_delay being constants, so gcc can reduce + * the whole stuff to just some assembler statements. + * + * _SCCwrite and _SCCread aren't intended to be used directly under + * normal circumstances. The macros SCCread[_ND] and SCCwrite[_ND] are + * for that purpose. They assume that a local variable 'info' is + * declared and pointing to the port's m68k_async_struct entry. The + * variants with "_NB" appended should be used if no other SCC + * accesses follow immediatly (within 0.5 usecs). They just skip the + * final delay nops. + * + * Please note that accesses to SCC registers should only take place + * when interrupts are turned off (at least if SCC interrupts are + * enabled). Otherwise, an interrupt could interfere with the + * two-stage accessing process. + * + */ + + +static __inline__ void _SCCwrite( + volatile struct PARTIAL_SCC *sc, + unsigned char *shadow, + volatile unsigned char *_scc_del, + int regno, + unsigned char val, int final_delay ) +{ + switch( regno ) { + + case COMMAND_REG: + /* WR0 can be written directly without pointing */ + sc->ctrl = val; + break; + + case SYNC_CHAR_REG: + /* For WR7, first set b0 of WR15 to 0, if needed */ + if (shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT) { + sc->ctrl = 15; + shadow[INT_CTRL_REG] &= ~ICR_OPTIONREG_SELECT; + scc_reg3_delay(); + sc->ctrl = shadow[INT_CTRL_REG]; + scc_reg_delay(); + } + goto normal_case; + + case SDLC_OPTION_REG: + /* For WR7', first set b0 of WR15 to 1, if needed */ + if (!(shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT)) { + sc->ctrl = 15; + shadow[INT_CTRL_REG] |= ICR_OPTIONREG_SELECT; + scc_reg3_delay(); + sc->ctrl = shadow[INT_CTRL_REG]; + scc_reg_delay(); + } + sc->ctrl = 7; + shadow[8] = val; /* WR7' shadowed at WR8 */ + scc_reg3_delay(); + sc->ctrl = val; + break; + + case TX_DATA_REG: /* WR8 */ + /* TX_DATA_REG can be accessed directly on some h/w */ + if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) + { + sc->ctrl = regno; + scc_reg_delay(); + sc->ctrl = val; + } + else + sc->data = val; + break; + + case MASTER_INT_CTRL: + sc->ctrl = regno; + val &= 0x3f; /* bits 6..7 are the reset commands */ + SCC_shadow[0][regno] = val; + scc_reg3_delay(); + sc->ctrl = val; + break; + + case DPLL_CTRL_REG: + sc->ctrl = regno; + val &= 0x1f; /* bits 5..7 are the DPLL commands */ + shadow[regno] = val; + scc_reg3_delay(); + sc->ctrl = val; + break; + + case 1 ... 6: + case 10 ... 13: + case 15: + normal_case: + sc->ctrl = regno; + shadow[regno] = val; + scc_reg3_delay(); + sc->ctrl = val; + break; + + default: + printk( "Bad SCC write access to WR%d\n", regno ); + break; + + } + + if (final_delay) + scc_reg_delay(); +} + + +static __inline__ unsigned char _SCCread( + volatile struct PARTIAL_SCC *sc, + unsigned char *shadow, + volatile unsigned char *_scc_del, + int regno, int final_delay ) +{ + unsigned char rv; + + switch( regno ) { + + /* --- real read registers --- */ + case STATUS_REG: + rv = sc->ctrl; + break; + + case INT_PENDING_REG: + /* RR3: read only from Channel A! */ + sc = (volatile struct PARTIAL_SCC *) + (((unsigned long)sc & ~(MACH_IS_BVME6000 ? 8 : (MACH_IS_MVME147 ? 2 : 4))) ^ ChannelsReversed); + goto normal_case; + + case RX_DATA_REG: + /* RR8 can be accessed directly on some h/w */ + if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147) + { + sc->ctrl = 8; + scc_reg_delay(); + rv = sc->ctrl; + } + else + rv = sc->data; + break; + + case CURR_VECTOR_REG: + /* RR2 (vector including status) from Ch. B */ + sc = (volatile struct PARTIAL_SCC *) + (((unsigned long)sc | (MACH_IS_BVME6000 ? 8 : (MACH_IS_MVME147 ? 2 : 4))) ^ ChannelsReversed); + goto normal_case; + + /* --- reading write registers: access the shadow --- */ + case 1 ... 7: + case 10 ... 15: + return shadow[regno]; /* no final delay! */ + + /* WR7' is special, because it is shadowed at the place of WR8 */ + case SDLC_OPTION_REG: + return shadow[8]; /* no final delay! */ + + /* WR9 is special too, because it is common for both channels */ + case MASTER_INT_CTRL: + return SCC_shadow[0][9]; /* no final delay! */ + + default: + printk( "Bad SCC read access to %cR%d\n", (regno & 16) ? 'R' : 'W', + regno & ~16 ); + break; + + case SPCOND_STATUS_REG: + case FS_FIFO_LOW_REG: + case FS_FIFO_HIGH_REG: + case DPLL_STATUS_REG: + normal_case: + sc->ctrl = regno & 0x0f; + scc_reg_delay(); + rv = sc->ctrl; + break; + + } + + if (final_delay) + scc_reg_delay(); + return rv; +} + +/* + * The BVME6000 maps the two halves of the SCC 8 bytes apart rather than 4. + * The MVME147 maps the two halves of the SCC 2 bytes apart rather than 4. + */ + +#define SCC_ACCESS_INIT(info) \ + volatile struct PARTIAL_SCC *_SCC_p = \ + (volatile struct PARTIAL_SCC *)info->port; \ + unsigned char *_SCC_shadow = &SCC_shadow[(info->port >> \ + (MACH_IS_BVME6000 ? 3 : (MACH_IS_MVME147 ? 1 : 2))) & 1][0] + +#define SCCwrite(reg,val) _SCCwrite(_SCC_p,_SCC_shadow,scc_del,(reg),(val),1) +#define SCCwrite_NB(reg,val) _SCCwrite(_SCC_p,_SCC_shadow,scc_del,(reg),(val),0) +#define SCCread(reg) _SCCread(_SCC_p,_SCC_shadow,scc_del,(reg),1) +#define SCCread_NB(reg) _SCCread(_SCC_p,_SCC_shadow,scc_del,(reg),0) + +#define SCCmod(reg,and,or) SCCwrite((reg),(SCCread(reg)&(and))|(or)) + +#endif /* _ATARI_SCC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.2.17/drivers/char/bttv.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/char/bttv.c Fri Sep 29 22:17:48 2000 @@ -95,7 +95,6 @@ /* Anybody who uses more than four? */ #define BTTV_MAX 4 -static int find_vga(void); static void bt848_set_risc_jmps(struct bttv *btv); static unsigned int vidmem=0; /* manually set video mem address */ @@ -559,7 +558,7 @@ /* 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}}, + { 4, 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) */ @@ -1196,6 +1195,7 @@ *(ro++)=cpu_to_le32(btv->bus_vbi_even); *(re++)=cpu_to_le32(BT848_RISC_JUMP); *(re++)=cpu_to_le32(btv->bus_vbi_odd); + return; } if (ncr < 0) { /* bitmap was pased */ memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); @@ -1307,8 +1307,8 @@ tvn=&tvnorms[btv->win.norm]; - btv->win.cropheight=tvn->sheight; - btv->win.cropwidth=tvn->swidth; +/* btv->win.cropheight=tvn->sheight; + btv->win.cropwidth=tvn->swidth; set somewhere else now */ /* if (btv->win.cropwidth>tvn->cropwidth) @@ -1413,6 +1413,62 @@ * Set TSA5522 synthesizer frequency in 1/16 Mhz steps */ +static void reset_cropwin(struct bttv * btv) +{ + btv->win.cropx=0; + btv->win.cropy=0; + btv->win.cropheight=tvnorms[btv->win.norm].sheight; + btv->win.cropwidth=tvnorms[btv->win.norm].swidth; +} + +static void clip_cropwin(struct bttv * btv, u16 width, u16 height) +{ + /* don't allow values beyond max */ + + if (btv->win.cropwidth>tvnorms[btv->win.norm].swidth) + btv->win.cropwidth=tvnorms[btv->win.norm].swidth; + + if (btv->win.cropheight>tvnorms[btv->win.norm].sheight) + btv->win.cropheight=tvnorms[btv->win.norm].sheight; + + /* horizontal: downscaling only (bt848 limitation)*/ + if (width>btv->win.cropwidth) + btv->win.cropwidth=width; + + /* horizontal scaling is kinda limited by the registers + probably irrelevant */ + if (btv->win.cropwidth>((65535UL+4096UL)*width)/4096UL) + btv->win.cropwidth = ((65535UL+4096UL)*width)/4096UL; + + /* vertical: downscaling only (not mentioned in the specs + but doesnt work anyways */ + if (height>btv->win.cropheight) + btv->win.cropheight = height; + + if (btv->win.interlace == 0) + { + if (btv->win.cropheight>127UL*height) + btv->win.cropheight = 127UL*height; +/* if (((127UL*512UL-1023UL)*height)/512UL>btv->win.cropheight) + btv->win.cropheight = (127UL*512UL-1023UL)*height/512UL;*/ + } else + { + if (btv->win.cropheight>2UL*127UL*height) + btv->win.cropheight = 2UL*127UL*height; + btv->win.cropheight = (btv->win.cropheight/2)*2; /*even number */ +/* if (((127UL*512UL-1023UL)*height)/256UL>btv->win.cropheight) + btv->win.cropheight = (127UL*512UL-1023UL)*height/256UL;*/ + } + + if (btv->win.cropx>tvnorms[btv->win.norm].swidth-btv->win.cropwidth) + btv->win.cropx = tvnorms[btv->win.norm].swidth-btv->win.cropwidth; + + if (btv->win.cropy>tvnorms[btv->win.norm].sheight-btv->win.cropheight) + btv->win.cropy = tvnorms[btv->win.norm].sheight-btv->win.cropheight; + + return; +} + static void set_freq(struct bttv *btv, unsigned short freq) { int fixme = freq; /* XXX */ @@ -1496,6 +1552,10 @@ * like QCIF has meaning as a capture. */ + + clip_cropwin(btv, mp->width, mp->height); + bt848_set_geo(btv, mp->width, mp->height, mp->format, 1); + /* * Ok load up the BT848 */ @@ -1602,8 +1662,6 @@ audio(btv, AUDIO_UNMUTE); for (i=users=0; ifbuffer=NULL; if (!btv->fbuffer) btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF); @@ -1721,6 +1779,7 @@ b.type = VID_TYPE_CAPTURE| VID_TYPE_TELETEXT| VID_TYPE_OVERLAY| + VID_TYPE_SUBCAPTURE| VID_TYPE_CLIPPING| VID_TYPE_FRAMERAM| VID_TYPE_SCALES| @@ -1780,7 +1839,8 @@ btv->win.norm = v.norm; make_vbitab(btv); bt848_set_winsize(btv); - btv->channel=v.channel; + reset_cropwin(btv); + btv->channel=v.channel; return 0; } case VIDIOCGTUNER: @@ -1905,6 +1965,7 @@ on=(btv->cap&3); bt848_cap(btv,0); + clip_cropwin(btv, vw.width, vw.height); bt848_set_winsize(btv); /* @@ -2226,6 +2287,8 @@ return -EIO; if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) return -EBUSY; + + return vgrab(btv, &vm); } @@ -2263,7 +2326,38 @@ return 0; } - case BTTV_BURST_ON: + case VIDIOCGCAPTURE: + { + struct video_capture vc; + vc.x=btv->win.cropx; + vc.y=btv->win.cropy; + vc.width=btv->win.cropwidth; + vc.height=btv->win.cropheight; + vc.decimation=0; /* not implemented at the moment */ + vc.flags=0; /* dito */ + if(copy_to_user((void *)arg, (void *)&vc, sizeof(vc))) + return -EFAULT; + return 0; + } + + case VIDIOCSCAPTURE: + { + struct video_capture vc; + if(copy_from_user((void *) &vc, (void *) arg, sizeof(vc))) + return -EFAULT; + if (vc.x>tvnorms[btv->win.norm].swidth|| + vc.y>tvnorms[btv->win.norm].sheight|| + vc.width>tvnorms[btv->win.norm].swidth|| + vc.height>tvnorms[btv->win.norm].sheight) + return -EFAULT; + btv->win.cropx=vc.x; + btv->win.cropy=(vc.y>>1)<<1; // make even + btv->win.cropwidth=vc.width; + btv->win.cropheight=vc.height; + return 0; + } + + case BTTV_BURST_ON: { tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2; tvnorms[0].hdelayx1=186-BURSTOFFSET; @@ -2576,234 +2670,6 @@ }; -struct vidbases -{ - unsigned short vendor, device; - char *name; - uint badr; -}; - -static struct vidbases vbs[] = { - { PCI_VENDOR_ID_ALLIANCE, PCI_DEVICE_ID_ALLIANCE_AT3D, - "Alliance AT3D", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215CT222, - "ATI MACH64 CT", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX, - "ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215GT, - "ATI MACH64 GT", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, - "DEC DC21030", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, - "Matrox Millennium", PCI_BASE_ADDRESS_1}, - { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, - "Matrox Millennium II", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, - "Matrox Millennium II AGP", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1}, - { PCI_VENDOR_ID_MATROX, 0x0521, "Matrox G200", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128, - "Number Nine Imagine 128", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128_2, - "Number Nine Imagine 128 Series 2", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0}, - { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128, - "Riva128", PCI_BASE_ADDRESS_1}, -}; - - -/* DEC TGA offsets stolen from XFree-3.2 */ - -static uint dec_offsets[4] = { - 0x200000, - 0x804000, - 0, - 0x1004000 -}; - -#define NR_CARDS (sizeof(vbs)/sizeof(struct vidbases)) - -/* Scan for PCI display adapter - if more than one card is present the last one is used for now */ - -#if LINUX_VERSION_CODE >= 0x020100 - -static int find_vga(void) -{ - unsigned short badr; - int found = 0, i, tga_type; - unsigned int vidadr=0; - struct pci_dev *dev; - - - for (dev = pci_devices; dev != NULL; dev = dev->next) - { - if (dev->class != PCI_CLASS_NOT_DEFINED_VGA && - ((dev->class) >> 16 != PCI_BASE_CLASS_DISPLAY)) - { - continue; - } - if (PCI_FUNC(dev->devfn) != 0) - continue; - - badr=0; - printk(KERN_INFO "bttv: PCI display adapter: "); - for (i=0; ivendor == vbs[i].vendor) - { - if (vbs[i].device) - if (vbs[i].device!=dev->device) - continue; - printk("%s.\n", vbs[i].name); - badr=vbs[i].badr; - break; - } - } - if (!badr) - { - printk(KERN_ERR "bttv: Unknown video memory base address.\n"); - continue; - } - pci_read_config_dword(dev, badr, &vidadr); - if (vidadr & PCI_BASE_ADDRESS_SPACE_IO) - { - printk(KERN_ERR "bttv: Memory seems to be I/O memory.\n"); - printk(KERN_ERR "bttv: Check entry for your card type in bttv.c vidbases struct.\n"); - continue; - } - vidadr &= PCI_BASE_ADDRESS_MEM_MASK; - if (!vidadr) - { - printk(KERN_ERR "bttv: Memory @ 0, must be something wrong!"); - continue; - } - - if (dev->vendor == PCI_VENDOR_ID_DEC && - dev->device == PCI_DEVICE_ID_DEC_TGA) - { - tga_type = (readl((unsigned long)vidadr) >> 12) & 0x0f; - if (tga_type != 0 && tga_type != 1 && tga_type != 3) - { - printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type); - found--; - } - vidadr+=dec_offsets[tga_type]; - } - DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr)); - DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", dev->devfn)); - found++; - } - - if (vidmem) - { - vidadr=vidmem<<20; - printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr); - found=1; - } - for (i=0; i> 16; -/* if (class == PCI_CLASS_DISPLAY_VGA) {*/ - if ((class>>8) == PCI_BASE_CLASS_DISPLAY || - /* Number 9 GXE64Pro needs this */ - class == PCI_CLASS_NOT_DEFINED_VGA) - { - badr=0; - printk(KERN_INFO "bttv: PCI display adapter: "); - for (i=0; i> 12) & 0x0f; - if (tga_type != 0 && tga_type != 1 && tga_type != 3) - { - printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type); - found--; - } - vidadr+=dec_offsets[tga_type]; - } - - DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr)); - DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", devfn)); - found++; - } - } - - if (vidmem) - { - if (vidmem < 0x1000) - vidadr=vidmem<<20; - else - vidadr=vidmem; - printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr); - found=1; - } - for (i=0; i= 0x020100 - static void handle_chipset(void) { struct pci_dev *dev = NULL; @@ -2876,78 +2740,6 @@ #endif } } -#else -static void handle_chipset(void) -{ - int index; - - for (index = 0; index < 8; index++) - { - unsigned char bus, devfn; - unsigned char b; - - /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ - - if (!pcibios_find_device(PCI_VENDOR_ID_SI, - PCI_DEVICE_ID_SI_496, - index, &bus, &devfn)) - { - printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); - } - - if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82441, - index, &bus, &devfn)) - { - pcibios_read_config_byte(bus, devfn, 0x53, &b); - DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); - DEBUG(printk("bufcon=0x%02x\n",b)); - } - - if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, - index, &bus, &devfn)) - { - printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); - triton1=BT848_INT_ETBF; - -#if 0 - /* The ETBF bit SHOULD make all this unnecessary */ - /* 430FX (Triton I) freezes with bus concurrency on -> switch it off */ - { - unsigned char bo; - - pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b); - bo=b; - DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b)); - - if(!(b & TRITON_BUS_CONCURRENCY)) - { - printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n"); - b |= TRITON_BUS_CONCURRENCY; - } - - if(b & TRITON_PEER_CONCURRENCY) - { - printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n"); - b &= ~TRITON_PEER_CONCURRENCY; - } - if(!(b & TRITON_STREAMING)) - { - printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n"); - b |= TRITON_STREAMING; - } - - if (b!=bo) - { - pcibios_write_config_byte(bus, devfn, TRITON_PCON, b); - printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b); - } - } -#endif - } - } -} -#endif static void init_tea6300(struct i2c_bus *bus) { @@ -3444,6 +3236,7 @@ btv->grf = btv->grf_next; btv->risc_jmp[5]=cpu_to_le32(btv->gro); btv->risc_jmp[11]=cpu_to_le32(btv->gre); + clip_cropwin(btv, btv->gwidth, btv->gheight); bt848_set_geo(btv, btv->gwidth, btv->gheight, btv->gfmt, 0); @@ -3451,7 +3244,9 @@ 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, + clip_cropwin(btv, btv->win.width, + btv->win.height); + bt848_set_geo(btv, btv->win.width, btv->win.height, btv->win.color_fmt, 0); } @@ -3463,7 +3258,8 @@ btv->risc_jmp[5]=cpu_to_le32(btv->gro); 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, + clip_cropwin(btv, btv->gwidth, btv->gheight); + bt848_set_geo(btv, btv->gwidth, btv->gheight, btv->gfmt, 0); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.2.17/drivers/char/bttv.h Wed May 3 22:26:11 2000 +++ linux/drivers/char/bttv.h Sat Dec 9 21:25:43 2000 @@ -40,7 +40,7 @@ #define VBIBUF_SIZE 65536 /* maximum needed buffer size for extended VBI frame mode capturing */ -#define BTTV_MAX_FBUF 0x190000 +#define BTTV_MAX_FBUF 0x208000 #ifdef __KERNEL__ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/buz.c linux/drivers/char/buz.c --- v2.2.17/drivers/char/buz.c Fri Apr 21 12:45:51 2000 +++ linux/drivers/char/buz.c Wed Nov 8 22:52:33 2000 @@ -201,6 +201,7 @@ mem_map_reserve(MAP_NR(mem + off)); DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem))); } else { + v4l_fbuffer_free(zr); return -ENOBUFS; } } @@ -2389,7 +2390,7 @@ case VIDIOCSCHAN: { struct video_channel v; - int input; + int input, norm; int on, res; if (copy_from_user(&v, arg, sizeof(v))) { @@ -2421,9 +2422,10 @@ if (on) zr36057_overlay(zr, 0); + norm = zr->params.norm; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm); if (on) zr36057_overlay(zr, 1); @@ -2781,7 +2783,7 @@ case BUZIOC_S_PARAMS: { struct zoran_params bp; - int input, on; + int input, on, norm; if (zr->codec_mode != BUZ_MODE_IDLE) { return -EINVAL; @@ -2808,9 +2810,10 @@ zr36057_overlay(zr, 0); input = zr->params.input == 0 ? 3 : 7; + norm = zr->params.norm; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm); if (on) zr36057_overlay(zr, 1); @@ -2939,8 +2942,9 @@ /* restore previous input and norm */ input = zr->params.input == 0 ? 3 : 7; + norm = zr->params.norm; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); if (copy_to_user(arg, &bs, sizeof(bs))) { return -EFAULT; @@ -3252,8 +3256,9 @@ j = zr->params.input == 0 ? 3 : 7; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + j = zr->params.norm; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &j); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &j); /* set individual interrupt enables (without GIRQ0) but don't global enable until zoran_open() */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.2.17/drivers/char/bw-qcam.c Fri Apr 21 12:45:51 2000 +++ linux/drivers/char/bw-qcam.c Sat Nov 18 00:46:36 2000 @@ -867,12 +867,9 @@ case VIDIOCGWIN: { struct video_window vw; - vw.x=0; - vw.y=0; + memset(&vw, 0, sizeof(vw)); vw.width=qcam->width/qcam->transfer_scale; vw.height=qcam->height/qcam->transfer_scale; - vw.chromakey=0; - vw.flags=0; if(copy_to_user(arg, &vw, sizeof(vw))) return -EFAULT; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.2.17/drivers/char/c-qcam.c Fri Apr 21 12:45:51 2000 +++ linux/drivers/char/c-qcam.c Sat Nov 18 00:46:54 2000 @@ -612,12 +612,9 @@ case VIDIOCGWIN: { struct video_window vw; - vw.x=0; - vw.y=0; + memset(&vw, 0, sizeof(vw)); vw.width=qcam->width; vw.height=qcam->height; - vw.chromakey=0; - vw.flags=0; if(copy_to_user(arg, &vw, sizeof(vw))) return -EFAULT; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/console.c linux/drivers/char/console.c --- v2.2.17/drivers/char/console.c Sat Sep 9 18:42:34 2000 +++ linux/drivers/char/console.c Wed Nov 8 23:03:17 2000 @@ -575,10 +575,12 @@ } if (redraw) { + int update; + set_origin(currcons); + update = sw->con_switch(vc_cons[currcons].d); set_palette(currcons); - if (sw->con_switch(vc_cons[currcons].d) && vcmode != KD_GRAPHICS) - /* Update the screen contents */ + if (update && vcmode != KD_GRAPHICS) do_update_region(currcons, origin, screenbuf_size/2); } set_cursor(currcons); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/cpia.c linux/drivers/char/cpia.c --- v2.2.17/drivers/char/cpia.c Sun Jun 11 21:44:12 2000 +++ linux/drivers/char/cpia.c Tue Sep 5 23:08:25 2000 @@ -3,9 +3,9 @@ * * Supports CPiA based Video Camera's. * - * (C) 1999 Peter Pregler, - * Scott J. Bertin, - * Johannes Erdfelt + * (C) Copyright 1999-2000 Peter Pregler, + * (C) Copyright 1999-2000 Scott J. Bertin, + * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,28 +22,28 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* #define _CPIA_DEBUG_ define for verbose debug output */ #include #include +#include #include -#include #include #include -#include #include -#include +#include #include #include -#include +#include #include #include +#include #ifdef CONFIG_KMOD #include #endif -#undef _CPIA_DEBUG_ /* define for verbose debug output */ -#include +#include "cpia.h" #ifdef CONFIG_VIDEO_CPIA_PP extern int cpia_pp_init(void); @@ -53,7 +53,7 @@ #endif #ifdef MODULE -MODULE_AUTHOR("Scott J. Bertin & Peter Pregler "); +MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras"); MODULE_SUPPORTED_DEVICE("video"); #endif @@ -97,6 +97,7 @@ #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13) #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1) +#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2) #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3) #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4) #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6) @@ -127,6 +128,7 @@ #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12) #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13) #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14) +#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15) #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1) #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4) @@ -135,117 +137,7 @@ #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8) #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9) #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10) - -struct cam_params { - struct { - u8 firmwareVersion; - u8 firmwareRevision; - u8 vcVersion; - u8 vcRevision; - } version; - struct { - u16 vendor; - u16 product; - u16 deviceRevision; - } pnpID; - struct { - u8 vpVersion; - u8 vpRevision; - u16 cameraHeadID; - } vpVersion; - struct { - u8 systemState; - u8 grabState; - u8 streamState; - u8 fatalError; - u8 cmdError; - u8 debugFlags; - u8 vpStatus; - u8 errorCode; - } status; - struct { - u8 brightness; - u8 contrast; - u8 saturation; - } colourParams; - struct { - u8 gainMode; - u8 expMode; - u8 compMode; - u8 centreWeight; - u8 gain; - u8 fineExp; - u8 coarseExpLo; - u8 coarseExpHi; - u8 redComp; - u8 green1Comp; - u8 green2Comp; - u8 blueComp; - } exposure; - struct { - u8 balanceMode; - u8 redGain; - u8 greenGain; - u8 blueGain; - } colourBalance; - struct { - u8 divisor; - u8 baserate; - } sensorFps; - struct { - u8 gain1; - u8 gain2; - u8 gain4; - u8 gain8; - } apcor; - struct { - u8 flickerMode; - u8 coarseJump; - u8 allowableOverExposure; - } flickerControl; - struct { - u8 gain1; - u8 gain2; - u8 gain4; - u8 gain8; - } vlOffset; - struct { - u8 mode; - u8 decimation; - } compression; - struct { - u8 frTargeting; - u8 targetFR; - u8 targetQ; - } compressionTarget; - struct { - u8 yThreshold; - u8 uvThreshold; - } yuvThreshold; - struct { - u8 hysteresis; - u8 threshMax; - u8 smallStep; - u8 largeStep; - u8 decimationHysteresis; - u8 frDiffStepThresh; - u8 qDiffStepThresh; - u8 decimationThreshMod; - } compressionParams; - struct { - u8 videoSize; /* CIF/QCIF */ - u8 subSample; - u8 yuvOrder; - } format; - struct { - u8 colStart; /* skip first 8*colStart pixels */ - u8 colEnd; /* finish at 8*colEnd pixels */ - u8 rowStart; /* skip first 4*rowStart lines */ - u8 rowEnd; /* finish at 4*rowEnd lines */ - } roi; - u8 ecpTiming; - u8 streamStartLine; -}; +#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11) enum { FRAME_READY, /* Ready to grab into */ @@ -254,24 +146,6 @@ FRAME_UNUSED, /* Unused (no MCAPTURE) */ }; -#define FRAME_NUM 2 /* double buffering for now */ -struct cpia_frame { - u8 *data; - int count; - int width; - int height; - volatile int state; -}; - -enum v4l_camstates { - CPIA_V4L_IDLE = 0, - CPIA_V4L_ERROR, - CPIA_V4L_COMMAND, - CPIA_V4L_GRABBING, - CPIA_V4L_STREAMING, - CPIA_V4L_STREAMING_PAUSED, -}; - #define COMMAND_NONE 0x0000 #define COMMAND_SETCOMPRESSION 0x0001 #define COMMAND_SETCOMPRESSIONTARGET 0x0002 @@ -288,45 +162,7 @@ #define COMMAND_SETAPCOR 0x1000 #define COMMAND_SETFLICKERCTRL 0x2000 #define COMMAND_SETVLOFFSET 0x4000 - -struct cam_data { - int index; /* which camera is this */ - struct semaphore busy_lock; /* guard against SMP multithreading */ - struct cpia_camera_ops *ops; /* lowlevel driver operations */ - void *lowlevel_data; /* private data for lowlevel driver */ - u8 *raw_image; /* buffer for raw image data */ - struct cpia_frame decompressed_frame; - /* buffer to hold decompressed frame */ - int image_size; /* sizeof last decompressed image */ - int open_count; /* # of process that have camera open */ - /* camera status */ - int fps; /* actual fps reported by the camera */ - int transfer_rate; /* transfer rate from camera in kB/s */ - u8 mainsFreq; /* for flicker control */ - - /* proc interface */ - struct semaphore param_lock; /* params lock for this camera */ - struct cam_params params; /* camera settings */ - struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */ - - /* v4l */ - int video_size; /* VIDEO_SIZE_ */ - volatile enum v4l_camstates camstate; /* v4l layer status */ - struct video_device vdev; /* v4l videodev */ - struct video_picture vp; /* v4l camera settings */ - struct video_window vw; /* v4l capture area */ - - /* mmap interface */ - int curframe; /* the current frame to grab into */ - u8 *frame_buf; /* frame buffer data */ - struct cpia_frame frame[FRAME_NUM]; - /* FRAME_NUM-buffering, so we need a array */ - - int first_frame; - volatile u32 cmd_queue; /* queued commands */ -}; - -static struct cam_data *camera[CPIA_MAXCAMS] ={ [0 ... CPIA_MAXCAMS-1] = NULL }; +#define COMMAND_SETLIGHTS 0x8000 /* GA 04/14/00 */ /* Developer's Guide Table 5 p 3-34 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ @@ -338,6 +174,7 @@ /* forward declaration of local function */ static void reset_camera_struct(struct cam_data *cam); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) /********************************************************************** * * Memory management @@ -357,64 +194,134 @@ pte_t *ptep, pte; pgd = pgd_offset(current->mm, adr); - if (pgd_none(*pgd)) return 0; + if (pgd_none(*pgd)) + return 0; pmd = pmd_offset(pgd, adr); - if (pmd_none(*pmd)) return 0; + if (pmd_none(*pmd)) + return 0; ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); pte = *ptep; - if(pte_present(pte)) - return - virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); + if (pte_present(pte)) + return virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); return 0; } -static inline unsigned long kvirt_to_phys(unsigned long adr) +static inline unsigned long kvirt_to_pa(unsigned long adr) { return uvirt_to_phys(VMALLOC_VMADDR(adr)); } -static void * rvmalloc(unsigned long size) +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */ + +/********************************************************************** + * + * Memory management + * + * This is a shameless copy from the USB-cpia driver (linux kernel + * version 2.3.29 or so, I have no idea what this code actually does ;). + * Actually it seems to be a copy of a shameless copy of the bttv-driver. + * Or that is a copy of a shameless copy of ... (To the powers: is there + * no generic kernel-function to do this sort of stuff?) + * + * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says + * there will be one, but apparentely not yet - jerdfelt + * + **********************************************************************/ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if (pte_present(pte)) + ret = page_address(pte_page(pte)) | + (adr & (PAGE_SIZE-1)); + } + } + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */ + +static void *rvmalloc(unsigned long size) { - void * mem; + void *mem; unsigned long adr, page; + /* Round it off to PAGE_SIZE */ size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - mem=vmalloc(size); - if (mem) { - /* Clear the ram out, no junk to the user */ - memset(mem, 0, size); - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_phys(adr); - mem_map_reserve(MAP_NR(phys_to_virt(page))); - adr+=PAGE_SIZE; - if (size > PAGE_SIZE) size-=PAGE_SIZE; - else size=0; - } + mem = vmalloc(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + mem_map_reserve(MAP_NR(phys_to_virt(page))); +#else + mem_map_reserve(MAP_NR(__va(page))); +#endif + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; } + return mem; } -static void rvfree(void * mem, unsigned long size) +static void rvfree(void *mem, unsigned long size) { unsigned long adr, page; - + + if (!mem) + return; + size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - if (mem) { - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_phys(adr); - mem_map_unreserve(MAP_NR(phys_to_virt(page))); - adr+=PAGE_SIZE; - if (size > PAGE_SIZE) size-=PAGE_SIZE; - else size=0; - } - vfree(mem); + adr = (unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + mem_map_unreserve(MAP_NR(phys_to_virt(page))); +#else + mem_map_unreserve(MAP_NR(__va(page))); +#endif + adr += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; } + vfree(mem); } /********************************************************************** @@ -422,6 +329,7 @@ * /proc interface * **********************************************************************/ +#ifdef CONFIG_PROC_FS static struct proc_dir_entry *cpia_proc_root=NULL; static int cpia_read_proc(char *page, char **start, off_t off, @@ -432,7 +340,7 @@ struct cam_data *cam = data; char tmpstr[20]; - /* IMPORTANT: This output MUST be kept under 4k (FIXME: PAGE_SIZE?) + /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ out += sprintf(out, "read-only\n-----------------------\n"); @@ -467,22 +375,23 @@ cam->params.status.vpStatus); out += sprintf(out, "error_code: %#04x\n", cam->params.status.errorCode); + /* GA 04/14/00 - QX3 specific entries */ + if (cam->params.qx3.qx3_detected) { + out += sprintf(out, "button: %4d\n", + cam->params.qx3.button); + out += sprintf(out, "cradled: %4d\n", + cam->params.qx3.cradled); + } out += sprintf(out, "video_size: %s\n", cam->params.format.videoSize == VIDEOSIZE_CIF ? "CIF " : "QCIF"); - out += sprintf(out, "sub_sample: %s\n", - cam->params.format.subSample == SUBSAMPLE_420 ? - "420" : "422"); - out += sprintf(out, "yuv_order: %s\n", - cam->params.format.yuvOrder == YUVORDER_YUYV ? - "YUYV" : "UYVY"); out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n", cam->params.roi.colStart*8, cam->params.roi.rowStart*4, cam->params.roi.colEnd*8, cam->params.roi.rowEnd*4); - out += sprintf(out, "actual_fps: %d\n", cam->fps); - out += sprintf(out, "transfer_rate: %dkB/s\n", + out += sprintf(out, "actual_fps: %3d\n", cam->fps); + out += sprintf(out, "transfer_rate: %4dkB/s\n", cam->transfer_rate); out += sprintf(out, "\nread-write\n"); @@ -490,13 +399,13 @@ " max default comment\n"); out += sprintf(out, "brightness: %8d %8d %8d %8d\n", cam->params.colourParams.brightness, 0, 100, 50); - if(cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) { + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) /* 1-02 firmware limits contrast to 80 */ tmp = 80; - } else { + else tmp = 96; - } + out += sprintf(out, "contrast: %8d %8d %8d %8d" " steps of 8\n", cam->params.colourParams.contrast, 0, tmp, 48); @@ -510,21 +419,20 @@ 2*cam->params.streamStartLine, 0, cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144, cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120); + out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n", + cam->params.format.subSample == SUBSAMPLE_420 ? + "420" : "422", "420", "422", "422"); + out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n", + cam->params.format.yuvOrder == YUVORDER_YUYV ? + "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV"); out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n", cam->params.ecpTiming ? "slow" : "normal", "slow", "normal", "normal"); - switch(cam->params.colourBalance.balanceMode) { - case 1: - // FIXME case 3: - sprintf(tmpstr, "manual"); - break; - case 2: + if (cam->params.colourBalance.balanceModeIsAuto) { sprintf(tmpstr, "auto"); - break; - default: - sprintf(tmpstr, "unknown"); - break; + } else { + sprintf(tmpstr, "manual"); } out += sprintf(out, "color_balance_mode: %8s %8s %8s" " %8s\n", tmpstr, "manual", "auto", "auto"); @@ -535,20 +443,20 @@ out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n", cam->params.colourBalance.blueGain, 0, 212, 92); - if(cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) { + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) /* 1-02 firmware limits gain to 2 */ sprintf(tmpstr, "%8d %8d", 1, 2); - } else { + else sprintf(tmpstr, "%8d %8d", 1, 8); - } - if(cam->params.exposure.gainMode == 0) { + + if (cam->params.exposure.gainMode == 0) out += sprintf(out, "max_gain: unknown %18s" " %8d powers of 2\n", tmpstr, 2); - } else { + else out += sprintf(out, "max_gain: %8d %18s %8d powers of 2\n", 1<<(cam->params.exposure.gainMode-1), tmpstr, 2); - } + switch(cam->params.exposure.expMode) { case 1: case 3: @@ -568,22 +476,22 @@ "off", "on", "on"); out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n", 1<params.exposure.gain, 1, 1); - if(cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) { + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) /* 1-02 firmware limits fineExp to 127 */ tmp = 255; - } else { + else tmp = 511; - } + out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n", cam->params.exposure.fineExp*2, 0, tmp, 0); - if(cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2) { + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2) /* 1-02 firmware limits coarseExpHi to 0 */ tmp = 255; - } else { + else tmp = 65535; - } + out += sprintf(out, "coarse_exp: %8d %8d %8d" " %8d\n", cam->params.exposure.coarseExpLo+ 256*cam->params.exposure.coarseExpHi, 0, tmp, 185); @@ -637,9 +545,9 @@ break; } out += sprintf(out, " none,auto,manual auto\n"); - out += sprintf(out, "decimation: %8s %8s %8s %8s\n", + out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n", cam->params.compression.decimation == - DECIMATION_ENAB ? "on":"off", "off", "off", + DECIMATION_ENAB ? "on":"off", "off", "on", "off"); out += sprintf(out, "compression_target: %9s %9s %9s %9s\n", cam->params.compressionTarget.frTargeting == @@ -647,13 +555,13 @@ "framerate":"quality", "framerate", "quality", "quality"); out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n", - cam->params.compressionTarget.targetFR, 0, 30, 7); + cam->params.compressionTarget.targetFR, 1, 30, 15); out += sprintf(out, "target_quality: %8d %8d %8d %8d\n", - cam->params.compressionTarget.targetQ, 0, 255, 10); + cam->params.compressionTarget.targetQ, 1, 64, 5); out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n", - cam->params.yuvThreshold.yThreshold, 0, 31, 15); + cam->params.yuvThreshold.yThreshold, 0, 31, 6); out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n", - cam->params.yuvThreshold.uvThreshold, 0, 31, 15); + cam->params.yuvThreshold.uvThreshold, 0, 31, 6); out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n", cam->params.compressionParams.hysteresis, 0, 255, 3); out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n", @@ -674,15 +582,25 @@ out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n", cam->params.compressionParams.decimationThreshMod, 0, 255, 2); - + + /* GA 04/14/00 - QX3 specific entries */ + if (cam->params.qx3.qx3_detected) { + out += sprintf(out, "toplight: %8s %8s %8s %8s\n", + cam->params.qx3.toplight ? "on" : "off", + "off", "on", "off"); + out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n", + cam->params.qx3.bottomlight ? "on" : "off", + "off", "on", "off"); + } + len = out - page; len -= off; if (len < count) { *eof = 1; if (len <= 0) return 0; - } else { + } else len = count; - } + *start = page + off; return len; } @@ -692,16 +610,14 @@ { struct cam_data *cam = data; struct cam_params new_params; - int retval, len, colon_found; + int retval, find_colon; int size = count; - char *p; unsigned long val; u32 command_flags = 0; u8 new_mains; - if(down_interruptible(&cam->param_lock)) { + if (down_interruptible(&cam->param_lock)) return -ERESTARTSYS; - } /* * Skip over leading whitespace @@ -714,106 +630,112 @@ memcpy(&new_params, &cam->params, sizeof(struct cam_params)); new_mains = cam->mainsFreq; -#define MATCH(x) (len=strlen(x), len <= count && strncmp(buffer, x, len) == 0) +#define MATCH(x) \ + ({ \ + int _len = strlen(x), _ret, _colon_found; \ + _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \ + if (_ret) { \ + buffer += _len; \ + count -= _len; \ + if (find_colon) { \ + _colon_found = 0; \ + while (count && (*buffer == ' ' || *buffer == '\t' || \ + (!_colon_found && *buffer == ':'))) { \ + if (*buffer == ':') \ + _colon_found = 1; \ + --count; \ + ++buffer; \ + } \ + if (!count || !_colon_found) \ + retval = -EINVAL; \ + find_colon = 0; \ + } \ + } \ + _ret; \ + }) #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \ new_params.version.firmwareRevision == (y)) #define VALUE \ - simple_strtoul(buffer, &p, 0); \ - if(p == buffer) { \ - retval = -EINVAL; \ - } else { \ - count -= p-buffer; \ - buffer = p; \ - } -#define FIND_VALUE \ - buffer += len;\ - count -= len; \ - colon_found=0; \ - while(count && (*buffer == ' ' || *buffer == '\t' || \ - (!colon_found && *buffer == ':'))) { \ - if(*buffer == ':') colon_found = 1; \ - --count; \ - ++buffer; \ - } \ - if(!count || !colon_found) { \ - retval = -EINVAL; \ - } -#define FIND_END \ - if(retval == 0) { \ - while(count && isspace(*buffer) && *buffer != '\n'){ \ - --count; \ - ++buffer; \ + ({ \ + char *_p; \ + unsigned long int _ret; \ + _ret = simple_strtoul(buffer, &_p, 0); \ + if (_p == buffer) \ + retval = -EINVAL; \ + else { \ + count -= _p - buffer; \ + buffer = _p; \ } \ - if(count) { \ - if(*buffer != '\n' && *buffer != ';') { \ - retval = -EINVAL; \ - } else { \ - --count; \ - ++buffer; \ - } \ - } \ - } + _ret; \ + }) + retval = 0; - while(count && !retval) { - if(MATCH("brightness")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 100) - new_params.colourParams.brightness=val; - else retval = -EINVAL; + while (count && !retval) { + find_colon = 1; + if (MATCH("brightness")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 100) + new_params.colourParams.brightness = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURPARAMS; - FIND_END - } else if(MATCH("contrast")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 100) { + } else if (MATCH("contrast")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 100) { /* contrast is in steps of 8, so round*/ val = ((val + 3) / 8) * 8; /* 1-02 firmware limits contrast to 80*/ - if(FIRMWARE_VERSION(1,2) && val > 80) + if (FIRMWARE_VERSION(1,2) && val > 80) val = 80; + new_params.colourParams.contrast = val; - } else retval = -EINVAL; + } else + retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURPARAMS; - FIND_END - } else if(MATCH("saturation")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 100) - new_params.colourParams.saturation=val; - else retval = -EINVAL; + } else if (MATCH("saturation")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 100) + new_params.colourParams.saturation = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURPARAMS; - FIND_END - } else if(MATCH("sensor_fps")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("sensor_fps")) { + if (!retval) + val = VALUE; + + if (!retval) { /* find values so that sensorFPS is minimized, * but >= val */ - if(val > 30) { + if (val > 30) retval = -EINVAL; - } else if(val > 25) { + else if (val > 25) { new_params.sensorFps.divisor = 0; new_params.sensorFps.baserate = 1; - } else if(val > 15) { + } else if (val > 15) { new_params.sensorFps.divisor = 0; new_params.sensorFps.baserate = 0; - } else if(val > 12) { + } else if (val > 12) { new_params.sensorFps.divisor = 1; new_params.sensorFps.baserate = 1; - } else if(val > 7) { + } else if (val > 7) { new_params.sensorFps.divisor = 1; new_params.sensorFps.baserate = 0; - } else if(val > 6) { + } else if (val > 6) { new_params.sensorFps.divisor = 2; new_params.sensorFps.baserate = 1; - } else if(val > 3) { + } else if (val > 3) { new_params.sensorFps.divisor = 2; new_params.sensorFps.baserate = 0; } else { @@ -825,89 +747,100 @@ flicker_jumps[new_mains] [new_params.sensorFps.baserate] [new_params.sensorFps.divisor]; - if(new_params.flickerControl.flickerMode) + if (new_params.flickerControl.flickerMode) command_flags |= COMMAND_SETFLICKERCTRL; } command_flags |= COMMAND_SETSENSORFPS; - FIND_END - } else if(MATCH("stream_start_line")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("stream_start_line")) { + if (!retval) + val = VALUE; + + if (!retval) { int max_line = 288; - if(new_params.format.videoSize==VIDEOSIZE_QCIF) + + if (new_params.format.videoSize == VIDEOSIZE_QCIF) max_line = 144; - if(val <= max_line) + if (val <= max_line) new_params.streamStartLine = val/2; - else retval = -EINVAL; + else + retval = -EINVAL; } - FIND_END - } else if(MATCH("ecp_timing")) { - FIND_VALUE - if(!retval && MATCH("normal")) { - buffer += len; - count -= len; + } else if (MATCH("sub_sample")) { + if (!retval && MATCH("420")) + new_params.format.subSample = SUBSAMPLE_420; + else if (!retval && MATCH("422")) + new_params.format.subSample = SUBSAMPLE_422; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETFORMAT; + } else if (MATCH("yuv_order")) { + if (!retval && MATCH("YUYV")) + new_params.format.yuvOrder = YUVORDER_YUYV; + else if (!retval && MATCH("UYVY")) + new_params.format.yuvOrder = YUVORDER_UYVY; + else + retval = -EINVAL; + + command_flags |= COMMAND_SETFORMAT; + } else if (MATCH("ecp_timing")) { + if (!retval && MATCH("normal")) new_params.ecpTiming = 0; - } else if(!retval && MATCH("slow")) { - buffer += len; - count -= len; + else if (!retval && MATCH("slow")) new_params.ecpTiming = 1; - } else { + else retval = -EINVAL; - } + command_flags |= COMMAND_SETECPTIMING; - FIND_END - } else if(MATCH("color_balance_mode")) { - FIND_VALUE - if(!retval && MATCH("manual")) { - buffer += len; - count -= len; - new_params.colourBalance.balanceMode=1; - } else if(!retval && MATCH("auto")) { - buffer += len; - count -= len; - new_params.colourBalance.balanceMode=2; - } else { + } else if (MATCH("color_balance_mode")) { + if (!retval && MATCH("manual")) + new_params.colourBalance.balanceModeIsAuto = 0; + else if (!retval && MATCH("auto")) + new_params.colourBalance.balanceModeIsAuto = 1; + else retval = -EINVAL; - } + command_flags |= COMMAND_SETCOLOURBALANCE; - FIND_END - } else if(MATCH("red_gain")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 212) + } else if (MATCH("red_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 212) new_params.colourBalance.redGain = val; - else retval = -EINVAL; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURBALANCE; - FIND_END - } else if(MATCH("green_gain")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 212) - new_params.colourBalance.greenGain=val; - else retval = -EINVAL; + } else if (MATCH("green_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 212) + new_params.colourBalance.greenGain = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURBALANCE; - FIND_END - } else if(MATCH("blue_gain")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 212) + } else if (MATCH("blue_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 212) new_params.colourBalance.blueGain = val; - else retval = -EINVAL; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOLOURBALANCE; - FIND_END - } else if(MATCH("max_gain")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("max_gain")) { + if (!retval) + val = VALUE; + + if (!retval) { /* 1-02 firmware limits gain to 2 */ - if(FIRMWARE_VERSION(1,2) && val > 2) + if (FIRMWARE_VERSION(1,2) && val > 2) val = 2; switch(val) { case 1: @@ -928,44 +861,32 @@ } } command_flags |= COMMAND_SETEXPOSURE; - FIND_END - } else if(MATCH("exposure_mode")) { - FIND_VALUE - if(!retval && MATCH("auto")) { - buffer += len; - count -= len; + } else if (MATCH("exposure_mode")) { + if (!retval && MATCH("auto")) new_params.exposure.expMode = 2; - } else if(!retval && MATCH("manual")) { - buffer += len; - count -= len; - if(new_params.exposure.expMode == 2) + else if (!retval && MATCH("manual")) { + if (new_params.exposure.expMode == 2) new_params.exposure.expMode = 3; new_params.flickerControl.flickerMode = 0; command_flags |= COMMAND_SETFLICKERCTRL; - } else { + } else retval = -EINVAL; - } + command_flags |= COMMAND_SETEXPOSURE; - FIND_END - } else if(MATCH("centre_weight")) { - FIND_VALUE - if(!retval && MATCH("on")) { - buffer += len; - count -= len; + } else if (MATCH("centre_weight")) { + if (!retval && MATCH("on")) new_params.exposure.centreWeight = 1; - } else if(!retval && MATCH("off")) { - buffer += len; - count -= len; + else if (!retval && MATCH("off")) new_params.exposure.centreWeight = 2; - } else { + else retval = -EINVAL; - } + command_flags |= COMMAND_SETEXPOSURE; - FIND_END - } else if(MATCH("gain")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("gain")) { + if (!retval) + val = VALUE; + + if (!retval) { switch(val) { case 1: new_params.exposure.gain = 0; @@ -996,35 +917,36 @@ break; } command_flags |= COMMAND_SETEXPOSURE; - if(new_params.exposure.gain > - new_params.exposure.gainMode-1) + if (new_params.exposure.gain > + new_params.exposure.gainMode-1) retval = -EINVAL; } - FIND_END - } else if(MATCH("fine_exp")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val < 256) { + } else if (MATCH("fine_exp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 256) { /* 1-02 firmware limits fineExp to 127*/ - if(FIRMWARE_VERSION(1,2) && val > 127) + if (FIRMWARE_VERSION(1,2) && val > 127) val = 127; new_params.exposure.fineExp = val; new_params.exposure.expMode = 1; command_flags |= COMMAND_SETEXPOSURE; new_params.flickerControl.flickerMode = 0; command_flags |= COMMAND_SETFLICKERCTRL; - } else retval = -EINVAL; + } else + retval = -EINVAL; } - FIND_END - } else if(MATCH("coarse_exp")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val < 65536) { + } else if (MATCH("coarse_exp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 65536) { /* 1-02 firmware limits * coarseExp to 255 */ - if(FIRMWARE_VERSION(1,2) && val > 255) + if (FIRMWARE_VERSION(1,2) && val > 255) val = 255; new_params.exposure.coarseExpLo = val & 0xff; @@ -1034,353 +956,398 @@ command_flags |= COMMAND_SETEXPOSURE; new_params.flickerControl.flickerMode = 0; command_flags |= COMMAND_SETFLICKERCTRL; - } else retval = -EINVAL; + } else + retval = -EINVAL; } - FIND_END - } else if(MATCH("red_comp")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val >= 220 && val <= 255) { + } else if (MATCH("red_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 220 && val <= 255) { new_params.exposure.redComp = val; command_flags |= COMMAND_SETEXPOSURE; - } else retval = -EINVAL; + } else + retval = -EINVAL; } - FIND_END - } else if(MATCH("green1_comp")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val >= 214 && val <= 255) { + } else if (MATCH("green1_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 214 && val <= 255) { new_params.exposure.green1Comp = val; command_flags |= COMMAND_SETEXPOSURE; - } else retval = -EINVAL; + } else + retval = -EINVAL; } - FIND_END - } else if(MATCH("green2_comp")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val >= 214 && val <= 255) { + } else if (MATCH("green2_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 214 && val <= 255) { new_params.exposure.green2Comp = val; command_flags |= COMMAND_SETEXPOSURE; - } else retval = -EINVAL; + } else + retval = -EINVAL; } - FIND_END - } else if(MATCH("blue_comp")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val >= 230 && val <= 255) { + } else if (MATCH("blue_comp")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val >= 230 && val <= 255) { new_params.exposure.blueComp = val; command_flags |= COMMAND_SETEXPOSURE; - } else retval = -EINVAL; + } else + retval = -EINVAL; } - FIND_END - } else if(MATCH("apcor_gain1")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("apcor_gain1")) { + if (!retval) + val = VALUE; + + if (!retval) { command_flags |= COMMAND_SETAPCOR; - if(val <= 0xff) new_params.apcor.gain1 = val; - else retval = -EINVAL; + if (val <= 0xff) + new_params.apcor.gain1 = val; + else + retval = -EINVAL; } - FIND_END - } else if(MATCH("apcor_gain2")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("apcor_gain2")) { + if (!retval) + val = VALUE; + + if (!retval) { command_flags |= COMMAND_SETAPCOR; - if(val <= 0xff) new_params.apcor.gain2 = val; - else retval = -EINVAL; + if (val <= 0xff) + new_params.apcor.gain2 = val; + else + retval = -EINVAL; } - FIND_END - } else if(MATCH("apcor_gain4")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("apcor_gain4")) { + if (!retval) + val = VALUE; + + if (!retval) { command_flags |= COMMAND_SETAPCOR; - if(val <= 0xff) new_params.apcor.gain4 = val; - else retval = -EINVAL; + if (val <= 0xff) + new_params.apcor.gain4 = val; + else + retval = -EINVAL; } - FIND_END - } else if(MATCH("apcor_gain8")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { + } else if (MATCH("apcor_gain8")) { + if (!retval) + val = VALUE; + + if (!retval) { command_flags |= COMMAND_SETAPCOR; - if(val <= 0xff) new_params.apcor.gain8 = val; - else retval = -EINVAL; + if (val <= 0xff) + new_params.apcor.gain8 = val; + else + retval = -EINVAL; } - FIND_END - } else if(MATCH("vl_offset_gain1")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 0xff) new_params.vlOffset.gain1 = val; - else retval = -EINVAL; + } else if (MATCH("vl_offset_gain1")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain1 = val; + else + retval = -EINVAL; } - FIND_END command_flags |= COMMAND_SETVLOFFSET; - } else if(MATCH("vl_offset_gain2")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 0xff) new_params.vlOffset.gain2 = val; - else retval = -EINVAL; + } else if (MATCH("vl_offset_gain2")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain2 = val; + else + retval = -EINVAL; } - FIND_END command_flags |= COMMAND_SETVLOFFSET; - } else if(MATCH("vl_offset_gain4")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 0xff) new_params.vlOffset.gain4 = val; - else retval = -EINVAL; + } else if (MATCH("vl_offset_gain4")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain4 = val; + else + retval = -EINVAL; } - FIND_END command_flags |= COMMAND_SETVLOFFSET; - } else if(MATCH("vl_offset_gain8")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 0xff) new_params.vlOffset.gain8 = val; - else retval = -EINVAL; + } else if (MATCH("vl_offset_gain8")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.vlOffset.gain8 = val; + else + retval = -EINVAL; } - FIND_END command_flags |= COMMAND_SETVLOFFSET; - } else if(MATCH("flicker_control")) { - FIND_VALUE - if(!retval && MATCH("on")) { - buffer += len; - count -= len; + } else if (MATCH("flicker_control")) { + if (!retval && MATCH("on")) { new_params.flickerControl.flickerMode = 1; new_params.exposure.expMode = 2; command_flags |= COMMAND_SETEXPOSURE; - } else if(!retval && MATCH("off")) { - buffer += len; - count -= len; + } else if (!retval && MATCH("off")) new_params.flickerControl.flickerMode = 0; - } else { + else retval = -EINVAL; - } + command_flags |= COMMAND_SETFLICKERCTRL; - FIND_END - } else if(MATCH("mains_frequency")) { - FIND_VALUE - if(!retval && MATCH("50")) { - buffer += len; - count -= len; + } else if (MATCH("mains_frequency")) { + if (!retval && MATCH("50")) { new_mains = 0; new_params.flickerControl.coarseJump = flicker_jumps[new_mains] [new_params.sensorFps.baserate] [new_params.sensorFps.divisor]; - if(new_params.flickerControl.flickerMode) + if (new_params.flickerControl.flickerMode) command_flags |= COMMAND_SETFLICKERCTRL; - } else if(!retval && MATCH("60")) { - buffer += len; - count -= len; + } else if (!retval && MATCH("60")) { new_mains = 1; new_params.flickerControl.coarseJump = flicker_jumps[new_mains] [new_params.sensorFps.baserate] [new_params.sensorFps.divisor]; - if(new_params.flickerControl.flickerMode) + if (new_params.flickerControl.flickerMode) command_flags |= COMMAND_SETFLICKERCTRL; - } else { + } else retval = -EINVAL; - } - FIND_END - } else if(MATCH("allowable_overexposure")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val <= 0xff) { + } else if (MATCH("allowable_overexposure")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) { new_params.flickerControl. allowableOverExposure = val; command_flags |= COMMAND_SETFLICKERCTRL; - } else retval = -EINVAL; + } else + retval = -EINVAL; } - FIND_END - } else if(MATCH("compression_mode")) { - FIND_VALUE - if(!retval && MATCH("none")) { - buffer += len; - count -= len; + } else if (MATCH("compression_mode")) { + if (!retval && MATCH("none")) new_params.compression.mode = CPIA_COMPRESSION_NONE; - } else if(!retval && MATCH("auto")) { - buffer += len; - count -= len; + else if (!retval && MATCH("auto")) new_params.compression.mode = CPIA_COMPRESSION_AUTO; - } else if(!retval && MATCH("manual")) { - buffer += len; - count -= len; + else if (!retval && MATCH("manual")) new_params.compression.mode = CPIA_COMPRESSION_MANUAL; - } else { + else retval = -EINVAL; - } + command_flags |= COMMAND_SETCOMPRESSION; - FIND_END - } else if(MATCH("decimation")) { - FIND_VALUE - if(!retval && MATCH("off")) { - buffer += len; - count -= len; + } else if (MATCH("decimation_enable")) { + if (!retval && MATCH("off")) new_params.compression.decimation = 0; - } else { + else if (!retval && MATCH("on")) + new_params.compression.decimation = 1; + else retval = -EINVAL; - } + command_flags |= COMMAND_SETCOMPRESSION; - FIND_END - } else if(MATCH("compression_target")) { - FIND_VALUE - if(!retval && MATCH("quality")) { - buffer += len; - count -= len; + } else if (MATCH("compression_target")) { + if (!retval && MATCH("quality")) new_params.compressionTarget.frTargeting = CPIA_COMPRESSION_TARGET_QUALITY; - } else if(!retval && MATCH("framerate")) { - buffer += len; - count -= len; + else if (!retval && MATCH("framerate")) new_params.compressionTarget.frTargeting = CPIA_COMPRESSION_TARGET_FRAMERATE; - } else { + else retval = -EINVAL; - } + command_flags |= COMMAND_SETCOMPRESSIONTARGET; - FIND_END - } else if(MATCH("target_framerate")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) - new_params.compressionTarget.targetFR = val; + } else if (MATCH("target_framerate")) { + if (!retval) + val = VALUE; + + if (!retval) { + if(val > 0 && val <= 30) + new_params.compressionTarget.targetFR = val; + else + retval = -EINVAL; + } command_flags |= COMMAND_SETCOMPRESSIONTARGET; - FIND_END - } else if(MATCH("target_quality")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) new_params.compressionTarget.targetQ = val; + } else if (MATCH("target_quality")) { + if (!retval) + val = VALUE; + + if (!retval) { + if(val > 0 && val <= 64) + new_params.compressionTarget.targetQ = val; + else + retval = -EINVAL; + } command_flags |= COMMAND_SETCOMPRESSIONTARGET; - FIND_END - } else if(MATCH("y_threshold")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val < 32) - new_params.yuvThreshold.yThreshold=val; - else retval = -EINVAL; + } else if (MATCH("y_threshold")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 32) + new_params.yuvThreshold.yThreshold = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETYUVTHRESH; - FIND_END - } else if(MATCH("uv_threshold")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(val < 32) - new_params.yuvThreshold.uvThreshold=val; - else retval = -EINVAL; + } else if (MATCH("uv_threshold")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val < 32) + new_params.yuvThreshold.uvThreshold = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETYUVTHRESH; - FIND_END - } else if(MATCH("hysteresis")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams.hysteresis=val; - else retval = -EINVAL; + } else if (MATCH("hysteresis")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.hysteresis = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END - } else if(MATCH("threshold_max")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams.threshMax=val; - else retval = -EINVAL; + } else if (MATCH("threshold_max")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.threshMax = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END - } else if(MATCH("small_step")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams.smallStep=val; - else retval = -EINVAL; + } else if (MATCH("small_step")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.smallStep = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END - } else if(MATCH("large_step")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams.largeStep=val; - else retval = -EINVAL; + } else if (MATCH("large_step")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.largeStep = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END - } else if(MATCH("decimation_hysteresis")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams. - decimationHysteresis = val; - else retval = -EINVAL; + } else if (MATCH("decimation_hysteresis")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.decimationHysteresis = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END - } else if(MATCH("fr_diff_step_thresh")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams. - frDiffStepThresh = val; - else retval = -EINVAL; + } else if (MATCH("fr_diff_step_thresh")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.frDiffStepThresh = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END - } else if(MATCH("q_diff_step_thresh")) { - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams. - qDiffStepThresh = val; - else retval = -EINVAL; - command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END - } else if(MATCH("decimation_thresh_mod")) { + } else if (MATCH("q_diff_step_thresh")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.qDiffStepThresh = val; + else + retval = -EINVAL; } - FIND_VALUE - if(!retval) { val = VALUE } - if(!retval) { - if(retval <= 0xff) - new_params.compressionParams. - decimationThreshMod = val; - else retval = -EINVAL; + command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("decimation_thresh_mod")) { + if (!retval) + val = VALUE; + + if (!retval) { + if (val <= 0xff) + new_params.compressionParams.decimationThreshMod = val; + else + retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; - FIND_END + } else if (MATCH("toplight")) { /* GA 4/14/00 */ + if (!retval && MATCH("on")) + new_params.qx3.toplight = 1; + + else if (!retval && MATCH("off")) + new_params.qx3.toplight = 0; + + else + retval = -EINVAL; + command_flags |= COMMAND_SETLIGHTS; + + } else if (MATCH("bottomlight")) { /* GA 4/14/00 */ + if (!retval && MATCH("on")) + new_params.qx3.bottomlight = 1; + + else if (!retval && MATCH("off")) + new_params.qx3.bottomlight = 0; + + else + retval = -EINVAL; + command_flags |= COMMAND_SETLIGHTS; + } else { + DBG("No match found\n"); retval = -EINVAL; } + + if (!retval) { + while (count && isspace(*buffer) && *buffer != '\n') { + --count; + ++buffer; + } + if (count) { + if (*buffer != '\n' && *buffer != ';') + retval = -EINVAL; + else { + --count; + ++buffer; + } + } + } } #undef MATCH #undef FIRMWARE_VERSION #undef VALUE #undef FIND_VALUE #undef FIND_END - if(retval == 0) { - if(command_flags & COMMAND_SETCOLOURPARAMS) { + if (!retval) { + if (command_flags & COMMAND_SETCOLOURPARAMS) { /* Adjust cam->vp to reflect these changes */ cam->vp.brightness = new_params.colourParams.brightness*65535/100; @@ -1394,9 +1361,8 @@ cam->mainsFreq = new_mains; cam->cmd_queue |= command_flags; retval = size; - } else { + } else DBG("error: %d\n", retval); - } up(&cam->param_lock); @@ -1408,17 +1374,21 @@ char name[7]; struct proc_dir_entry *ent; - if(cpia_proc_root == NULL || cam == NULL) { + if (!cpia_proc_root || !cam) return; - } + sprintf(name, "video%d", cam->vdev.minor); ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root); - if (!ent) return; + if (!ent) + return; + ent->data = cam; ent->read_proc = cpia_read_proc; ent->write_proc = cpia_write_proc; - ent->size = 3623; + ent->size = 3736; + if (cam->params.qx3.qx3_detected) + ent->size += 188; cam->proc_entry = ent; } @@ -1426,16 +1396,43 @@ { char name[7]; - if(cam == NULL || cam->proc_entry == NULL) return; + if (!cam || !cam->proc_entry) + return; sprintf(name, "video%d", cam->vdev.minor); remove_proc_entry(name, cpia_proc_root); cam->proc_entry = NULL; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) +/* + * This is called as the fill_inode function when an inode + * is going into (fill = 1) or out of service (fill = 0). + * We use it here to manage the module use counts. + */ +static void proc_cpia_modcount(struct inode *inode, int fill) +{ +#ifdef MODULE + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +#endif +} +#endif + static void proc_cpia_create(void) { cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0); + + if (cpia_proc_root) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + cpia_proc_root->fill_inode = &proc_cpia_modcount; +#else + cpia_proc_root->owner = THIS_MODULE; +#endif + } else + LOG("Unable to initialise /proc/cpia\n"); } #ifdef MODULE @@ -1444,6 +1441,7 @@ remove_proc_entry("cpia", 0); } #endif +#endif /* CONFIG_PROC_FS */ /* ----------------------- debug functions ---------------------- */ @@ -1473,39 +1471,41 @@ { /* return the best match, where 'best' is as always * the largest that is not bigger than what is requested. */ - if(width>=352 && height>=288) { + if (width>=352 && height>=288) return VIDEOSIZE_352_288; /* CIF */ - } - if(width>=320 && height>=240) { + + if (width>=320 && height>=240) return VIDEOSIZE_320_240; /* SIF */ - } - if(width>=288 && height>=216) { + + if (width>=288 && height>=216) return VIDEOSIZE_288_216; - } - if(width>=256 && height>=192) { + + if (width>=256 && height>=192) return VIDEOSIZE_256_192; - } - if(width>=224 && height>=168) { + + if (width>=224 && height>=168) return VIDEOSIZE_224_168; - } - if(width>=192 && height>=144) { + + if (width>=192 && height>=144) return VIDEOSIZE_192_144; - } - if(width>=176 && height>=144) { + + if (width>=176 && height>=144) return VIDEOSIZE_176_144; /* QCIF */ - } - if(width>=160 && height>=120) { + + if (width>=160 && height>=120) return VIDEOSIZE_160_120; /* QSIF */ - } - if(width>=128 && height>=96) { + + if (width>=128 && height>=96) return VIDEOSIZE_128_96; - } - if(width>=64 && height>=48) { + + if (width>=88 && height>=72) + return VIDEOSIZE_88_72; + + if (width>=64 && height>=48) return VIDEOSIZE_64_48; - } - if(width>=48 && height>=48) { + + if (width>=48 && height>=48) return VIDEOSIZE_48_48; - } return -1; } @@ -1608,6 +1608,16 @@ cam->params.roi.rowEnd=30; cam->params.streamStartLine = 60; break; + case VIDEOSIZE_88_72: + cam->vw.width = 88; + cam->vw.height = 72; + cam->params.format.videoSize=VIDEOSIZE_QCIF; + cam->params.roi.colStart=5; + cam->params.roi.colEnd=16; + cam->params.roi.rowStart=9; + cam->params.roi.rowEnd=27; + cam->params.streamStartLine = 60; + break; case VIDEOSIZE_64_48: cam->vw.width = 64; cam->vw.height = 48; @@ -1635,27 +1645,29 @@ return; } -static int allocate_frame_buf(struct cam_data *cam) { +static int allocate_frame_buf(struct cam_data *cam) +{ int i; - cam->frame_buf = rvmalloc(FRAME_NUM*CPIA_MAX_FRAME_SIZE); - if (!cam->frame_buf) { + cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE); + if (!cam->frame_buf) return -ENOBUFS; - } - for( i=0; iframe[i].data = cam->frame_buf + i*CPIA_MAX_FRAME_SIZE; - } + + for (i = 0; i < FRAME_NUM; i++) + cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE; + return 0; } -static int free_frame_buf(struct cam_data *cam) { +static int free_frame_buf(struct cam_data *cam) +{ int i; rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE); - cam->frame_buf=0; - for( i=0; iframe_buf = 0; + for (i=0; i < FRAME_NUM; i++) cam->frame[i].data = NULL; - } + return 0; } @@ -1663,9 +1675,9 @@ static void inline free_frames(struct cpia_frame frame[FRAME_NUM]) { int i; - for( i=0; iparam_lock); datasize=8; break; + case CPIA_COMMAND_ReadMCPorts: /* GA 4/14/00 */ + case CPIA_COMMAND_ReadVCRegs: + datasize = 4; + break; default: datasize=0; break; @@ -1708,12 +1724,12 @@ cmd[7] = 0; retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); - if(retval) { - LOG("%x - failed\n", command); + if (retval) { + DBG("%x - failed, retval=%d\n", command, retval); if (command == CPIA_COMMAND_GetColourParams || command == CPIA_COMMAND_GetColourBalance || command == CPIA_COMMAND_GetExposure) - up(&cam->param_lock); + up(&cam->param_lock); } else { switch(command) { case CPIA_COMMAND_GetCPIAVersion: @@ -1765,9 +1781,48 @@ cam->params.exposure.green1Comp = data[5]; cam->params.exposure.green2Comp = data[6]; cam->params.exposure.blueComp = data[7]; + /* If the *Comp parameters are wacko, generate + * a warning, and reset them back to default + * values. - rich@annexia.org + */ + if (cam->params.exposure.redComp < 220 || + cam->params.exposure.redComp > 255 || + cam->params.exposure.green1Comp < 214 || + cam->params.exposure.green1Comp > 255 || + cam->params.exposure.green2Comp < 214 || + cam->params.exposure.green2Comp > 255 || + cam->params.exposure.blueComp < 230 || + cam->params.exposure.blueComp > 255) + { + printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n", + cam->params.exposure.redComp, + cam->params.exposure.green1Comp, + cam->params.exposure.green2Comp, + cam->params.exposure.blueComp); + cam->params.exposure.redComp = 220; + cam->params.exposure.green1Comp = 214; + cam->params.exposure.green2Comp = 214; + cam->params.exposure.blueComp = 230; + } up(&cam->param_lock); break; - default: + + case CPIA_COMMAND_ReadMCPorts: /* GA 04/14/00 */ + if (!cam->params.qx3.qx3_detected) break; + + /* test button press */ + cam->params.qx3.button = ((data[1] & 0x02) == 0); + if (cam->params.qx3.button) { + /* button pressed - unlock the latch */ + do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0); + do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0); + } + + /* test whether microscope is cradled */ + cam->params.qx3.cradled = ((data[2] & 0x40) == 0); + break; + + default: break; } } @@ -1782,6 +1837,7 @@ { int retval; u8 cmd[8], data[8]; + cmd[0] = command>>8; cmd[1] = command&0xff; cmd[2] = a; @@ -1800,29 +1856,186 @@ data[7] = l; retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data); - if(retval) { + if (retval) LOG("%x - failed\n", command); + + return retval; +} + +/********************************************************************** + * + * Colorspace conversion + * + **********************************************************************/ +#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16) + +static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt, + int linesize, int mmap_kludge) +{ + int y, u, v, r, g, b, y1; + + switch(out_fmt) { + case VIDEO_PALETTE_RGB555: + y = (*yuv++ - 16) * 76310; + y1 = (*yuv - 16) * 76310; + r = ((*(rgb+1-linesize)) & 0x7c) << 1; + g = ((*(rgb-linesize)) & 0xe0) >> 4 | + ((*(rgb+1-linesize)) & 0x03) << 6; + b = ((*(rgb-linesize)) & 0x1f) << 3; + u = (-53294 * r - 104635 * g + 157929 * b) / 5756495; + v = (157968 * r - 132278 * g - 25690 * b) / 5366159; + r = 104635 * v; + g = -25690 * u - 53294 * v; + b = 132278 * u; + break; + case VIDEO_PALETTE_RGB565: + y = (*yuv++ - 16) * 76310; + y1 = (*yuv - 16) * 76310; + r = (*(rgb+1-linesize)) & 0xf8; + g = ((*(rgb-linesize)) & 0xe0) >> 3 | + ((*(rgb+1-linesize)) & 0x07) << 5; + b = ((*(rgb-linesize)) & 0x1f) << 3; + u = (-53294 * r - 104635 * g + 157929 * b) / 5756495; + v = (157968 * r - 132278 * g - 25690 * b) / 5366159; + r = 104635 * v; + g = -25690 * u - 53294 * v; + b = 132278 * u; + break; + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_RGB32: + y = (*yuv++ - 16) * 76310; + y1 = (*yuv - 16) * 76310; + if (mmap_kludge) { + r = *(rgb+2-linesize); + g = *(rgb+1-linesize); + b = *(rgb-linesize); + } else { + r = *(rgb-linesize); + g = *(rgb+1-linesize); + b = *(rgb+2-linesize); + } + u = (-53294 * r - 104635 * g + 157929 * b) / 5756495; + v = (157968 * r - 132278 * g - 25690 * b) / 5366159; + r = 104635 * v; + g = -25690 * u + -53294 * v; + b = 132278 * u; + break; + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + y = *yuv++; + u = *(rgb+1-linesize); + y1 = *yuv; + v = *(rgb+3-linesize); + /* Just to avoid compiler warnings */ + r = 0; + g = 0; + b = 0; + break; + case VIDEO_PALETTE_UYVY: + u = *(rgb-linesize); + y = *yuv++; + v = *(rgb+2-linesize); + y1 = *yuv; + /* Just to avoid compiler warnings */ + r = 0; + g = 0; + b = 0; + break; + case VIDEO_PALETTE_GREY: + default: + y = *yuv++; + y1 = *yuv; + /* Just to avoid compiler warnings */ + u = 0; + v = 0; + r = 0; + g = 0; + b = 0; + break; + } + switch(out_fmt) { + case VIDEO_PALETTE_RGB555: + *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3); + *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6); + *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3); + *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6); + return 4; + case VIDEO_PALETTE_RGB565: + *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3); + *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5); + *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3); + *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5); + return 4; + case VIDEO_PALETTE_RGB24: + if (mmap_kludge) { + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(b+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(r+y1); + } else { + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(r+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(b+y1); + } + return 6; + case VIDEO_PALETTE_RGB32: + if (mmap_kludge) { + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(r+y); + rgb++; + *rgb++ = LIMIT(b+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(r+y1); + } else { + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(b+y); + rgb++; + *rgb++ = LIMIT(r+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(b+y1); + } + return 8; + case VIDEO_PALETTE_GREY: + *rgb++ = y; + *rgb = y1; + return 2; + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + *rgb++ = y; + *rgb++ = u; + *rgb++ = y1; + *rgb = v; + return 4; + case VIDEO_PALETTE_UYVY: + *rgb++ = u; + *rgb++ = y; + *rgb++ = v; + *rgb = y1; + return 4; + default: + DBG("Empty: %d\n", out_fmt); + return 0; } - return retval; } -/********************************************************************** - * - * Colorspace conversion - * - **********************************************************************/ -#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16) - static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt, - int in_uyvy) + int in_uyvy, int mmap_kludge) { int y, u, v, r, g, b, y1; + switch(out_fmt) { case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_RGB24: case VIDEO_PALETTE_RGB32: - if(in_uyvy) { + if (in_uyvy) { u = *yuv++ - 128; y = (*yuv++ - 16) * 76310; v = *yuv++ - 128; @@ -1862,21 +2075,40 @@ *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5); return 4; case VIDEO_PALETTE_RGB24: - *rgb++ = LIMIT(b+y); - *rgb++ = LIMIT(g+y); - *rgb++ = LIMIT(r+y); - *rgb++ = LIMIT(b+y1); - *rgb++ = LIMIT(g+y1); - *rgb = LIMIT(r+y1); + if (mmap_kludge) { + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(b+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(r+y1); + } else { + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(r+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(b+y1); + } return 6; case VIDEO_PALETTE_RGB32: - *rgb++ = LIMIT(b+y); - *rgb++ = LIMIT(g+y); - *rgb++ = LIMIT(r+y); - rgb++; - *rgb++ = LIMIT(b+y1); - *rgb++ = LIMIT(g+y1); - *rgb = LIMIT(r+y1); + if (mmap_kludge) { + *rgb++ = LIMIT(b+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(r+y); + rgb++; + *rgb++ = LIMIT(b+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(r+y1); + } else { + *rgb++ = LIMIT(r+y); + *rgb++ = LIMIT(g+y); + *rgb++ = LIMIT(b+y); + rgb++; + *rgb++ = LIMIT(r+y1); + *rgb++ = LIMIT(g+y1); + *rgb = LIMIT(b+y1); + } return 8; case VIDEO_PALETTE_GREY: *rgb++ = y; @@ -1896,11 +2128,13 @@ *rgb = y1; return 4; default: + DBG("Empty: %d\n", out_fmt); return 0; } } -static int skipcount(int count, int fmt) { +static int skipcount(int count, int fmt) +{ switch(fmt) { case VIDEO_PALETTE_GREY: return count; @@ -1922,66 +2156,68 @@ static int parse_picture(struct cam_data *cam, int size) { u8 *obuf, *ibuf, *end_obuf; - int ll, in_uyvy, compressed, origsize, out_fmt; + int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt; + int rows, cols, linesize, subsample_422; /* make sure params don't change while we are decoding */ down(&cam->param_lock); - + obuf = cam->decompressed_frame.data; end_obuf = obuf+CPIA_MAX_FRAME_SIZE; ibuf = cam->raw_image; origsize = size; out_fmt = cam->vp.palette; - - if((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) { + + if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) { LOG("header not found\n"); up(&cam->param_lock); return -1; } - if((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) { + if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) { LOG("wrong video size\n"); up(&cam->param_lock); return -1; } - if(ibuf[17] != SUBSAMPLE_422) { + if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) { LOG("illegal subtype %d\n",ibuf[17]); up(&cam->param_lock); return -1; } + subsample_422 = ibuf[17] == SUBSAMPLE_422; - if(ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) { + if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) { LOG("illegal yuvorder %d\n",ibuf[18]); up(&cam->param_lock); return -1; } in_uyvy = ibuf[18] == YUVORDER_UYVY; -#if 0 - /* FIXME: ROI mismatch occurs when switching capture sizes */ - if((ibuf[24] != cam->params.roi.colStart) || - (ibuf[25] != cam->params.roi.colEnd) || - (ibuf[26] != cam->params.roi.rowStart) || - (ibuf[27] != cam->params.roi.rowEnd)) { + if ((ibuf[24] != cam->params.roi.colStart) || + (ibuf[25] != cam->params.roi.colEnd) || + (ibuf[26] != cam->params.roi.rowStart) || + (ibuf[27] != cam->params.roi.rowEnd)) { LOG("ROI mismatch\n"); up(&cam->param_lock); return -1; } -#endif + cols = 8*(ibuf[25] - ibuf[24]); + rows = 4*(ibuf[27] - ibuf[26]); - if((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) { + if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) { LOG("illegal compression %d\n",ibuf[28]); up(&cam->param_lock); return -1; } compressed = (ibuf[28] == COMPRESSED); - if(ibuf[29] != NO_DECIMATION) { - LOG("decimation not supported\n"); + if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) { + LOG("illegal decimation %d\n",ibuf[29]); up(&cam->param_lock); return -1; } + decimation = (ibuf[29] == DECIMATION_ENAB); cam->params.yuvThreshold.yThreshold = ibuf[30]; cam->params.yuvThreshold.uvThreshold = ibuf[31]; @@ -1994,98 +2230,135 @@ cam->params.status.vpStatus = ibuf[38]; cam->params.status.errorCode = ibuf[39]; cam->fps = ibuf[41]; + up(&cam->param_lock); - ibuf += 64; - size -= 64; + linesize = skipcount(cols, out_fmt); + ibuf += FRAME_HEADER_SIZE; + size -= FRAME_HEADER_SIZE; ll = ibuf[0] | (ibuf[1] << 8); ibuf += 2; - while(size > 0) { + even_line = 1; + + while (size > 0) { size -= (ll+2); - if(size < 0) { + if (size < 0) { LOG("Insufficient data in buffer\n"); - up(&cam->param_lock); return -1; } - while(ll > 1) { - if(!compressed || (compressed && !(*ibuf & 1))) { - obuf += yuvconvert(ibuf,obuf,out_fmt,in_uyvy); - ibuf += 4; - ll -= 4; + + while (ll > 1) { + if (!compressed || (compressed && !(*ibuf & 1))) { + if(subsample_422 || even_line) { + obuf += yuvconvert(ibuf, obuf, out_fmt, + in_uyvy, cam->mmap_kludge); + ibuf += 4; + ll -= 4; + } else { + /* SUBSAMPLE_420 on an odd line */ + obuf += convert420(ibuf, obuf, + out_fmt, linesize, + cam->mmap_kludge); + ibuf += 2; + ll -= 2; + } } else { /*skip compressed interval from previous frame*/ - int skipsize = skipcount(*ibuf >> 1, out_fmt); - obuf += skipsize; - if( obuf > end_obuf ) { - LOG("Insufficient data in buffer\n"); - up(&cam->param_lock); + obuf += skipcount(*ibuf >> 1, out_fmt); + if (obuf > end_obuf) { + LOG("Insufficient buffer size\n"); return -1; } ++ibuf; ll--; } } - if(ll == 1) { - if(*ibuf != EOL) { + if (ll == 1) { + if (*ibuf != EOL) { LOG("EOL not found giving up after %d/%d" " bytes\n", origsize-size, origsize); - up(&cam->param_lock); return -1; } - ibuf++; /* skip over EOL */ + ++ibuf; /* skip over EOL */ - if((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) && + if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) && (ibuf[2] == EOI) && (ibuf[3] == EOI)) { size -= 4; break; } - if(size > 1) { + if(decimation) { + /* skip the odd lines for now */ + obuf += linesize; + } + + if (size > 1) { ll = ibuf[0] | (ibuf[1] << 8); ibuf += 2; /* skip over line length */ } + + if(!decimation) + even_line = !even_line; } else { LOG("line length was not 1 but %d after %d/%d bytes\n", ll, origsize-size, origsize); - up(&cam->param_lock); return -1; } } + if(decimation) { + /* interpolate odd rows */ + int i, j; + u8 *prev, *next; + prev = cam->decompressed_frame.data; + obuf = prev+linesize; + next = obuf+linesize; + for(i=1; idecompressed_frame.count = obuf-cam->decompressed_frame.data; - up(&cam->param_lock); - return cam->decompressed_frame.count; } /* InitStreamCap wrapper to select correct start line */ -static inline int init_stream_cap(struct cam_data *cam) { +static inline int init_stream_cap(struct cam_data *cam) +{ return do_command(cam, CPIA_COMMAND_InitStreamCap, 0, cam->params.streamStartLine, 0, 0); } /* update various camera modes and settings */ -static void dispatch_commands(struct cam_data *cam ) { +static void dispatch_commands(struct cam_data *cam) +{ down(&cam->param_lock); - if( cam->cmd_queue==COMMAND_NONE ) { + if (cam->cmd_queue==COMMAND_NONE) { up(&cam->param_lock); return; } DEB_BYTE(cam->cmd_queue); DEB_BYTE(cam->cmd_queue>>8); - if( cam->cmd_queue & COMMAND_SETCOLOURPARAMS ) { + if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS) do_command(cam, CPIA_COMMAND_SetColourParams, cam->params.colourParams.brightness, cam->params.colourParams.contrast, cam->params.colourParams.saturation, 0); - } - if( cam->cmd_queue & COMMAND_SETCOMPRESSION ) { + + if (cam->cmd_queue & COMMAND_SETCOMPRESSION) do_command(cam, CPIA_COMMAND_SetCompression, cam->params.compression.mode, cam->params.compression.decimation, 0, 0); - } - if( cam->cmd_queue & COMMAND_SETFORMAT ) { + + if (cam->cmd_queue & COMMAND_SETFORMAT) { do_command(cam, CPIA_COMMAND_SetFormat, cam->params.format.videoSize, cam->params.format.subSample, @@ -2095,22 +2368,23 @@ cam->params.roi.rowStart, cam->params.roi.rowEnd); cam->first_frame = 1; } - if( cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET ) { + + if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET) do_command(cam, CPIA_COMMAND_SetCompressionTarget, cam->params.compressionTarget.frTargeting, cam->params.compressionTarget.targetFR, cam->params.compressionTarget.targetQ, 0); - } - if( cam->cmd_queue & COMMAND_SETYUVTHRESH ) { + + if (cam->cmd_queue & COMMAND_SETYUVTHRESH) do_command(cam, CPIA_COMMAND_SetYUVThresh, cam->params.yuvThreshold.yThreshold, cam->params.yuvThreshold.uvThreshold, 0, 0); - } - if( cam->cmd_queue & COMMAND_SETECPTIMING ) { + + if (cam->cmd_queue & COMMAND_SETECPTIMING) do_command(cam, CPIA_COMMAND_SetECPTiming, cam->params.ecpTiming, 0, 0, 0); - } - if( cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS ) { + + if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS) do_command_extended(cam, CPIA_COMMAND_SetCompressionParams, 0, 0, 0, 0, cam->params.compressionParams.hysteresis, @@ -2121,8 +2395,8 @@ cam->params.compressionParams.frDiffStepThresh, cam->params.compressionParams.qDiffStepThresh, cam->params.compressionParams.decimationThreshMod); - } - if( cam->cmd_queue & COMMAND_SETEXPOSURE ) { + + if (cam->cmd_queue & COMMAND_SETEXPOSURE) do_command_extended(cam, CPIA_COMMAND_SetExposure, cam->params.exposure.gainMode, cam->params.exposure.expMode, @@ -2136,150 +2410,191 @@ cam->params.exposure.green1Comp, cam->params.exposure.green2Comp, cam->params.exposure.blueComp); + + if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) { + if (cam->params.colourBalance.balanceModeIsAuto) { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 2, 0, 0, 0); + } else { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 1, + cam->params.colourBalance.redGain, + cam->params.colourBalance.greenGain, + cam->params.colourBalance.blueGain); + do_command(cam, CPIA_COMMAND_SetColourBalance, + 3, 0, 0, 0); + } } - if( cam->cmd_queue & COMMAND_SETCOLOURBALANCE ) { - do_command(cam, CPIA_COMMAND_SetColourBalance, - cam->params.colourBalance.balanceMode, - cam->params.colourBalance.redGain, - cam->params.colourBalance.greenGain, - cam->params.colourBalance.blueGain); - } - if( cam->cmd_queue & COMMAND_SETSENSORFPS ) { + + if (cam->cmd_queue & COMMAND_SETSENSORFPS) do_command(cam, CPIA_COMMAND_SetSensorFPS, cam->params.sensorFps.divisor, cam->params.sensorFps.baserate, 0, 0); - } - if( cam->cmd_queue & COMMAND_SETAPCOR ) { + + if (cam->cmd_queue & COMMAND_SETAPCOR) do_command(cam, CPIA_COMMAND_SetApcor, cam->params.apcor.gain1, cam->params.apcor.gain2, cam->params.apcor.gain4, cam->params.apcor.gain8); - } - if( cam->cmd_queue & COMMAND_SETFLICKERCTRL ) { + + if (cam->cmd_queue & COMMAND_SETFLICKERCTRL) do_command(cam, CPIA_COMMAND_SetFlickerCtrl, cam->params.flickerControl.flickerMode, cam->params.flickerControl.coarseJump, cam->params.flickerControl.allowableOverExposure, 0); - } - if( cam->cmd_queue & COMMAND_SETVLOFFSET ) { + + if (cam->cmd_queue & COMMAND_SETVLOFFSET) do_command(cam, CPIA_COMMAND_SetVLOffset, cam->params.vlOffset.gain1, cam->params.vlOffset.gain2, cam->params.vlOffset.gain4, cam->params.vlOffset.gain8); - } - if( cam->cmd_queue & COMMAND_PAUSE ) { + + if (cam->cmd_queue & COMMAND_PAUSE) do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0); - } - if( cam->cmd_queue & COMMAND_RESUME ) { - init_stream_cap( cam ); - } + + if (cam->cmd_queue & COMMAND_RESUME) + init_stream_cap(cam); + + /* GA 04/14/00 */ + if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) + { + int p1 = (cam->params.qx3.bottomlight == 0) << 1; + int p2 = (cam->params.qx3.toplight == 0) << 3; + do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0); + do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0); + } + up(&cam->param_lock); - cam->cmd_queue=COMMAND_NONE; + cam->cmd_queue = COMMAND_NONE; return; } /* kernel thread function to read image from camera */ static void fetch_frame(void *data) { - int image_size; + int image_size, retry; struct cam_data *cam = (struct cam_data *)data; unsigned long oldjif, rate, diff; - /* load first frame always uncompressed */ - if( cam->first_frame && - cam->params.compression.mode != CPIA_COMPRESSION_NONE ) { - do_command(cam, CPIA_COMMAND_SetCompression, - CPIA_COMPRESSION_NONE, - NO_DECIMATION, 0, 0); - } - - /* init camera upload */ - if(do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_CONTINUOUS, - 0, 0, 0)) goto end; - if(do_command(cam, CPIA_COMMAND_GrabFrame, 0, - cam->params.streamStartLine, 0, 0)) goto end; - - /* loop until image ready */ - do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - while(cam->params.status.streamState != STREAM_READY) { - if(current->need_resched) {schedule();} - current->state=TASK_INTERRUPTIBLE; - schedule_timeout(10*HZ/1000); /* 10 ms, hopefully ;) */ - if(signal_pending(current)) { - goto end; - } - do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - } - - /* grab image from camera */ - if(current->need_resched) {schedule();} - oldjif = jiffies; - image_size=cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0); - if(image_size<=0) { - DBG("read frame failed\n"); - goto end; - } - rate = image_size * HZ / 1024; - diff = jiffies-oldjif; - rate = diff==0 ? rate : rate/diff; /* unlikely but possible */ - /* Keep track of transfer_rate as a runnung average over 3 frames - * to smooth out any inconsistencies */ - cam->transfer_rate = (2*cam->transfer_rate + rate) / 3; - - /* camera idle now so dispatch queued commands */ - dispatch_commands( cam ); - - /* Update our knowledge of the camera state - FIXME: necessary? */ - do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); - do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); - - /* decompress and convert image to by copying it from - * raw_image to decompressed_frame - */ - if(current->need_resched) {schedule();} - cam->image_size = parse_picture(cam, image_size); - if( cam->image_size <= 0 ) { - DBG("parse frame failed\n"); - goto end; - } - - /* FIXME: this only works for double buffering */ - if( cam->frame[cam->curframe].state == FRAME_READY ) { - memcpy(cam->frame[cam->curframe].data, - cam->decompressed_frame.data, - cam->decompressed_frame.count); - cam->frame[cam->curframe].state = FRAME_DONE; - } else { - cam->decompressed_frame.state = FRAME_DONE; - } + /* Allow up to two bad images in a row to be read and + * ignored before an error is reported */ + for (retry = 0; retry < 3; ++retry) { + if (retry) + DBG("retry=%d\n", retry); + + if (!cam->ops) + continue; + + /* load first frame always uncompressed */ + if (cam->first_frame && + cam->params.compression.mode != CPIA_COMPRESSION_NONE) + do_command(cam, CPIA_COMMAND_SetCompression, + CPIA_COMPRESSION_NONE, + NO_DECIMATION, 0, 0); + + /* init camera upload */ + if (do_command(cam, CPIA_COMMAND_SetGrabMode, + CPIA_GRAB_CONTINUOUS, 0, 0, 0)) + continue; + + if (do_command(cam, CPIA_COMMAND_GrabFrame, 0, + cam->params.streamStartLine, 0, 0)) + continue; + + if (cam->ops->wait_for_stream_ready) { + /* loop until image ready */ + do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0); + while (cam->params.status.streamState != STREAM_READY) { + if (current->need_resched) + schedule(); + + current->state = TASK_INTERRUPTIBLE; + + /* sleep for 10 ms, hopefully ;) */ + schedule_timeout(10*HZ/1000); + if (signal_pending(current)) + return; + + do_command(cam, CPIA_COMMAND_GetCameraStatus, + 0, 0, 0, 0); + } + } + + /* grab image from camera */ + if (current->need_resched) + schedule(); + + oldjif = jiffies; + image_size = cam->ops->streamRead(cam->lowlevel_data, + cam->raw_image, 0); + if (image_size <= 0) { + DBG("streamRead failed: %d\n", image_size); + continue; + } + + rate = image_size * HZ / 1024; + diff = jiffies-oldjif; + cam->transfer_rate = diff==0 ? rate : rate/diff; + /* diff==0 ? unlikely but possible */ + + /* camera idle now so dispatch queued commands */ + dispatch_commands(cam); + + /* Update our knowledge of the camera state - FIXME: necessary? */ + do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); + do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); /* GA */ + + + /* decompress and convert image to by copying it from + * raw_image to decompressed_frame + */ + if (current->need_resched) + schedule(); + + cam->image_size = parse_picture(cam, image_size); + if (cam->image_size <= 0) + DBG("parse_picture failed %d\n", cam->image_size); + else + break; + } + + if (retry < 3) { + /* FIXME: this only works for double buffering */ + if (cam->frame[cam->curframe].state == FRAME_READY) { + memcpy(cam->frame[cam->curframe].data, + cam->decompressed_frame.data, + cam->decompressed_frame.count); + cam->frame[cam->curframe].state = FRAME_DONE; + } else + cam->decompressed_frame.state = FRAME_DONE; #if 0 - if( cam->first_frame && - cam->params.compression.mode != CPIA_COMPRESSION_NONE ) { - cam->first_frame = 0; - cam->cmd_queue |= COMMAND_SETCOMPRESSION; - } + if (cam->first_frame && + cam->params.compression.mode != CPIA_COMPRESSION_NONE) { + cam->first_frame = 0; + cam->cmd_queue |= COMMAND_SETCOMPRESSION; + } #else - if( cam->first_frame ) { - cam->first_frame = 0; - cam->cmd_queue |= COMMAND_SETCOMPRESSION; - cam->cmd_queue |= COMMAND_SETEXPOSURE; - } + if (cam->first_frame) { + cam->first_frame = 0; + cam->cmd_queue |= COMMAND_SETCOMPRESSION; + cam->cmd_queue |= COMMAND_SETEXPOSURE; + } #endif -end: - return; + } } static int capture_frame(struct cam_data *cam, struct video_mmap *vm) { int retval = 0; - if( cam->frame_buf == NULL ) { /* we do lazy allocation */ - if( (retval = allocate_frame_buf(cam)) ) { + if (!cam->frame_buf) { + /* we do lazy allocation */ + if ((retval = allocate_frame_buf(cam))) return retval; - } } /* FIXME: the first frame seems to be captured by the camera @@ -2287,25 +2602,30 @@ that one, the next one is generated with our settings (exposure, color balance, ...) */ - if(cam->first_frame) { - cam->curframe = vm->frame; - cam->frame[cam->curframe].state = FRAME_READY; - fetch_frame(cam); - if(cam->frame[cam->curframe].state != FRAME_DONE) retval=-EIO; + if (cam->first_frame) { + cam->curframe = vm->frame; + cam->frame[cam->curframe].state = FRAME_READY; + fetch_frame(cam); + if (cam->frame[cam->curframe].state != FRAME_DONE) + retval = -EIO; } cam->curframe = vm->frame; - cam->frame[cam->curframe].state = FRAME_READY; - fetch_frame(cam); - if(cam->frame[cam->curframe].state != FRAME_DONE) retval=-EIO; + cam->frame[cam->curframe].state = FRAME_READY; + fetch_frame(cam); + if (cam->frame[cam->curframe].state != FRAME_DONE) + retval=-EIO; return retval; } static int goto_high_power(struct cam_data *cam) { - if(do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0)) return -1; - if(do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) return -1; - if(cam->params.status.systemState == HI_POWER_STATE) { + if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0)) + return -1; + mdelay(100); /* windows driver does it too */ + if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) + return -1; + if (cam->params.status.systemState == HI_POWER_STATE) { DBG("camera now in HIGH power state\n"); return 0; } @@ -2315,14 +2635,15 @@ static int goto_low_power(struct cam_data *cam) { - if(do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0)) return -1; - if(do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) return -1; - if(cam->params.status.systemState == LO_POWER_STATE) { + if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0)) + return -1; + if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) + return -1; + if (cam->params.status.systemState == LO_POWER_STATE) { DBG("camera now in LOW power state\n"); return 0; } printstatus(cam); - mdelay(100); /* windows driver does it too */ return -1; } @@ -2344,21 +2665,23 @@ cam->params.colourBalance.redGain, cam->params.colourBalance.greenGain, cam->params.colourBalance.blueGain); - - return; } static void set_camera_state(struct cam_data *cam) { - if(cam->params.colourBalance.balanceMode != 1) { + if(cam->params.colourBalance.balanceModeIsAuto) { + do_command(cam, CPIA_COMMAND_SetColourBalance, + 2, 0, 0, 0); + } else { do_command(cam, CPIA_COMMAND_SetColourBalance, 1, cam->params.colourBalance.redGain, cam->params.colourBalance.greenGain, cam->params.colourBalance.blueGain); + do_command(cam, CPIA_COMMAND_SetColourBalance, + 3, 0, 0, 0); } - if(cam->params.colourBalance.balanceMode == 0) - cam->params.colourBalance.balanceMode = 2; + do_command_extended(cam, CPIA_COMMAND_SetExposure, cam->params.exposure.gainMode, 1, 1, @@ -2367,19 +2690,19 @@ cam->params.exposure.fineExp, cam->params.exposure.coarseExpLo, cam->params.exposure.coarseExpHi, - cam->params.exposure.redComp, - cam->params.exposure.green1Comp, - cam->params.exposure.green2Comp, - cam->params.exposure.blueComp); + cam->params.exposure.redComp, + cam->params.exposure.green1Comp, + cam->params.exposure.green2Comp, + cam->params.exposure.blueComp); do_command_extended(cam, CPIA_COMMAND_SetExposure, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - if(cam->params.exposure.gainMode == 0) + if (!cam->params.exposure.gainMode) cam->params.exposure.gainMode = 2; - if(cam->params.exposure.expMode == 0) + if (!cam->params.exposure.expMode) cam->params.exposure.expMode = 2; - if(cam->params.exposure.centreWeight == 0) + if (!cam->params.exposure.centreWeight) cam->params.exposure.centreWeight = 1; cam->cmd_queue = COMMAND_SETCOMPRESSION | @@ -2407,32 +2730,25 @@ { /* GetCPIAVersion */ do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0); - printk(KERN_INFO " CPIA Version: %d.%02d (%d.%d)\n", - cam->params.version.firmwareVersion, - cam->params.version.firmwareRevision, - cam->params.version.vcVersion, - cam->params.version.vcRevision); /* GetPnPID */ do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0); - printk(KERN_INFO " CPIA PnP-ID: %04x:%04x:%04x\n", - cam->params.pnpID.vendor, cam->params.pnpID.product, - cam->params.pnpID.deviceRevision); } /* initialize camera */ static int reset_camera(struct cam_data *cam) { /* Start the camera in low power mode */ - if(goto_low_power(cam)) { - if( cam->params.status.systemState != 0x4 ) { + if (goto_low_power(cam)) { + if (cam->params.status.systemState != WARM_BOOT_STATE) return -ENODEV; - } + /* FIXME: this is just dirty trial and error */ reset_camera_struct(cam); goto_high_power(cam); do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0); - if(goto_low_power(cam)) return -NODEV; + if (goto_low_power(cam)) + return -NODEV; } /* procedure described in developer's guide p3-28 */ @@ -2440,11 +2756,15 @@ /* Check the firmware version FIXME: should we check PNPID? */ cam->params.version.firmwareVersion = 0; get_version_information(cam); - if(cam->params.version.firmwareVersion != 1) { + if (cam->params.version.firmwareVersion != 1) return -ENODEV; - } + + /* GA 04/14/00 - set QX3 detected flag */ + cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 && + cam->params.pnpID.product == 0x0001); - /* The fatal error checking should be done after the camera powers up (developer's guide p 3-38) */ + /* The fatal error checking should be done after + * the camera powers up (developer's guide p 3-38) */ /* Set streamState before transition to high power to avoid bug * in firmware 1-02 */ @@ -2452,40 +2772,38 @@ STREAM_NOT_READY, 0); /* GotoHiPower */ - if(goto_high_power(cam)) + if (goto_high_power(cam)) return -ENODEV; - /* Check the camera status */ - if(do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) + if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) return -EIO; - if(cam->params.status.fatalError) { - DBG("fatal_error: %#04x\n",cam->params.status.fatalError); - DBG("vp_status: %#04x\n",cam->params.status.vpStatus); - if(cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) { + + if (cam->params.status.fatalError) { + DBG("fatal_error: %#04x\n", + cam->params.status.fatalError); + DBG("vp_status: %#04x\n", + cam->params.status.vpStatus); + if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) { /* Fatal error in camera */ return -EIO; - } else if(cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)){ + } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) { /* Firmware 1-02 may do this for parallel port cameras, * just clear the flags (developer's guide p 3-38) */ do_command(cam, CPIA_COMMAND_ModifyCameraStatus, FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0); } } - + /* Check the camera status again */ - if(cam->params.status.fatalError) { - if(cam->params.status.fatalError) + if (cam->params.status.fatalError) { + if (cam->params.status.fatalError) return -EIO; } /* VPVersion can't be retrieved before the camera is in HiPower, * so get it here instead of in get_version_information. */ do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0); - printk(KERN_INFO " VP-Version: %d.%d %04x\n", - cam->params.vpVersion.vpVersion, - cam->params.vpVersion.vpRevision, - cam->params.vpVersion.cameraHeadID); /* set camera to a known state */ set_camera_state(cam); @@ -2499,54 +2817,60 @@ int i; struct cam_data *cam = dev->priv; - DBG("cpia_open\n"); - - if(cam->open_count > 0) { - DBG("Camera[%d] already open\n",cam->index); + if (!cam) { + DBG("Internal error, cam_data not found!\n"); + return -EBUSY; + } + + if (cam->open_count > 0) { + DBG("Camera already open\n"); return -EBUSY; } - if(cam->raw_image == NULL) { - if((cam->raw_image=rvmalloc(CPIA_MAX_IMAGE_SIZE)) == NULL){ + if (!cam->raw_image) { + cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE); + if (!cam->raw_image) return -ENOMEM; - } } - if(cam->decompressed_frame.data == NULL) { - cam->decompressed_frame.data=rvmalloc(CPIA_MAX_FRAME_SIZE); - if(cam->decompressed_frame.data == NULL){ + + if (!cam->decompressed_frame.data) { + cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE); + if (!cam->decompressed_frame.data) { rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image=NULL; + cam->raw_image = NULL; return -ENOMEM; } } /* open cpia */ - if (cam->ops->open(cam->index, &cam->lowlevel_data)) { + if (cam->ops->open(cam->lowlevel_data)) { rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data=NULL; + cam->decompressed_frame.data = NULL; rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image=NULL; + cam->raw_image = NULL; return -ENODEV; } /* reset the camera */ - if((i = reset_camera(cam)) != 0) { + if ((i = reset_camera(cam)) != 0) { cam->ops->close(cam->lowlevel_data); rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data=NULL; + cam->decompressed_frame.data = NULL; rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image=NULL; + cam->raw_image = NULL; return i; } /* Set ownership of /proc/cpia/videoX to current user */ - if(cam->proc_entry != NULL) + if(cam->proc_entry) cam->proc_entry->uid = current->uid; - + /* set mark for loading first frame uncompressed */ cam->first_frame = 1; - cam->busy_lock = MUTEX; - + + /* init it to something */ + cam->mmap_kludge = 0; + ++cam->open_count; #ifdef MODULE MOD_INC_USE_COUNT; @@ -2554,78 +2878,51 @@ return 0; } -/* FIXME */ static void cpia_close(struct video_device *dev) { struct cam_data *cam; - DBG("cpia_close\n"); cam = dev->priv; - if(cam->ops == NULL) { - if(--cam->open_count == 0) { - int i; - video_unregister_device(dev); - /* Need a lock when adding/removing cameras */ - lock_kernel(); - if(cam->raw_image) { - rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image=0; - } - if(cam->decompressed_frame.data) { - rvfree(cam->decompressed_frame.data, - CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data=0; - } - if(cam->frame_buf) { - free_frame_buf(cam); - } - for(i=0; iops) { + /* Return ownership of /proc/cpia/videoX to root */ + if(cam->proc_entry) + cam->proc_entry->uid = 0; - /* Return ownership of /proc/cpia/videoX to root */ - if(cam->proc_entry != NULL) - cam->proc_entry->uid = 0; - - /* save camera state for later open (developers guide ch 3.5.3) */ - save_camera_state(cam); + /* save camera state for later open (developers guide ch 3.5.3) */ + save_camera_state(cam); - /* GotoLoPower */ - goto_low_power(cam); + /* GotoLoPower */ + goto_low_power(cam); - /* cleanup internal state stuff */ - free_frames(cam->frame); + /* Update the camera ststus */ + do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); - /* Update the camera ststus */ - do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); + /* cleanup internal state stuff */ + free_frames(cam->frame); - /* close cpia */ - cam->ops->close(cam->lowlevel_data); + /* close cpia */ + cam->ops->close(cam->lowlevel_data); + } - if(--cam->open_count == 0) { + if (--cam->open_count == 0) { /* clean up capture-buffers */ - if(cam->raw_image) { + if (cam->raw_image) { rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image = 0; + cam->raw_image = NULL; } - if(cam->decompressed_frame.data) { + + if (cam->decompressed_frame.data) { rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data = 0; + cam->decompressed_frame.data = NULL; } - if(cam->frame_buf) { + + if (cam->frame_buf) free_frame_buf(cam); + + if (!cam->ops) { + video_unregister_device(dev); + kfree(cam); } } @@ -2637,26 +2934,27 @@ } static long cpia_read(struct video_device *dev, char *buf, - unsigned long count, int noblock) + unsigned long count, int noblock) { struct cam_data *cam = dev->priv; /* make this _really_ smp and multithredi-safe */ - if( down_interruptible(&cam->busy_lock) ) { + if (down_interruptible(&cam->busy_lock)) return -EINTR; - } if (!buf) { DBG("buf NULL\n"); up(&cam->busy_lock); return -EINVAL; } - if(count == 0) { + + if (!count) { DBG("count 0\n"); up(&cam->busy_lock); return 0; } - if(!cam->ops) { + + if (!cam->ops) { DBG("ops NULL\n"); up(&cam->busy_lock); return -ENODEV; @@ -2664,8 +2962,9 @@ /* upload frame */ cam->decompressed_frame.state = FRAME_READY; + cam->mmap_kludge=0; fetch_frame(cam); - if( cam->decompressed_frame.state != FRAME_DONE ) { + if (cam->decompressed_frame.state != FRAME_DONE) { DBG("upload failed %d/%d\n", cam->decompressed_frame.count, cam->decompressed_frame.state); up(&cam->busy_lock); @@ -2674,12 +2973,13 @@ cam->decompressed_frame.state = FRAME_UNUSED; /* copy data to user space */ - if(cam->decompressed_frame.count > count) { - DBG("count wrong\n"); + if (cam->decompressed_frame.count > count) { + DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count, + count); up(&cam->busy_lock); return -EFAULT; } - if(copy_to_user(buf, cam->decompressed_frame.data, + if (copy_to_user(buf, cam->decompressed_frame.data, cam->decompressed_frame.count)) { DBG("copy_to_user failed\n"); up(&cam->busy_lock); @@ -2695,31 +2995,34 @@ struct cam_data *cam = dev->priv; int retval = 0; + if (!cam || !cam->ops) + return -ENODEV; + /* make this _really_ smp-safe */ - if( down_interruptible(&cam->busy_lock) ) { + if (down_interruptible(&cam->busy_lock)) return -EINTR; - } + //DBG("cpia_ioctl: %u\n", ioctlnr); switch (ioctlnr) { - /* query capabilites */ case VIDIOCGCAP: { struct video_capability b; DBG("VIDIOCGCAP\n"); - strcpy(b.name, "CPiA Parport Camera"); + strcpy(b.name, "CPiA Camera"); b.type = VID_TYPE_CAPTURE; b.channels = 1; b.audios = 0; - b.maxwidth = 352; /* VIDEOSIZE_CIF */ + b.maxwidth = 352; /* VIDEOSIZE_CIF */ b.maxheight = 288; - b.minwidth = 48; /* VIDEOSIZE_48_48 */ + b.minwidth = 48; /* VIDEOSIZE_48_48 */ b.minheight = 48; if (copy_to_user(arg, &b, sizeof(b))) retval = -EFAULT; + break; } @@ -2782,13 +3085,15 @@ retval = -EFAULT; break; } + /* check validity */ DBG("palette: %d\n", vp.palette); DBG("depth: %d\n", vp.depth); - if ( !valid_mode(vp.palette, vp.depth) ) { + if (!valid_mode(vp.palette, vp.depth)) { retval = -EINVAL; break; } + down(&cam->param_lock); /* brightness, colour, contrast need no check 0-65535 */ memcpy( &cam->vp, &vp, sizeof(vp) ); @@ -2799,12 +3104,13 @@ /* contrast is in steps of 8, so round */ cam->params.colourParams.contrast = ((cam->params.colourParams.contrast + 3) / 8) * 8; - if(cam->params.version.firmwareVersion == 1 && - cam->params.version.firmwareRevision == 2 && - cam->params.colourParams.contrast > 80) { + if (cam->params.version.firmwareVersion == 1 && + cam->params.version.firmwareRevision == 2 && + cam->params.colourParams.contrast > 80) { /* 1-02 firmware limits contrast to 80 */ cam->params.colourParams.contrast = 80; } + /* queue command to update camera */ cam->cmd_queue |= COMMAND_SETCOLOURPARAMS; up(&cam->param_lock); @@ -2845,9 +3151,10 @@ * is requested by the user??? */ down(&cam->param_lock); - if(vw.width!=cam->vw.width || vw.height!=cam->vw.height) { + if (vw.width != cam->vw.width || vw.height != cam->vw.height) { int video_size = match_videosize(vw.width, vw.height); - if(video_size < 0) { + + if (video_size < 0) { retval = -EINVAL; up(&cam->param_lock); break; @@ -2863,7 +3170,7 @@ /* setformat ignored by camera during streaming, * so stop/dispatch/start */ - if(cam->cmd_queue & COMMAND_SETFORMAT) { + if (cam->cmd_queue & COMMAND_SETFORMAT) { DBG("\n"); dispatch_commands(cam); } @@ -2882,10 +3189,10 @@ memset(&vm, 0, sizeof(vm)); vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM; vm.frames = FRAME_NUM; - for( i=0; ivp.palette = vm.format; switch(vm.format) { case VIDEO_PALETTE_GREY: + cam->vp.depth = 8; + break; case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_YUV422: @@ -2930,15 +3239,16 @@ retval = -EINVAL; break; } - if(retval != 0) break; + if (retval) + break; /* set video size */ video_size = match_videosize(vm.width, vm.height); - if(cam->video_size<0) { + if (cam->video_size < 0) { retval = -EINVAL; break; } - if( video_size != cam->video_size ) { + if (video_size != cam->video_size) { cam->video_size = video_size; set_vw_size(cam); cam->cmd_queue |= COMMAND_SETFORMAT; @@ -2949,6 +3259,7 @@ cam->vw.width, cam->vw.height); #endif /* according to v4l-spec we must start streaming here */ + cam->mmap_kludge = 1; retval = capture_frame(cam, &vm); break; @@ -2964,7 +3275,7 @@ } //DBG("VIDIOCSYNC: %d\n", frame); - if (frame<0||frame>=FRAME_NUM) { + if (frame<0 || frame >= FRAME_NUM) { retval = -EINVAL; break; } @@ -2982,7 +3293,7 @@ //DBG("VIDIOCSYNC: %d synced\n", frame); break; } - if(retval == -EINTR) { + if (retval == -EINTR) { /* FIXME - xawtv does not handle this nice */ retval = 0; } @@ -3040,49 +3351,57 @@ { unsigned long start = (unsigned long)adr; unsigned long page, pos; - struct cam_data *cam; + struct cam_data *cam = dev->priv; int retval; + if (!cam || !cam->ops) + return -ENODEV; + DBG("cpia_mmap: %ld\n", size); - if(size > FRAME_NUM*CPIA_MAX_FRAME_SIZE){ + if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE) return -EINVAL; - } - - cam = dev->priv; + if (!cam || !cam->ops) + return -ENODEV; + /* make this _really_ smp-safe */ - if( down_interruptible(&cam->busy_lock) ) { + if (down_interruptible(&cam->busy_lock)) return -EINTR; - } - if( cam->frame_buf == NULL ) { /* we do lazy allocation */ - if( (retval = allocate_frame_buf(cam)) ) { + if (!cam->frame_buf) { /* we do lazy allocation */ + if ((retval = allocate_frame_buf(cam))) { up(&cam->busy_lock); return retval; } } + pos = (unsigned long)(cam->frame_buf); while (size > 0) { - page = kvirt_to_phys(pos); + page = kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { up(&cam->busy_lock); return -EAGAIN; } - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - if (size > PAGE_SIZE) size-=PAGE_SIZE; - else size=0; + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; } DBG("cpia_mmap: %ld\n", size); up(&cam->busy_lock); + return 0; } int cpia_video_init(struct video_device *vdev) { +#ifdef CONFIG_PROC_FS create_proc_cpia_cam(vdev->priv); +#endif return 0; } @@ -3124,7 +3443,7 @@ cam->params.exposure.green1Comp = 214; cam->params.exposure.green2Comp = 214; cam->params.exposure.blueComp = 230; - cam->params.colourBalance.balanceMode = 2; /* auto color balance */ + cam->params.colourBalance.balanceModeIsAuto = 1; cam->params.colourBalance.redGain = 32; cam->params.colourBalance.greenGain = 6; cam->params.colourBalance.blueGain = 92; @@ -3151,16 +3470,15 @@ cam->params.compressionParams.decimationThreshMod = 2; /* End of default values from Software Developer's Guide */ - /* Start with a reasonable transfer rate */ - cam->transfer_rate = 500; + cam->transfer_rate = 0; /* Set Sensor FPS to 15fps. This seems better than 30fps * for indoor lighting. */ cam->params.sensorFps.divisor = 1; cam->params.sensorFps.baserate = 1; - cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */ - cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */ + cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */ + cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */ cam->params.format.subSample = SUBSAMPLE_422; cam->params.format.yuvOrder = YUVORDER_YUYV; @@ -3168,8 +3486,14 @@ cam->params.compression.mode = CPIA_COMPRESSION_AUTO; cam->params.compressionTarget.frTargeting = CPIA_COMPRESSION_TARGET_QUALITY; - cam->params.compressionTarget.targetFR = 7; /* FIXME? */ - cam->params.compressionTarget.targetQ = 10; /* FIXME? */ + cam->params.compressionTarget.targetFR = 15; /* From windows driver */ + cam->params.compressionTarget.targetQ = 5; /* From windows driver */ + + cam->params.qx3.qx3_detected = 0; + cam->params.qx3.toplight = 0; + cam->params.qx3.bottomlight = 0; + cam->params.qx3.button = 0; + cam->params.qx3.cradled = 0; cam->video_size = VIDEOSIZE_CIF; @@ -3179,7 +3503,7 @@ cam->vp.contrast = 32768; /* 50% */ cam->vp.whiteness = 0; /* not used -> grayscale only */ cam->vp.depth = 0; /* FIXME: to be set by user? */ - cam->vp.palette = 0; /* FIXME: to be set by user? */ + cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */ cam->vw.x = 0; cam->vw.y = 0; @@ -3201,11 +3525,13 @@ struct cpia_camera_ops *ops ) { int i; + /* Default everything to 0 */ memset(cam, 0, sizeof(struct cam_data)); cam->ops = ops; - cam->param_lock = MUTEX; + init_MUTEX(&cam->param_lock); + init_MUTEX(&cam->busy_lock); reset_camera_struct(cam); @@ -3215,7 +3541,7 @@ cam->vdev.priv = cam; cam->curframe = 0; - for( i=0; iframe[i].width = 0; cam->frame[i].height = 0; cam->frame[i].state = FRAME_UNUSED; @@ -3225,95 +3551,84 @@ cam->decompressed_frame.height = 0; cam->decompressed_frame.state = FRAME_UNUSED; cam->decompressed_frame.data = NULL; - - return; } -int cpia_register_camera(struct cpia_camera_ops *ops) +struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel) { - int i; - struct cam_data *cam; + struct cam_data *camera; + /* Need a lock when adding/removing cameras. This doesn't happen * often and doesn't take very long, so grabbing the kernel lock * should be OK. */ - lock_kernel(); - for(i=0; i < CPIA_MAXCAMS && camera[i] != NULL; ++i); /* no loop body */ - if(i == CPIA_MAXCAMS) { - unlock_kernel(); - return -ENODEV; - } - if((camera[i] = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) { + if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) { unlock_kernel(); - return -ENOMEM; + return NULL; } - init_camera_struct( camera[i], ops ); - camera[i]->index = i; - + init_camera_struct( camera, ops ); + camera->lowlevel_data = lowlevel; + /* register v4l device */ - if (video_register_device(&camera[i]->vdev, VFL_TYPE_GRABBER) == -1) { - kfree(camera[i]); - camera[i] = NULL; + if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) { + kfree(camera); unlock_kernel(); printk(KERN_DEBUG "video_register_device failed\n"); - return -ENODEV; + return NULL; } - unlock_kernel(); - - /* FIXME */ -#if 0 - cam = camera[i]; + /* get version information from camera: open/reset/close */ + /* open cpia */ - if (cam->ops->open(cam->index, &cam->lowlevel_data)) { - rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data=NULL; - rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image=NULL; - return -ENODEV; - } + if (camera->ops->open(camera->lowlevel_data)) + return camera; /* reset the camera */ - if((i = reset_camera(cam)) != 0) { - cam->ops->close(cam->lowlevel_data); - rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE); - cam->decompressed_frame.data=NULL; - rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); - cam->raw_image=NULL; - return i; + if (reset_camera(camera) != 0) { + camera->ops->close(camera->lowlevel_data); + return camera; } -#endif - return i; + + /* close cpia */ + camera->ops->close(camera->lowlevel_data); + + printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n", + camera->params.version.firmwareVersion, + camera->params.version.firmwareRevision, + camera->params.version.vcVersion, + camera->params.version.vcRevision); + printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n", + camera->params.pnpID.vendor, + camera->params.pnpID.product, + camera->params.pnpID.deviceRevision); + printk(KERN_INFO " VP-Version: %d.%d %04x\n", + camera->params.vpVersion.vpVersion, + camera->params.vpVersion.vpRevision, + camera->params.vpVersion.cameraHeadID); + + return camera; } -void cpia_unregister_camera(int camnr) +void cpia_unregister_camera(struct cam_data *cam) { - struct cam_data *cam; - if(camnr >= CPIA_MAXCAMS || camera[camnr] == NULL) return; - cam = camera[camnr]; - - DBG("unregistering video\n"); - /* FIXME: Is this safe if the device is open? */ - video_unregister_device(&cam->vdev); - - /* Need a lock when adding/removing cameras. This doesn't happen - * often and doesn't take very long, so grabbing the kernel lock - * should be OK. */ - lock_kernel(); + if (!cam->open_count) { + DBG("unregistering video\n"); + video_unregister_device(&cam->vdev); + } else { + LOG("/dev/video%d removed while open, " + "deferring video_unregister_device\n", cam->vdev.minor); + DBG("camera open -- setting ops to NULL\n"); + cam->ops = NULL; + } +#ifdef CONFIG_PROC_FS DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor); destroy_proc_cpia_cam(cam); - - if(cam->open_count == 0) { +#endif + if (!cam->open_count) { DBG("freeing camera\n"); - kfree(camera[camnr]); - camera[camnr] = NULL; - } else { - DBG("camera open -- setting ops to NULL\n"); - cam->ops = NULL; + kfree(cam); } - unlock_kernel(); } /**************************************************************************** @@ -3327,7 +3642,9 @@ { printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); +#ifdef CONFIG_PROC_FS proc_cpia_create(); +#endif #ifdef CONFIG_KMOD #ifdef CONFIG_VIDEO_CPIA_PP_MODULE request_module("cpia_pp"); @@ -3341,14 +3658,9 @@ void cleanup_module(void) { - int i; - for(i=0; ivdev); - } - } - +#ifdef CONFIG_PROC_FS proc_cpia_destroy(); +#endif } #else @@ -3357,25 +3669,25 @@ { printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT, CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); +#ifdef CONFIG_PROC_FS proc_cpia_create(); +#endif -#ifdef MODULE +#ifdef CONFIG_VIDEO_CPIA_PP + cpia_pp_init(); +#endif #ifdef CONFIG_KMOD #ifdef CONFIG_VIDEO_CPIA_PP_MODULE request_module("cpia_pp"); #endif + #ifdef CONFIG_VIDEO_CPIA_USB_MODULE request_module("cpia_usb"); #endif #endif /* CONFIG_KMOD */ -#else /* !MODULE */ -#ifdef CONFIG_VIDEO_CPIA_PP - cpia_pp_init(); -#endif #ifdef CONFIG_VIDEO_CPIA_USB cpia_usb_init(); #endif -#endif /* !MODULE */ return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/cpia.h linux/drivers/char/cpia.h --- v2.2.17/drivers/char/cpia.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/cpia.h Sat Dec 9 21:24:54 2000 @@ -0,0 +1,430 @@ +#ifndef cpia_h +#define cpia_h + +/* + * CPiA Parallel Port Video4Linux driver + * + * Supports CPiA based parallel port Video Camera's. + * + * (C) Copyright 1999 Bas Huisman, + * Peter Pregler, + * Scott J. Bertin, + * VLSI Vision Ltd. + * + * 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. + */ + +#define CPIA_MAJ_VER 1 +#define CPIA_MIN_VER 0 +#define CPIA_PATCH_VER 0 + +#define CPIA_PP_MAJ_VER 1 +#define CPIA_PP_MIN_VER 0 +#define CPIA_PP_PATCH_VER 0 + +#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */ +#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */ + +#ifdef __KERNEL__ + +#include +#include +#include + +struct cpia_camera_ops +{ + /* open sets privdata to point to structure for this camera. + * Returns negative value on error, otherwise 0. + */ + int (*open)(void *privdata); + + /* Registers callback function cb to be called with cbdata + * when an image is ready. If cb is NULL, only single image grabs + * should be used. cb should immediately call streamRead to read + * the data or data may be lost. Returns negative value on error, + * otherwise 0. + */ + int (*registerCallback)(void *privdata, void (*cb)(void *cbdata), + void *cbdata); + + /* transferCmd sends commands to the camera. command MUST point to + * an 8 byte buffer in kernel space. data can be NULL if no extra + * data is needed. The size of the data is given by the last 2 + * bytes of comand. data must also point to memory in kernel space. + * Returns negative value on error, otherwise 0. + */ + int (*transferCmd)(void *privdata, u8 *command, u8 *data); + + /* streamStart initiates stream capture mode. + * Returns negative value on error, otherwise 0. + */ + int (*streamStart)(void *privdata); + + /* streamStop terminates stream capture mode. + * Returns negative value on error, otherwise 0. + */ + int (*streamStop)(void *privdata); + + /* streamRead reads a frame from the camera. buffer points to a + * buffer large enough to hold a complete frame in kernel space. + * noblock indicates if this should be a non blocking read. + * Returns the number of bytes read, or negative value on error. + */ + int (*streamRead)(void *privdata, u8 *buffer, int noblock); + + /* close disables the device until open() is called again. + * Returns negative value on error, otherwise 0. + */ + int (*close)(void *privdata); + + /* If wait_for_stream_ready is non-zero, wait until the streamState + * is STREAM_READY before calling streamRead. + */ + int wait_for_stream_ready; +}; + +struct cpia_frame { + u8 *data; + int count; + int width; + int height; + volatile int state; +}; + +struct cam_params { + struct { + u8 firmwareVersion; + u8 firmwareRevision; + u8 vcVersion; + u8 vcRevision; + } version; + struct { + u16 vendor; + u16 product; + u16 deviceRevision; + } pnpID; + struct { + u8 vpVersion; + u8 vpRevision; + u16 cameraHeadID; + } vpVersion; + struct { + u8 systemState; + u8 grabState; + u8 streamState; + u8 fatalError; + u8 cmdError; + u8 debugFlags; + u8 vpStatus; + u8 errorCode; + } status; + struct { + u8 brightness; + u8 contrast; + u8 saturation; + } colourParams; + struct { + u8 gainMode; + u8 expMode; + u8 compMode; + u8 centreWeight; + u8 gain; + u8 fineExp; + u8 coarseExpLo; + u8 coarseExpHi; + u8 redComp; + u8 green1Comp; + u8 green2Comp; + u8 blueComp; + } exposure; + struct { + u8 balanceModeIsAuto; + u8 redGain; + u8 greenGain; + u8 blueGain; + } colourBalance; + struct { + u8 divisor; + u8 baserate; + } sensorFps; + struct { + u8 gain1; + u8 gain2; + u8 gain4; + u8 gain8; + } apcor; + struct { + u8 flickerMode; + u8 coarseJump; + u8 allowableOverExposure; + } flickerControl; + struct { + u8 gain1; + u8 gain2; + u8 gain4; + u8 gain8; + } vlOffset; + struct { + u8 mode; + u8 decimation; + } compression; + struct { + u8 frTargeting; + u8 targetFR; + u8 targetQ; + } compressionTarget; + struct { + u8 yThreshold; + u8 uvThreshold; + } yuvThreshold; + struct { + u8 hysteresis; + u8 threshMax; + u8 smallStep; + u8 largeStep; + u8 decimationHysteresis; + u8 frDiffStepThresh; + u8 qDiffStepThresh; + u8 decimationThreshMod; + } compressionParams; + struct { + u8 videoSize; /* CIF/QCIF */ + u8 subSample; + u8 yuvOrder; + } format; + + struct { /* GA 04/14/00 - Intel QX3 specific data */ + u8 qx3_detected; /* a QX3 is present */ + u8 toplight; /* top light lit , R/W */ + u8 bottomlight; /* bottom light lit, R/W */ + u8 button; /* snapshot button pressed (R/O) */ + u8 cradled; /* microscope is in cradle (R/O) */ + } qx3; + + struct { + u8 colStart; /* skip first 8*colStart pixels */ + u8 colEnd; /* finish at 8*colEnd pixels */ + u8 rowStart; /* skip first 4*rowStart lines */ + u8 rowEnd; /* finish at 4*rowEnd lines */ + } roi; + u8 ecpTiming; + u8 streamStartLine; +}; + +enum v4l_camstates { + CPIA_V4L_IDLE = 0, + CPIA_V4L_ERROR, + CPIA_V4L_COMMAND, + CPIA_V4L_GRABBING, + CPIA_V4L_STREAMING, + CPIA_V4L_STREAMING_PAUSED, +}; + +#define FRAME_NUM 2 /* double buffering for now */ + +struct cam_data { + struct cam_data **previous; + struct cam_data *next; + + struct semaphore busy_lock; /* guard against SMP multithreading */ + struct cpia_camera_ops *ops; /* lowlevel driver operations */ + void *lowlevel_data; /* private data for lowlevel driver */ + u8 *raw_image; /* buffer for raw image data */ + struct cpia_frame decompressed_frame; + /* buffer to hold decompressed frame */ + int image_size; /* sizeof last decompressed image */ + int open_count; /* # of process that have camera open */ + + /* camera status */ + int fps; /* actual fps reported by the camera */ + int transfer_rate; /* transfer rate from camera in kB/s */ + u8 mainsFreq; /* for flicker control */ + + /* proc interface */ + struct semaphore param_lock; /* params lock for this camera */ + struct cam_params params; /* camera settings */ + struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */ + + /* v4l */ + int video_size; /* VIDEO_SIZE_ */ + volatile enum v4l_camstates camstate; /* v4l layer status */ + struct video_device vdev; /* v4l videodev */ + struct video_picture vp; /* v4l camera settings */ + struct video_window vw; /* v4l capture area */ + + /* mmap interface */ + int curframe; /* the current frame to grab into */ + u8 *frame_buf; /* frame buffer data */ + struct cpia_frame frame[FRAME_NUM]; + /* FRAME_NUM-buffering, so we need a array */ + + int first_frame; + int mmap_kludge; /* 'wrong' byte order for mmap */ + volatile u32 cmd_queue; /* queued commands */ +}; + +/* cpia_register_camera is called by low level driver for each camera. + * A unique camera number is returned, or a negative value on error */ +struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel); + +/* cpia_unregister_camera is called by low level driver when a camera + * is removed. This must not fail. */ +void cpia_unregister_camera(struct cam_data *cam); + +/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI + + * one byte 16bit DMA alignment + */ +#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5) + +/* constant value's */ +#define MAGIC_0 0x19 +#define MAGIC_1 0x68 +#define DATA_IN 0xC0 +#define DATA_OUT 0x40 +#define VIDEOSIZE_QCIF 0 /* 176x144 */ +#define VIDEOSIZE_CIF 1 /* 352x288 */ +#define VIDEOSIZE_SIF 2 /* 320x240 */ +#define VIDEOSIZE_QSIF 3 /* 160x120 */ +#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */ +#define VIDEOSIZE_64_48 5 +#define VIDEOSIZE_128_96 6 +#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF +#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF +#define VIDEOSIZE_192_144 7 +#define VIDEOSIZE_224_168 8 +#define VIDEOSIZE_256_192 9 +#define VIDEOSIZE_288_216 10 +#define VIDEOSIZE_320_240 VIDEOSIZE_SIF +#define VIDEOSIZE_352_288 VIDEOSIZE_CIF +#define VIDEOSIZE_88_72 11 /* quarter CIF */ +#define SUBSAMPLE_420 0 +#define SUBSAMPLE_422 1 +#define YUVORDER_YUYV 0 +#define YUVORDER_UYVY 1 +#define NOT_COMPRESSED 0 +#define COMPRESSED 1 +#define NO_DECIMATION 0 +#define DECIMATION_ENAB 1 +#define EOI 0xff /* End Of Image */ +#define EOL 0xfd /* End Of Line */ +#define FRAME_HEADER_SIZE 64 + +/* Image grab modes */ +#define CPIA_GRAB_SINGLE 0 +#define CPIA_GRAB_CONTINUOUS 1 + +/* Compression parameters */ +#define CPIA_COMPRESSION_NONE 0 +#define CPIA_COMPRESSION_AUTO 1 +#define CPIA_COMPRESSION_MANUAL 2 +#define CPIA_COMPRESSION_TARGET_QUALITY 0 +#define CPIA_COMPRESSION_TARGET_FRAMERATE 1 + +/* Return offsets for GetCameraState */ +#define SYSTEMSTATE 0 +#define GRABSTATE 1 +#define STREAMSTATE 2 +#define FATALERROR 3 +#define CMDERROR 4 +#define DEBUGFLAGS 5 +#define VPSTATUS 6 +#define ERRORCODE 7 + +/* SystemState */ +#define UNINITIALISED_STATE 0 +#define PASS_THROUGH_STATE 1 +#define LO_POWER_STATE 2 +#define HI_POWER_STATE 3 +#define WARM_BOOT_STATE 4 + +/* GrabState */ +#define GRAB_IDLE 0 +#define GRAB_ACTIVE 1 +#define GRAB_DONE 2 + +/* StreamState */ +#define STREAM_NOT_READY 0 +#define STREAM_READY 1 +#define STREAM_OPEN 2 +#define STREAM_PAUSED 3 +#define STREAM_FINISHED 4 + +/* Fatal Error, CmdError, and DebugFlags */ +#define CPIA_FLAG 1 +#define SYSTEM_FLAG 2 +#define INT_CTRL_FLAG 4 +#define PROCESS_FLAG 8 +#define COM_FLAG 16 +#define VP_CTRL_FLAG 32 +#define CAPTURE_FLAG 64 +#define DEBUG_FLAG 128 + +/* VPStatus */ +#define VP_STATE_OK 0x00 + +#define VP_STATE_FAILED_VIDEOINIT 0x01 +#define VP_STATE_FAILED_AECACBINIT 0x02 +#define VP_STATE_AEC_MAX 0x04 +#define VP_STATE_ACB_BMAX 0x08 + +#define VP_STATE_ACB_RMIN 0x10 +#define VP_STATE_ACB_GMIN 0x20 +#define VP_STATE_ACB_RMAX 0x40 +#define VP_STATE_ACB_GMAX 0x80 + +/* ErrorCode */ +#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */ + +#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args) +#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args) + +#ifdef _CPIA_DEBUG_ +#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args) +#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args) +#else +#define DBG(fmn,args...) do {} while(0) +#endif + +#define DEB_BYTE(p)\ + DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\ + (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\ + (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0); + +#define ADD_TO_LIST(l, drv) \ + {\ + lock_kernel();\ + (drv)->next = l;\ + (drv)->previous = &(l);\ + (l) = drv;\ + unlock_kernel();\ + } while(0) + +#define REMOVE_FROM_LIST(drv) \ + {\ + if ((drv)->previous != NULL) {\ + lock_kernel();\ + if ((drv)->next != NULL)\ + (drv)->next->previous = (drv)->previous;\ + *((drv)->previous) = (drv)->next;\ + (drv)->previous = NULL;\ + (drv)->next = NULL;\ + unlock_kernel();\ + }\ + } while (0) + + +#endif /* __KERNEL__ */ + +#endif /* cpia_h */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/cpia_pp.c linux/drivers/char/cpia_pp.c --- v2.2.17/drivers/char/cpia_pp.c Fri Apr 21 12:45:51 2000 +++ linux/drivers/char/cpia_pp.c Fri Sep 1 13:51:28 2000 @@ -3,10 +3,9 @@ * * Supports CPiA based parallel port Video Camera's. * - * (C) 1999 Bas Huisman - * Scott J. Bertin , - * Peter Pregler - * Johannes Erdfelt + * (C) Copyright 1999 Bas Huisman + * (C) Copyright 1999-2000 Scott J. Bertin , + * (C) Copyright 1999-2000 Peter Pregler * * 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 @@ -24,6 +23,11 @@ */ #include +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +#undef CONFIG_VIDEO_CPIA_PP_DMA +#endif #include #include @@ -32,6 +36,8 @@ #include #include #include +#include + #ifdef CONFIG_VIDEO_CPIA_PP_DMA #include #endif @@ -41,6 +47,7 @@ #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) /* If this is a module and parport_pc is not, some parport_pc_* functions * are not directly availbale. parport.h messes this up. * This fixes what we need. @@ -67,11 +74,12 @@ #define parport_disable_irq(p) parport_pc_disable_irq(p) #endif /* parport_enable_irq */ #endif /* !PARPORT_NEED_GENERIC_OPS */ +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */ -#undef _CPIA_DEBUG_ /* define for verbose debug output */ -#include +/* #define _CPIA_DEBUG_ define for verbose debug output */ +#include "cpia.h" -static int cpia_pp_open(int camnr, void **privdata); +static int cpia_pp_open(void *privdata); static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata), void *cbdata); static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data); @@ -126,6 +134,8 @@ #define ECP_FIFO_SIZE 16 #define DMA_BUFFER_SIZE PAGE_SIZE /* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */ +#define PARPORT_CHUNK_SIZE PAGE_SIZE/* >=2.3.x */ + /* we read this many bytes at once */ #define GetECRMasked(port,mask) (parport_read_econtrol(port) & (mask)) #define GetStatus(port) ((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8)) @@ -139,7 +149,6 @@ #define ClearControlMasked(port,mask) SetControl(port,GetControl(port)&~(mask)); #define FrobControlBit(port,mask,value) SetControl(port,(GetControl(port)&~(mask))|((value)&(mask))); -#define PP_MAXCAMS (PARPORT_MAX & Peter Pregler "); MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras"); -MODULE_PARM(parport, "1-" __MODULE_STRING(PP_MAXCAMS) "s"); +MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s"); MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); #else -static int parport_nr[PP_MAXCAMS] __initdata = - {[0 ... PP_MAXCAMS - 1] = PPCPIA_PARPORT_UNSPEC}; +static int parport_nr[PARPORT_MAX] __initdata = + {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; static int parport_ptr = 0; #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) enum comstates { CPIA_FORWARD, CPIA_REVERSE }; //fixme enum camstates { CPIA_PHASE_idle = 0, @@ -187,16 +198,22 @@ "CPIA_PHASE_secpwrite", }; #endif +#endif + struct pp_cam_entry { struct pardevice *pdev; struct parport *port; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) enum comstates state; enum camstates camstate; +#endif struct tq_struct cb_task; int open_count; - int camnr; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) struct wait_queue *wq_stream; - +#else + wait_queue_head_t wq_stream; +#endif /* image state flags */ int image_ready; /* we got an interrupt */ int image_complete; /* we have seen 4 EOI */ @@ -220,8 +237,6 @@ #endif }; -static struct pp_cam_entry *camera[PP_MAXCAMS] = {[0 ... PP_MAXCAMS - 1] = NULL}; - static struct cpia_camera_ops cpia_pp_ops = { cpia_pp_open, @@ -230,9 +245,12 @@ cpia_pp_streamStart, cpia_pp_streamStop, cpia_pp_streamRead, - cpia_pp_close + cpia_pp_close, + 1 }; +static struct cam_data *cam_list; + #ifdef _CPIA_DEBUG_ #define DEB_PORT(port) { \ u8 controll = GetControl(port); \ @@ -258,17 +276,18 @@ /* FIXME */ static void cpia_parport_enable_irq( struct parport *port ) { - parport_enable_irq(port); - mdelay(10); - return; + parport_enable_irq(port); + mdelay(10); + return; } static void cpia_parport_disable_irq( struct parport *port ) { - parport_disable_irq(port); - mdelay(10); - return; + parport_disable_irq(port); + mdelay(10); + return; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) static int while_out(struct pp_cam_entry *cam) { struct parport *port = cam->port; @@ -709,7 +728,7 @@ release_dma_lock(flags); return cam->readbytes; } -#endif +#endif /* CONFIG_VIDEO_CPIA_PP_DMA */ /**************************************************************************** * @@ -779,6 +798,7 @@ return written; } +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */ /**************************************************************************** * @@ -787,10 +807,13 @@ ***************************************************************************/ static void EndTransferMode(struct pp_cam_entry *cam) { - if (!cam) return; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) if (cam->state == CPIA_REVERSE) Reverse2Forward(cam); Valid1284Termination(cam); if(cam->stream_irq) cpia_parport_enable_irq(cam->port); +#else + parport_negotiate(cam->port, IEEE1284_MODE_COMPAT); +#endif } /**************************************************************************** @@ -800,6 +823,7 @@ ***************************************************************************/ static int ForwardSetup(struct pp_cam_entry *cam) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) if(cam->stream_irq) cpia_parport_disable_irq(cam->port); if (!Negotiate2SetupPhase(cam, 0)) { if (!ECPSetupPhase(cam)) { @@ -812,6 +836,22 @@ } EndTransferMode(cam); return -1; +#else + int retry; + + /* After some commands the camera needs extra time before + * it will respond again, so we try up to 3 times */ + for(retry=0; retry<3; ++retry) { + if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) { + break; + } + } + if(retry == 3) { + DBG("Unable to negotiate ECP mode\n"); + return -1; + } + return 0; +#endif } /**************************************************************************** @@ -821,6 +861,7 @@ ***************************************************************************/ static int ReverseSetup(struct pp_cam_entry *cam, int extensibility) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) if(cam->stream_irq) cpia_parport_disable_irq(cam->port); if (!Negotiate2SetupPhase(cam, extensibility)) { if (!ECPSetupPhase(cam)) { @@ -837,6 +878,28 @@ } EndTransferMode(cam); return -1; +#else + int retry; + int mode = IEEE1284_MODE_ECP; + if(extensibility) mode = 8|3|IEEE1284_EXT_LINK; + + /* After some commands the camera needs extra time before + * it will respond again, so we try up to 3 times */ + for(retry=0; retry<3; ++retry) { + if(!parport_negotiate(cam->port, mode)) { + break; + } + } + if(retry == 3) { + if(extensibility) + DBG("Unable to negotiate extensibility mode\n"); + else + DBG("Unable to negotiate ECP mode\n"); + return -1; + } + if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP; + return 0; +#endif } #ifdef CONFIG_VIDEO_CPIA_PP_DMA @@ -967,7 +1030,7 @@ } return; } -#endif +#endif /* CONFIG_VIDEO_CPIA_PP_DMA */ /**************************************************************************** * @@ -975,6 +1038,7 @@ * ***************************************************************************/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) static void cpia_pp_irq_handler(int irq, void *handle, struct pt_regs *b) { struct pp_cam_entry *cam = handle; @@ -992,7 +1056,7 @@ } return; } -#endif +#endif /* CONFIG_VIDEO_CPIA_PP_DMA */ if (cam->camstate == CPIA_PHASE_ecpread) return; if( cam->camstate != CPIA_PHASE_idle ) DBG("got IRQ(%d) when in %s\n", @@ -1012,6 +1076,7 @@ } return; } +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */ /**************************************************************************** * @@ -1021,15 +1086,27 @@ static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size) { int retval=0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) + int size_written; +#endif if (packet == NULL) { return -EINVAL; } if (ForwardSetup(cam)) { + DBG("Write failed in setup\n"); return -EIO; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) if (SimECPWriteBuffer(cam, packet, size) != size) { retval = -EIO; } +#else + size_written = parport_write(cam->port, packet, size); + if(size_written != size) { + DBG("Write failed, wrote %d/%d\n", size_written, size); + retval = -EIO; + } +#endif EndTransferMode(cam); return retval; } @@ -1048,9 +1125,15 @@ if (ReverseSetup(cam, 0)) { return -EIO; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) if (SimECPReadBuffer(cam, packet, size) != size) { retval = -EIO; } +#else + if(parport_read(cam->port, packet, size) != size) { + retval = -EIO; + } +#endif EndTransferMode(cam); return retval; } @@ -1068,7 +1151,6 @@ cam->image_ready=0; //if (ReverseSetup(cam,1)) return -EIO; if(cam->stream_irq) cpia_parport_enable_irq(cam->port); - return 0; } @@ -1089,6 +1171,20 @@ return 0; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +static int cpia_pp_read(struct parport *port, u8 *buffer, int len) +{ + int bytes_read, new_bytes; + for(bytes_read=0; bytes_read= KERNEL_VERSION(2,3,0)) + int i, endseen, block_size, new_bytes; +#endif + if(cam == NULL) { DBG("Internal driver error: cam is NULL\n"); return -EINVAL; @@ -1120,8 +1220,12 @@ DBG("%d\n", cam->image_ready); } } else { - if (ReverseSetup(cam, 1)) return -EIO; + if (ReverseSetup(cam, 1)) { + DBG("unable to ReverseSetup\n"); + return -EIO; + } } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) read_bytes = ECPReadBuffer(cam, buffer, CPIA_MAX_IMAGE_SIZE); if( 1/*!cam->streaming*/) { EndTransferMode(cam); @@ -1131,6 +1235,36 @@ DBG("incomplete image: %ld / %d / %d\n", jiffies, cam->image_complete, read_bytes); } +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */ + endseen = 0; + block_size = PARPORT_CHUNK_SIZE; + while( !cam->image_complete ) { + if(current->need_resched) schedule(); + + new_bytes = cpia_pp_read(cam->port, buffer, block_size ); + if( new_bytes <= 0 ) { + break; + } + i=-1; + while(++iimage_complete=1; + break; + } + if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) { + block_size=CPIA_MAX_IMAGE_SIZE-read_bytes; + } + } + EndTransferMode(cam); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */ return cam->image_complete ? read_bytes : -EIO; } @@ -1145,6 +1279,7 @@ int retval=0; int databytes; struct pp_cam_entry *cam = privdata; + if(cam == NULL) { DBG("Internal driver error: cam is NULL\n"); return -EINVAL; @@ -1155,6 +1290,7 @@ } databytes = (((int)command[7])<<8) | command[6]; if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) { + DBG("Error writing command\n"); return err; } if(command[0] == DATA_IN) { @@ -1163,9 +1299,9 @@ DBG("Internal driver error: data is NULL\n"); return -EINVAL; } - err = ReadPacket(cam, buffer, 8); - if(err < 0) { + if((err = ReadPacket(cam, buffer, 8)) < 0) { return err; + DBG("Error reading command result\n"); } memcpy(data, buffer, databytes); } else if(command[0] == DATA_OUT) { @@ -1174,7 +1310,10 @@ DBG("Internal driver error: data is NULL\n"); retval = -EINVAL; } else { - WritePacket(cam, data, databytes); + if((err=WritePacket(cam, data, databytes)) < 0){ + DBG("Error writing command data\n"); + return err; + } } } } else { @@ -1189,29 +1328,19 @@ * cpia_pp_open * ***************************************************************************/ -static int cpia_pp_open(int camnr, void **privdata) +static int cpia_pp_open(void *privdata) { - struct pp_cam_entry *cam=NULL; - int i; - for(i=0; icamnr == camnr) { - DBG("Found camera[%d]\n", camnr); - break; - } - } + struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata; - *privdata = cam; + if (cam == NULL) + return -EINVAL; if(cam->open_count == 0) { if (parport_claim(cam->pdev)) { DBG("failed to claim the port\n"); return -EBUSY; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) parport_write_econtrol(cam->port, PARPORT_MODE_PCECR); parport_frob_econtrol(cam->port, ECR_serviceIntr|ECR_dmaEn|ECR_nErrIntrEn, @@ -1222,6 +1351,15 @@ #endif cam->stream_irq=0; cpia_parport_disable_irq(cam->port); +#else + parport_negotiate(cam->port, IEEE1284_MODE_COMPAT); + parport_data_forward(cam->port); + parport_write_control(cam->port, PARPORT_CONTROL_SELECT); + udelay(50); + parport_write_control(cam->port, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); +#endif } ++cam->open_count; @@ -1266,6 +1404,7 @@ MOD_DEC_USE_COUNT; #endif if (--cam->open_count == 0) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) if (cam->port->irq != PARPORT_IRQ_NONE) { cpia_parport_disable_irq(cam->port); } @@ -1278,11 +1417,12 @@ interruptible_sleep_on(&cam->wq_dma); } restore_flags(flags); -#endif +#endif /* CONFIG_VIDEO_CPIA_PP_DMA */ if (waitqueue_active(&cam->wq_stream)) { /* FIXME */ wake_up(&cam->wq_stream); } +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */ parport_release(cam->pdev); } return 0; @@ -1293,47 +1433,55 @@ * cpia_pp_register * ***************************************************************************/ -static int cpia_pp_register(int nr, struct parport *port) +static int cpia_pp_register(struct parport *port) { struct pardevice *pdev = NULL; - int camnr; + struct pp_cam_entry *cam; + struct cam_data *cpia; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) if (!(port->modes & PARPORT_MODE_PCECP)) { +#else + if (!(port->modes & PARPORT_MODE_ECP) && + !(port->modes & PARPORT_MODE_TRISTATE)) { +#endif LOG("port is not ECP capable\n"); return -ENXIO; } - if((camnr = cpia_register_camera(&cpia_pp_ops)) < 0) { - LOG("failed to cpia_register_camera\n"); - return -ENXIO; - } - camera[nr] = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL); - if (camera[nr] == NULL) { + cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL); + if (cam == NULL) { LOG("failed to allocate camera structure\n"); - cpia_unregister_camera(camnr); return -ENOMEM; } - memset(camera[nr],0,sizeof(struct pp_cam_entry)); + memset(cam,0,sizeof(struct pp_cam_entry)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + pdev = parport_register_device(port, "cpia_pp", NULL, NULL, + cpia_pp_irq_handler, 0, cam); +#else pdev = parport_register_device(port, "cpia_pp", NULL, NULL, - cpia_pp_irq_handler, 0, camera[nr]); + NULL, 0, cam); +#endif if (!pdev) { LOG("failed to parport_register_device\n"); - cpia_unregister_camera(camnr); - kfree(camera[nr]); + kfree(cam); return -ENXIO; } - camera[nr]->pdev = pdev; - camera[nr]->port = port; - camera[nr]->state = CPIA_FORWARD; - camera[nr]->camstate = CPIA_PHASE_idle; - camera[nr]->camnr = camnr; - init_waitqueue(&camera[nr]->wq_stream); + cam->pdev = pdev; + cam->port = port; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + cam->state = CPIA_FORWARD; + cam->camstate = CPIA_PHASE_idle; + init_waitqueue(&cam->wq_stream); +#else + init_waitqueue_head(&cam->wq_stream); +#endif - camera[nr]->streaming = 0; - camera[nr]->stream_irq = 0; + cam->streaming = 0; + cam->stream_irq = 0; #ifdef CONFIG_VIDEO_CPIA_PP_DMA if (pdev->port->irq != PARPORT_IRQ_NONE && @@ -1341,66 +1489,151 @@ if(request_dma(pdev->port->dma, "cpia_pp")) { LOG("failed to register dma %d\n", pdev->port->dma); parport_unregister_device(pdev); - cpia_unregister_camera(camnr); - kfree(camera[nr]); + kfree(cam); return -ENXIO; } - camera[nr]->dma_buf=kmalloc(DMA_BUFFER_SIZE, GFP_DMA); - if(camera[nr]->dma_buf == NULL) { - free_dma(camera[nr]->pdev->port->dma); - LOG("failed to allocate dma buffer, using FIFO mode\n"); + cam->dma_buf=kmalloc(DMA_BUFFER_SIZE, GFP_DMA); + if(cam->dma_buf == NULL) { + free_dma(cam->pdev->port->dma); + LOG("failed to allocate dma buffer, using PIO mode\n"); } else { - init_waitqueue(&camera[nr]->wq_dma); + init_waitqueue(&cam->wq_dma); printk(KERN_INFO " using DMA mode (irq %d, DMA %d)\n", pdev->port->irq, pdev->port->dma); } - memset(camera[nr]->dma_buf, 0, DMA_BUFFER_SIZE); + memset(cam->dma_buf, 0, DMA_BUFFER_SIZE); } else { printk(KERN_INFO " using PIO mode\n"); } #endif + if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) { + LOG("failed to cpia_register_camera\n"); +#ifdef CONFIG_VIDEO_CPIA_PP_DMA + if (cam->dma_buf) { + free_dma(cam->pdev->port->dma); + kfree(cam->dma_buf); + } +#endif + parport_unregister_device(pdev); + kfree(cam); + return -ENXIO; + } + ADD_TO_LIST(cam_list, cpia); + return 0; } +static void cpia_pp_detach (struct parport *port) +{ + struct cam_data *cpia; + + for(cpia = cam_list; cpia != NULL; cpia = cpia->next) { + struct pp_cam_entry *cam = cpia->lowlevel_data; + if (cam && cam->port->number == port->number) { + REMOVE_FROM_LIST(cpia); + +#ifdef CONFIG_VIDEO_CPIA_PP_DMA + if (cam->dma_buf) { + free_dma(cam->pdev->port->dma); + kfree(cam->dma_buf); + } +#endif + + cpia_unregister_camera(cpia); + + if(cam->open_count > 0) { + cpia_pp_close(cam); + } + + parport_unregister_device(cam->pdev); + + kfree(cam); + cpia->lowlevel_data = NULL; + break; + } + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +static void cpia_pp_attach (struct parport *port) +{ + unsigned int i; + + switch (parport_nr[0]) + { + case PPCPIA_PARPORT_UNSPEC: + case PPCPIA_PARPORT_AUTO: + if (port->probe_info[0].class != PARPORT_CLASS_MEDIA || + port->probe_info[0].cmdset == NULL || + strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0) + return; + + cpia_pp_register(port); + + break; + + default: + for (i = 0; i < PARPORT_MAX; ++i) { + if (port->number == parport_nr[i]) { + cpia_pp_register(port); + break; + } + } + break; + } +} + +static struct parport_driver cpia_pp_driver = { + "cpia_pp", + cpia_pp_attach, + cpia_pp_detach, + NULL +}; +#endif + int cpia_pp_init(void) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) struct parport *port; int i, count = 0; +#endif printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); - switch (parport_nr[0]) { - case PPCPIA_PARPORT_OFF: + if(parport_nr[0] == PPCPIA_PARPORT_OFF) { printk(" disabled\n"); return 0; - + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + switch (parport_nr[0]) { case PPCPIA_PARPORT_UNSPEC: case PPCPIA_PARPORT_AUTO: for (port = parport_enumerate(); port; port = port->next) { #if defined(CONFIG_PNP_PARPORT) || \ (defined(MODULE) && defined(CONFIG_PNP_PARPORT_MODULE)) - if (port->probe_info.class != PARPORT_CLASS_MEDIA || - port->probe_info.cmdset == NULL || - strncmp(port->probe_info.cmdset, "CPIA_1", 6) != 0){ - continue; + if(port->probe_info.model) { + if (port->probe_info.class != PARPORT_CLASS_MEDIA || + port->probe_info.cmdset == NULL || + strncmp(port->probe_info.cmdset, "CPIA_1", 6) != 0){ + continue; + } } #endif - - if (cpia_pp_register(count, port) == 0 && - ++count == PP_MAXCAMS) { - break; + if (!cpia_pp_register(port)) { + ++count; } } break; default: - for (i = 0; i < PP_MAXCAMS; i++) { + for (i = 0; i < PARPORT_MAX; i++) { for (port = parport_enumerate(); port; port = port->next) { if (port->number == parport_nr[i]) { - if (!cpia_pp_register(i, port)) { + if (!cpia_pp_register(port)) { count++; } break; @@ -1414,6 +1647,13 @@ if (count == 0) { return -ENODEV; } +#else /* kernel version >= 2.3.0 */ + if (parport_register_driver (&cpia_pp_driver)) { + LOG ("unable to register with parport\n"); + return -EIO; + } +#endif /* kernel version >= 2.3.0 */ + return 0; } @@ -1426,7 +1666,7 @@ parport_nr[0] = PPCPIA_PARPORT_AUTO; } else { int n; - for (n = 0; n < PP_MAXCAMS && parport[n]; n++) { + for (n = 0; n < PARPORT_MAX && parport[n]; n++) { if (!strncmp(parport[n], "none", 4)) { parport_nr[n] = PPCPIA_PARPORT_NONE; } else { @@ -1443,31 +1683,23 @@ } } #if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE) - request_module("parport_probe"); + if(parport_enumerate() && !parport_enumerate()->probe_info.model) { + request_module("parport_probe"); + } #endif return cpia_pp_init(); } void cleanup_module(void) { - int i; - for (i = 0; camera[i] != NULL && i < PP_MAXCAMS; i++) { - while(camera[i]->open_count > 0) { - LOG("You forgot to close camera %d, will do it for you\n", camera[i]->camnr); - cpia_pp_close(camera[i]); - } - -#ifdef CONFIG_VIDEO_CPIA_PP_DMA - if (camera[i]->dma_buf) { - free_dma(camera[i]->pdev->port->dma); - kfree(camera[i]->dma_buf); - } -#endif - - cpia_unregister_camera(camera[i]->camnr); - parport_unregister_device(camera[i]->pdev); - kfree(camera[i]); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) + parport_unregister_driver (&cpia_pp_driver); +#else + while(cam_list != NULL) { + struct pp_cam_entry *cam = cam_list->lowlevel_data; + cpia_pp_detach(cam->port); } +#endif return; } @@ -1482,7 +1714,7 @@ } } else if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str + 7, NULL, 10); - if (parport_ptr < PP_MAXCAMS) { + if (parport_ptr < PARPORT_MAX) { parport_nr[parport_ptr++] = n; } else { LOG("too many ports, %s ignored.\n", str); @@ -1493,5 +1725,8 @@ parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; } } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +__setup("cpia_pp=", cpia_pp_setup); +#endif #endif /* !MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/cpia_usb.c linux/drivers/char/cpia_usb.c --- v2.2.17/drivers/char/cpia_usb.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/cpia_usb.c Fri Sep 1 13:51:28 2000 @@ -0,0 +1,636 @@ +/* + * cpia_usb CPiA USB driver + * + * Supports CPiA based parallel port Video Camera's. + * + * Copyright (C) 1999 Jochen Scharrlach + * Copyright (C) 1999, 2000 Johannes Erdfelt + * + * 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 "cpia.h" + +#define USB_REQ_CPIA_GRAB_FRAME 0xC1 +#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2 +#define WAIT_FOR_NEXT_FRAME 0 +#define FORCE_FRAME_UPLOAD 1 + +#define FRAMES_PER_DESC 10 +#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */ +#define CPIA_NUMSBUF 2 +#define STREAM_BUF_SIZE (PAGE_SIZE * 4) +#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) + +struct cpia_sbuf { + char *data; + urb_t *urb; +}; + +#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100) +enum framebuf_status { + FRAME_EMPTY, + FRAME_READING, + FRAME_READY, + FRAME_ERROR, +}; + +struct framebuf { + int length; + enum framebuf_status status; + u8 data[FRAMEBUF_LEN]; + struct framebuf *next; +}; + +struct usb_cpia { + /* Device structure */ + struct usb_device *dev; + + unsigned char iface; + wait_queue_head_t wq_stream; + + int cursbuf; /* Current receiving sbuf */ + struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */ + + int streaming; + int open; + int present; + struct framebuf *buffers[3]; + struct framebuf *curbuff, *workbuff; +}; + +static int cpia_usb_open(void *privdata); +static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata), + void *cbdata); +static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data); +static int cpia_usb_streamStart(void *privdata); +static int cpia_usb_streamStop(void *privdata); +static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock); +static int cpia_usb_close(void *privdata); + +#define ABOUT "USB driver for Vision CPiA based cameras" + +static struct cpia_camera_ops cpia_usb_ops = { + cpia_usb_open, + cpia_usb_registerCallback, + cpia_usb_transferCmd, + cpia_usb_streamStart, + cpia_usb_streamStop, + cpia_usb_streamRead, + cpia_usb_close, + 0 +}; + +static struct cam_data *cam_list; + +static void cpia_usb_complete(struct urb *urb) +{ + int i; + char *cdata; + struct usb_cpia *ucpia; + + if (!urb || !urb->context) + return; + + ucpia = (struct usb_cpia *) urb->context; + + if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open) + return; + + if (ucpia->workbuff->status == FRAME_EMPTY) { + ucpia->workbuff->status = FRAME_READING; + ucpia->workbuff->length = 0; + } + + for (i = 0; i < urb->number_of_packets; i++) { + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (st) + printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st); + + if (FRAMEBUF_LEN < ucpia->workbuff->length + n) { + printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n); + return; + } + + if (n) { + if ((ucpia->workbuff->length > 0) || + (0x19 == cdata[0] && 0x68 == cdata[1])) { + memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n); + ucpia->workbuff->length += n; + } else + DBG("Ignoring packet!\n"); + } else { + if (ucpia->workbuff->length > 4 && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] && + 0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) { + ucpia->workbuff->status = FRAME_READY; + ucpia->curbuff = ucpia->workbuff; + ucpia->workbuff = ucpia->workbuff->next; + ucpia->workbuff->status = FRAME_EMPTY; + ucpia->workbuff->length = 0; + + if (waitqueue_active(&ucpia->wq_stream)) + wake_up_interruptible(&ucpia->wq_stream); + } + } + } +} + +static int cpia_usb_open(void *privdata) +{ + struct usb_cpia *ucpia = (struct usb_cpia *) privdata; + urb_t *urb; + int ret, retval = 0, fx, err; + + if (!ucpia) + return -EINVAL; + + ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ucpia->sbuf[0].data) + return -EINVAL; + + ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!ucpia->sbuf[1].data) { + retval = -EINVAL; + goto error_0; + } + + ret = usb_set_interface(ucpia->dev, ucpia->iface, 3); + if (ret < 0) { + printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret); + retval = -EBUSY; + goto error_all; + } + + ucpia->buffers[0]->status = FRAME_EMPTY; + ucpia->buffers[0]->length = 0; + ucpia->buffers[1]->status = FRAME_EMPTY; + ucpia->buffers[1]->length = 0; + ucpia->buffers[2]->status = FRAME_EMPTY; + ucpia->buffers[2]->length = 0; + ucpia->curbuff = ucpia->buffers[0]; + ucpia->workbuff = ucpia->buffers[1]; + + /* We double buffer the Iso lists */ + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { + printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); + retval = -ENOMEM; + goto error_all; + } + + ucpia->sbuf[0].urb = urb; + urb->dev = ucpia->dev; + urb->context = ucpia; + urb->pipe = usb_rcvisocpipe(ucpia->dev, 1); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ucpia->sbuf[0].data; + urb->complete = cpia_usb_complete; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { + printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); + retval = -ENOMEM; + goto error_all; + } + + ucpia->sbuf[1].urb = urb; + urb->dev = ucpia->dev; + urb->context = ucpia; + urb->pipe = usb_rcvisocpipe(ucpia->dev, 1); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ucpia->sbuf[1].data; + urb->complete = cpia_usb_complete; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb; + ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb; + + err = usb_submit_urb(ucpia->sbuf[0].urb); + if (err) + printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n", + err); + err = usb_submit_urb(ucpia->sbuf[1].urb); + if (err) + printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n", + err); + + ucpia->streaming = 1; + ucpia->open = 1; + + return 0; + +error_all: + kfree (ucpia->sbuf[1].data); +error_0: + kfree (ucpia->sbuf[0].data); + + return retval; +} + +// +// convenience functions +// + +/**************************************************************************** + * + * WritePacket + * + ***************************************************************************/ +static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size) +{ + if (!packet) + return -EINVAL; + + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + packet[1] + (packet[0] << 8), + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + packet[2] + (packet[3] << 8), + packet[4] + (packet[5] << 8), buf, size, HZ); +} + +/**************************************************************************** + * + * ReadPacket + * + ***************************************************************************/ +static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size) +{ + if (!packet || size <= 0) + return -EINVAL; + + return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + packet[1] + (packet[0] << 8), + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + packet[2] + (packet[3] << 8), + packet[4] + (packet[5] << 8), buf, size, HZ); +} + +static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data) +{ + int err = 0; + int databytes; + struct usb_cpia *ucpia = (struct usb_cpia *)privdata; + struct usb_device *udev = ucpia->dev; + + if (!udev) { + DBG("Internal driver error: udev is NULL\n"); + return -EINVAL; + } + + if (!command) { + DBG("Internal driver error: command is NULL\n"); + return -EINVAL; + } + + databytes = (((int)command[7])<<8) | command[6]; + + if (command[0] == DATA_IN) { + u8 buffer[8]; + + if (!data) { + DBG("Internal driver error: data is NULL\n"); + return -EINVAL; + } + + err = ReadPacket(udev, command, buffer, 8); + if (err < 0) + return err; + + memcpy(data, buffer, databytes); + } else if(command[0] == DATA_OUT) + WritePacket(udev, command, data, databytes); + else { + DBG("Unexpected first byte of command: %x\n", command[0]); + err = -EINVAL; + } + + return 0; +} + +static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata), + void *cbdata) +{ + return -ENODEV; +} + +static int cpia_usb_streamStart(void *privdata) +{ + return -ENODEV; +} + +static int cpia_usb_streamStop(void *privdata) +{ + return -ENODEV; +} + +static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock) +{ + struct usb_cpia *ucpia = (struct usb_cpia *) privdata; + struct framebuf *mybuff; + + if (!ucpia || !ucpia->present) + return -1; + + if (ucpia->curbuff->status != FRAME_READY) + interruptible_sleep_on(&ucpia->wq_stream); + else + DBG("Frame already waiting!\n"); + + mybuff = ucpia->curbuff; + + if (!mybuff) + return -1; + + if (mybuff->status != FRAME_READY || mybuff->length < 4) { + DBG("Something went wrong!\n"); + return -1; + } + + memcpy(frame, mybuff->data, mybuff->length); + mybuff->status = FRAME_EMPTY; + +/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */ +/* mybuff->length, frame[0], frame[1], */ +/* frame[mybuff->length-4], frame[mybuff->length-3], */ +/* frame[mybuff->length-2], frame[mybuff->length-1]); */ + + return mybuff->length; +} + +static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try) +{ + if (!ucpia->streaming) + return; + + ucpia->streaming = 0; + + /* Set packet size to 0 */ + if (try) { + int ret; + + ret = usb_set_interface(ucpia->dev, ucpia->iface, 0); + if (ret < 0) { + printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret); + return; + } + } + + /* Unschedule all of the iso td's */ + if (ucpia->sbuf[1].urb) { + usb_unlink_urb(ucpia->sbuf[1].urb); + usb_free_urb(ucpia->sbuf[1].urb); + ucpia->sbuf[1].urb = NULL; + } + + if (ucpia->sbuf[0].urb) { + usb_unlink_urb(ucpia->sbuf[0].urb); + usb_free_urb(ucpia->sbuf[0].urb); + ucpia->sbuf[0].urb = NULL; + } +} + +static int cpia_usb_close(void *privdata) +{ + struct usb_cpia *ucpia = (struct usb_cpia *) privdata; + + ucpia->open = 0; + + cpia_usb_free_resources(ucpia, 1); + + if (!ucpia->present) + kfree(ucpia); + + return 0; +} + +int cpia_usb_init(void) +{ + /* return -ENODEV; */ + return 0; +} + +/* Probing and initializing */ + +static void *cpia_probe(struct usb_device *udev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + struct usb_cpia *ucpia; + struct cam_data *cam; + int ret; + + /* A multi-config CPiA camera? */ + if (udev->descriptor.bNumConfigurations != 1) + return NULL; + + interface = &udev->actconfig->interface[ifnum].altsetting[0]; + + /* Is it a CPiA? */ + if (!((udev->descriptor.idVendor == 0x0553 && + udev->descriptor.idProduct == 0x0002) || + (udev->descriptor.idVendor == 0x0813 && + udev->descriptor.idProduct == 0x0001))) /* GA 04/14/00 */ + return NULL; + + /* We found a CPiA */ + printk(KERN_INFO "USB CPiA camera found\n"); + + ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL); + if (!ucpia) { + printk(KERN_ERR "couldn't kmalloc cpia struct\n"); + return NULL; + } + + memset(ucpia, 0, sizeof(*ucpia)); + + ucpia->dev = udev; + ucpia->iface = interface->bInterfaceNumber; + init_waitqueue_head(&ucpia->wq_stream); + + ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0])); + if (!ucpia->buffers[0]) { + printk(KERN_ERR "couldn't vmalloc frame buffer 0\n"); + goto fail_alloc_0; + } + + ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1])); + if (!ucpia->buffers[1]) { + printk(KERN_ERR "couldn't vmalloc frame buffer 1\n"); + goto fail_alloc_1; + } + + ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2])); + if (!ucpia->buffers[2]) { + printk(KERN_ERR "couldn't vmalloc frame buffer 2\n"); + goto fail_alloc_2; + } + + ucpia->buffers[0]->next = ucpia->buffers[1]; + ucpia->buffers[1]->next = ucpia->buffers[2]; + ucpia->buffers[2]->next = ucpia->buffers[0]; + + ret = usb_set_interface(udev, ucpia->iface, 0); + if (ret < 0) { + printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret); + /* goto fail_all; */ + } + + /* Before register_camera, important */ + ucpia->present = 1; + + cam = cpia_register_camera(&cpia_usb_ops, ucpia); + if (!cam) { + LOG("failed to cpia_register_camera\n"); + goto fail_all; + } + + ADD_TO_LIST(cam_list, cam); + + return cam; + +fail_all: + vfree(ucpia->buffers[2]); + ucpia->buffers[2] = NULL; +fail_alloc_2: + vfree(ucpia->buffers[1]); + ucpia->buffers[1] = NULL; +fail_alloc_1: + vfree(ucpia->buffers[0]); + ucpia->buffers[0] = NULL; +fail_alloc_0: + + return NULL; +} + +static void cpia_disconnect(struct usb_device *dev, void *ptr); + +static struct usb_driver cpia_driver = { + "cpia", + cpia_probe, + cpia_disconnect, + { NULL, NULL } +}; + +/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */ +/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */ +/* will do it for us as well as passing a udev structure - jerdfelt */ +static void cpia_disconnect(struct usb_device *udev, void *ptr) +{ + struct cam_data *cam = (struct cam_data *) ptr; + struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data; + + REMOVE_FROM_LIST(cam); + + /* Don't even try to reset the altsetting if we're disconnected */ + cpia_usb_free_resources(ucpia, 0); + + ucpia->present = 0; + + cpia_unregister_camera(cam); + + ucpia->curbuff->status = FRAME_ERROR; + + if (waitqueue_active(&ucpia->wq_stream)) + wake_up_interruptible(&ucpia->wq_stream); + + usb_driver_release_interface(&cpia_driver, + &udev->actconfig->interface[0]); + + ucpia->curbuff = ucpia->workbuff = NULL; + + if (ucpia->buffers[2]) { + vfree(ucpia->buffers[2]); + ucpia->buffers[2] = NULL; + } + + if (ucpia->buffers[1]) { + vfree(ucpia->buffers[1]); + ucpia->buffers[1] = NULL; + } + + if (ucpia->buffers[0]) { + vfree(ucpia->buffers[0]); + ucpia->buffers[0] = NULL; + } + + if (!ucpia->open) + kfree(ucpia); +} + +int usb_cpia_init(void) +{ + cam_list = NULL; + + return usb_register(&cpia_driver); +} + +void usb_cpia_cleanup(void) +{ +/* + struct cam_data *cam; + + while ((cam = cam_list) != NULL) + cpia_disconnect(NULL, cam); +*/ + + usb_deregister(&cpia_driver); +} + +#ifdef MODULE +int init_module(void) +{ + return usb_cpia_init(); +} + +void cleanup_module(void) +{ + usb_cpia_cleanup(); +} + +#else /* !MODULE */ + +__initfunc(void cpia_usb_setup(char *str, int *ints)) +{ +} + +#endif /* !MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/Config.in linux/drivers/char/drm/Config.in --- v2.2.17/drivers/char/drm/Config.in Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/Config.in Fri Sep 1 14:12:32 2000 @@ -0,0 +1,15 @@ +# +# drm device configuration +# +# This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.x. +# + +tristate 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM +if [ "$CONFIG_DRM" != "n" ]; then + tristate ' 3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX + tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA + tristate ' ATI Rage 128' CONFIG_DRM_R128 + dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP + dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP +fi diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/Makefile linux/drivers/char/drm/Makefile --- v2.2.17/drivers/char/drm/Makefile Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/Makefile Fri Sep 1 14:12:32 2000 @@ -0,0 +1,88 @@ +# +# Makefile for the drm device driver. This driver provides support for +# the Direct Rendering Infrastructure (DRI) in XFree86 4.x. +# + +# drm.o is a fake target -- it is never built +# The real targets are in the module-list +O_TARGET := drm.o +module-list := gamma.o tdfx.o r128.o ffb.o mga.o i810.o +export-objs := $(patsubst %.o,%_drv.o,$(module-list)) + +# libs-objs are included in every module so that radical changes to the +# architecture of the DRM support library can be made at a later time. +# +# The downside is that each module is larger, and a system that uses +# more than one module (i.e., a dual-head system) will use more memory +# (but a system that uses exactly one module will use the same amount of +# memory). +# +# The upside is that if the DRM support library ever becomes insufficient +# for new families of cards, a new library can be implemented for those new +# cards without impacting the drivers for the old cards. This is significant, +# because testing architectural changes to old cards may be impossible, and +# may delay the implementation of a better architecture. We've traded slight +# memory waste (in the dual-head case) for greatly improved long-term +# maintainability. +# +lib-objs := init.o memory.o proc.o auth.o context.o drawable.o bufs.o +lib-objs += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o + +ifeq ($(CONFIG_AGP),y) + lib-objs += agpsupport.o +else + ifeq ($(CONFIG_AGP),m) + lib-objs += agpsupport.o + endif +endif + +gamma-objs := $(lib-objs) gamma_drv.o gamma_dma.o +tdfx-objs := $(lib-objs) tdfx_drv.o tdfx_context.o +r128-objs := $(lib-objs) r128_drv.o r128_dma.o r128_context.o r128_bufs.o +ffb-objs := $(lib-objs) ffb_drv.o ffb_context.o +mga-objs := $(lib-objs) mga_drv.o mga_dma.o mga_context.o mga_bufs.o \ + mga_state.o +i810-objs := $(lib-objs) i810_drv.o i810_dma.o i810_context.o i810_bufs.o + +obj-$(CONFIG_DRM_GAMMA) += gamma.o $(gamma-objs) +obj-$(CONFIG_DRM_TDFX) += tdfx.o $(tdfx-objs) +obj-$(CONFIG_DRM_R128) += r128.o $(r128-objs) +obj-$(CONFIG_DRM_FFB) += ffb.o $(ffb-objs) + +ifneq ($CONFIG_AGP),) +obj-$(CONFIG_DRM_MGA) += mga.o $(mga-objs) +obj-$(CONFIG_DRM_I810) += i810.o $(i810-objs) +endif + +# Take module names out of obj-y and int-m + +obj-y := $(filter-out $(module-list), $(obj-y)) +int-m := $(filter-out $(module-list), $(obj-m)) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter $(module-list), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +include $(TOPDIR)/Rules.make + +gamma.o: $(gamma-objs) + $(LD) -r -o $@ $(gamma-objs) + +tdfx.o: $(tdfx-objs) + $(LD) -r -o $@ $(tdfx-objs) + +mga.o: $(mga-objs) + $(LD) -r -o $@ $(mga-objs) + +i810.o: $(i810-objs) + $(LD) -r -o $@ $(i810-objs) + +r128.o: $(r128-objs) + $(LD) -r -o $@ $(r128-objs) + +ffb.o: $(ffb-objs) + $(LD) -r -o $@ $(ffb-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/README.drm linux/drivers/char/drm/README.drm --- v2.2.17/drivers/char/drm/README.drm Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/README.drm Fri Sep 1 14:12:32 2000 @@ -0,0 +1,41 @@ + +The Direct Rendering Manager (drm) is a device-independent kernel-level +device driver that provides support for the XFree86 Direct Rendering +Infrastructure (DRI). + +The DRM supports the Direct Rendering Infrastructure (DRI) in four major +ways: + + 1. The DRM provides synchronized access to the graphics hardware via + the use of an optimized two-tiered lock. + + 2. The DRM enforces the DRI security policy for access to the graphics + hardware by only allowing authenticated X11 clients access to + restricted regions of memory. + + 3. The DRM provides a generic DMA engine, complete with multiple + queues and the ability to detect the need for an OpenGL context + switch. + + 4. The DRM is extensible via the use of small device-specific modules + that rely extensively on the API exported by the DRM module. + + +Documentation on the DRI is available from: + http://precisioninsight.com/piinsights.html + +For specific information about kernel-level support, see: + + The Direct Rendering Manager, Kernel Support for the Direct Rendering + Infrastructure + http://precisioninsight.com/dr/drm.html + + Hardware Locking for the Direct Rendering Infrastructure + http://precisioninsight.com/dr/locking.html + + A Security Analysis of the Direct Rendering Infrastructure + 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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/agpsupport.c linux/drivers/char/drm/agpsupport.c --- v2.2.17/drivers/char/drm/agpsupport.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/agpsupport.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,345 @@ +/* agpsupport.c -- DRM support for AGP/GART backend -*- linux-c -*- + * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Author: Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include + +drm_agp_func_t drm_agp = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +/* The C standard says that 'void *' is not guaranteed to hold a function + pointer, so we use this union to define a generic pointer that is + guaranteed to hold any of the function pointers we care about. */ +typedef union { + void (*free_memory)(agp_memory *); + agp_memory *(*allocate_memory)(size_t, u32); + int (*bind_memory)(agp_memory *, off_t); + int (*unbind_memory)(agp_memory *); + void (*enable)(u32); + int (*acquire)(void); + void (*release)(void); + void (*copy_info)(agp_kern_info *); + unsigned long address; +} drm_agp_func_u; + +typedef struct drm_agp_fill { + const char *name; + drm_agp_func_u *f; +} drm_agp_fill_t; + +static drm_agp_fill_t drm_agp_fill[] = { + { __MODULE_STRING(agp_free_memory), + (drm_agp_func_u *)&drm_agp.free_memory }, + { __MODULE_STRING(agp_allocate_memory), + (drm_agp_func_u *)&drm_agp.allocate_memory }, + { __MODULE_STRING(agp_bind_memory), + (drm_agp_func_u *)&drm_agp.bind_memory }, + { __MODULE_STRING(agp_unbind_memory), + (drm_agp_func_u *)&drm_agp.unbind_memory }, + { __MODULE_STRING(agp_enable), + (drm_agp_func_u *)&drm_agp.enable }, + { __MODULE_STRING(agp_backend_acquire), + (drm_agp_func_u *)&drm_agp.acquire }, + { __MODULE_STRING(agp_backend_release), + (drm_agp_func_u *)&drm_agp.release }, + { __MODULE_STRING(agp_copy_info), + (drm_agp_func_u *)&drm_agp.copy_info }, + { NULL, NULL } +}; + +int drm_agp_info(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; + agp_kern_info *kern; + drm_agp_info_t info; + + if (!dev->agp->acquired || !drm_agp.copy_info) return -EINVAL; + + kern = &dev->agp->agp_info; + info.agp_version_major = kern->version.major; + info.agp_version_minor = kern->version.minor; + info.mode = kern->mode; + info.aperture_base = kern->aper_base; + info.aperture_size = kern->aper_size * 1024 * 1024; + info.memory_allowed = kern->max_memory << PAGE_SHIFT; + info.memory_used = kern->current_memory << PAGE_SHIFT; + info.id_vendor = kern->device->vendor; + info.id_device = kern->device->device; + + copy_to_user_ret((drm_agp_info_t *)arg, &info, sizeof(info), -EFAULT); + return 0; +} + +int drm_agp_acquire(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; + int retcode; + + if (dev->agp->acquired || !drm_agp.acquire) return -EINVAL; + if ((retcode = (*drm_agp.acquire)())) return retcode; + dev->agp->acquired = 1; + return 0; +} + +int drm_agp_release(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; + + if (!dev->agp->acquired || !drm_agp.release) return -EINVAL; + (*drm_agp.release)(); + dev->agp->acquired = 0; + return 0; + +} + +int drm_agp_enable(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_agp_mode_t mode; + + if (!dev->agp->acquired || !drm_agp.enable) return -EINVAL; + + copy_from_user_ret(&mode, (drm_agp_mode_t *)arg, sizeof(mode), + -EFAULT); + + dev->agp->mode = mode.mode; + (*drm_agp.enable)(mode.mode); + dev->agp->base = dev->agp->agp_info.aper_base; + dev->agp->enabled = 1; + return 0; +} + +int drm_agp_alloc(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_agp_buffer_t request; + drm_agp_mem_t *entry; + agp_memory *memory; + unsigned long pages; + u32 type; + if (!dev->agp->acquired) return -EINVAL; + copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request), + -EFAULT); + if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) + return -ENOMEM; + + memset(entry, 0, sizeof(*entry)); + + pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; + type = (u32) request.type; + + if (!(memory = drm_alloc_agp(pages, type))) { + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return -ENOMEM; + } + + entry->handle = (unsigned long)memory->memory; + entry->memory = memory; + entry->bound = 0; + entry->pages = pages; + entry->prev = NULL; + entry->next = dev->agp->memory; + if (dev->agp->memory) dev->agp->memory->prev = entry; + dev->agp->memory = entry; + + request.handle = entry->handle; + request.physical = memory->physical; + + if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) { + dev->agp->memory = entry->next; + dev->agp->memory->prev = NULL; + drm_free_agp(memory, pages); + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return -EFAULT; + } + return 0; +} + +static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t *dev, + unsigned long handle) +{ + drm_agp_mem_t *entry; + + for (entry = dev->agp->memory; entry; entry = entry->next) { + if (entry->handle == handle) return entry; + } + return NULL; +} + +int drm_agp_unbind(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_agp_binding_t request; + drm_agp_mem_t *entry; + + if (!dev->agp->acquired) return -EINVAL; + copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request), + -EFAULT); + if (!(entry = drm_agp_lookup_entry(dev, request.handle))) + return -EINVAL; + if (!entry->bound) return -EINVAL; + return drm_unbind_agp(entry->memory); +} + +int drm_agp_bind(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_agp_binding_t request; + drm_agp_mem_t *entry; + int retcode; + int page; + + if (!dev->agp->acquired || !drm_agp.bind_memory) return -EINVAL; + copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request), + -EFAULT); + if (!(entry = drm_agp_lookup_entry(dev, request.handle))) + return -EINVAL; + if (entry->bound) return -EINVAL; + page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE; + if ((retcode = drm_bind_agp(entry->memory, page))) return retcode; + entry->bound = dev->agp->base + (page << PAGE_SHIFT); + DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", + dev->agp->base, entry->bound); + return 0; +} + +int drm_agp_free(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_agp_buffer_t request; + drm_agp_mem_t *entry; + + if (!dev->agp->acquired) return -EINVAL; + copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request), + -EFAULT); + if (!(entry = drm_agp_lookup_entry(dev, request.handle))) + return -EINVAL; + if (entry->bound) drm_unbind_agp(entry->memory); + + if (entry->prev) entry->prev->next = entry->next; + else dev->agp->memory = entry->next; + if (entry->next) entry->next->prev = entry->prev; + drm_free_agp(entry->memory, entry->pages); + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return 0; +} + +drm_agp_head_t *drm_agp_init(void) +{ + drm_agp_fill_t *fill; + drm_agp_head_t *head = NULL; + int agp_available = 1; + + for (fill = &drm_agp_fill[0]; fill->name; fill++) { + char *n = (char *)fill->name; + *fill->f = (drm_agp_func_u)get_module_symbol(NULL, n); + DRM_DEBUG("%s resolves to 0x%08lx\n", n, (*fill->f).address); + if (!(*fill->f).address) agp_available = 0; + } + + DRM_DEBUG("agp_available = %d\n", agp_available); + + if (agp_available) { + if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) + return NULL; + memset((void *)head, 0, sizeof(*head)); + (*drm_agp.copy_info)(&head->agp_info); + if (head->agp_info.chipset == NOT_SUPPORTED) { + drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + return NULL; + } + head->memory = NULL; + switch (head->agp_info.chipset) { + case INTEL_GENERIC: head->chipset = "Intel"; break; + case INTEL_LX: head->chipset = "Intel 440LX"; break; + case INTEL_BX: head->chipset = "Intel 440BX"; break; + case INTEL_GX: head->chipset = "Intel 440GX"; break; + case INTEL_I810: head->chipset = "Intel i810"; break; +#if LINUX_VERSION_CODE >= 0x020400 + case INTEL_I840: head->chipset = "Intel i840"; break; +#endif + + case VIA_GENERIC: head->chipset = "VIA"; break; + case VIA_VP3: head->chipset = "VIA VP3"; break; + case VIA_MVP3: head->chipset = "VIA MVP3"; break; +#if LINUX_VERSION_CODE >= 0x020400 + case VIA_MVP4: head->chipset = "VIA MVP4"; break; +#endif + case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; break; + case VIA_APOLLO_KX133: head->chipset = "VIA Apollo KX133"; break; + case VIA_APOLLO_KT133: head->chipset = "VIA Apollo KT133"; break; + + case SIS_GENERIC: head->chipset = "SiS"; break; + + case AMD_GENERIC: head->chipset = "AMD"; break; + case AMD_IRONGATE: head->chipset = "AMD Irongate"; break; + + case ALI_GENERIC: head->chipset = "ALi"; break; + case ALI_M1541: head->chipset = "ALi M1541"; break; + + default: head->chipset = "Unknown"; break; + } + DRM_INFO("AGP %d.%d on %s @ 0x%08lx %uMB\n", + head->agp_info.version.major, + head->agp_info.version.minor, + head->chipset, + head->agp_info.aper_base, + head->agp_info.aper_size); + } + return head; +} + +void drm_agp_uninit(void) +{ + drm_agp_fill_t *fill; + + for (fill = &drm_agp_fill[0]; fill->name; fill++) { +#if LINUX_VERSION_CODE >= 0x020400 + if ((*fill->f).address) put_module_symbol((*fill->f).address); +#endif + (*fill->f).address = 0; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/auth.c linux/drivers/char/drm/auth.c --- v2.2.17/drivers/char/drm/auth.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/auth.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,160 @@ +/* auth.c -- IOCTLs for authentication -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static int drm_hash_magic(drm_magic_t magic) +{ + return magic & (DRM_HASH_SIZE-1); +} + +static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic) +{ + drm_file_t *retval = NULL; + drm_magic_entry_t *pt; + int hash = drm_hash_magic(magic); + + down(&dev->struct_sem); + for (pt = dev->magiclist[hash].head; pt; pt = pt->next) { + if (pt->magic == magic) { + retval = pt->priv; + break; + } + } + up(&dev->struct_sem); + return retval; +} + +int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) +{ + int hash; + drm_magic_entry_t *entry; + + DRM_DEBUG("%d\n", magic); + + hash = drm_hash_magic(magic); + entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); + if (!entry) return -ENOMEM; + entry->magic = magic; + entry->priv = priv; + entry->next = NULL; + + down(&dev->struct_sem); + if (dev->magiclist[hash].tail) { + dev->magiclist[hash].tail->next = entry; + dev->magiclist[hash].tail = entry; + } else { + dev->magiclist[hash].head = entry; + dev->magiclist[hash].tail = entry; + } + up(&dev->struct_sem); + + return 0; +} + +int drm_remove_magic(drm_device_t *dev, drm_magic_t magic) +{ + drm_magic_entry_t *prev = NULL; + drm_magic_entry_t *pt; + int hash; + + DRM_DEBUG("%d\n", magic); + hash = drm_hash_magic(magic); + + down(&dev->struct_sem); + for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) { + if (pt->magic == magic) { + if (dev->magiclist[hash].head == pt) { + dev->magiclist[hash].head = pt->next; + } + if (dev->magiclist[hash].tail == pt) { + dev->magiclist[hash].tail = prev; + } + if (prev) { + prev->next = pt->next; + } + up(&dev->struct_sem); + return 0; + } + } + up(&dev->struct_sem); + + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + + return -EINVAL; +} + +int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + static drm_magic_t sequence = 0; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_auth_t auth; + + /* Find unique magic */ + if (priv->magic) { + auth.magic = priv->magic; + } else { + do { + spin_lock(&lock); + if (!sequence) ++sequence; /* reserve 0 */ + auth.magic = sequence++; + spin_unlock(&lock); + } while (drm_find_file(dev, auth.magic)); + priv->magic = auth.magic; + drm_add_magic(dev, priv, auth.magic); + } + + DRM_DEBUG("%u\n", auth.magic); + copy_to_user_ret((drm_auth_t *)arg, &auth, sizeof(auth), -EFAULT); + return 0; +} + +int drm_authmagic(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_auth_t auth; + drm_file_t *file; + + copy_from_user_ret(&auth, (drm_auth_t *)arg, sizeof(auth), -EFAULT); + DRM_DEBUG("%u\n", auth.magic); + if ((file = drm_find_file(dev, auth.magic))) { + file->authenticated = 1; + drm_remove_magic(dev, auth.magic); + return 0; + } + return -EINVAL; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c --- v2.2.17/drivers/char/drm/bufs.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/bufs.c Tue Nov 28 20:14:54 2000 @@ -0,0 +1,538 @@ +/* bufs.c -- IOCTLs to manage buffers -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include +#include "drmP.h" +#include "linux/un.h" + + /* Compute order. Can be made faster. */ +int drm_order(unsigned long size) +{ + int order; + unsigned long tmp; + + for (order = 0, tmp = size; tmp >>= 1; ++order); + if (size & ~(1 << order)) ++order; + return order; +} + +int drm_addmap(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_map_t *map; + + if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */ + + map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + if (!map) return -ENOMEM; + if (copy_from_user(map, (drm_map_t *)arg, sizeof(*map))) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EFAULT; + } + + DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", + map->offset, map->size, map->type); + if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } + map->mtrr = -1; + map->handle = 0; + + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +#if !defined(__sparc__) && !defined(__alpha__) + if (map->offset + map->size < map->offset + || map->offset < virt_to_phys(high_memory)) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } +#endif +#ifdef CONFIG_MTRR + if (map->type == _DRM_FRAME_BUFFER + || (map->flags & _DRM_WRITE_COMBINING)) { + map->mtrr = mtrr_add(map->offset, map->size, + MTRR_TYPE_WRCOMB, 1); + } +#endif + map->handle = drm_ioremap(map->offset, map->size); + break; + + + case _DRM_SHM: + 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; + } + map->offset = (unsigned long)map->handle; + if (map->flags & _DRM_CONTAINS_LOCK) { + dev->lock.hw_lock = map->handle; /* Pointer to lock */ + } + break; +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + case _DRM_AGP: + map->offset = map->offset + dev->agp->base; + break; +#endif + default: + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } + + down(&dev->struct_sem); + if (dev->maplist) { + ++dev->map_count; + dev->maplist = drm_realloc(dev->maplist, + (dev->map_count-1) + * sizeof(*dev->maplist), + dev->map_count + * sizeof(*dev->maplist), + DRM_MEM_MAPS); + } else { + dev->map_count = 1; + dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist), + DRM_MEM_MAPS); + } + dev->maplist[dev->map_count-1] = map; + up(&dev->struct_sem); + + copy_to_user_ret((drm_map_t *)arg, map, sizeof(*map), -EFAULT); + if (map->type != _DRM_SHM) { + copy_to_user_ret(&((drm_map_t *)arg)->handle, + &map->offset, + sizeof(map->offset), + -EFAULT); + } + return 0; +} + +int drm_addbufs(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + int count; + int order; + int size; + int total; + int page_order; + drm_buf_entry_t *entry; + unsigned long page; + drm_buf_t *buf; + int alignment; + unsigned long offset; + int i; + int byte_count; + int page_count; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + + DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n", + request.count, request.size, size, order, dev->queue_count); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->seglist = drm_alloc(count * sizeof(*entry->seglist), + DRM_MEM_SEGS); + if (!entry->seglist) { + drm_free(entry->buflist, + count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->seglist, 0, count * sizeof(*entry->seglist)); + + dma->pagelist = drm_realloc(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + DRM_DEBUG("pagelist: %d entries\n", + dma->page_count + (count << page_order)); + + + entry->buf_size = size; + entry->page_order = page_order; + byte_count = 0; + page_count = 0; + while (entry->buf_count < count) { + if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break; + entry->seglist[entry->seg_count++] = page; + for (i = 0; i < (1 << page_order); i++) { + DRM_DEBUG("page %d @ 0x%08lx\n", + dma->page_count + page_count, + page + PAGE_SIZE * i); + dma->pagelist[dma->page_count + page_count++] + = page + PAGE_SIZE * i; + } + for (offset = 0; + offset + size <= total && entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + byte_count + offset); + buf->address = (void *)(page + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + byte_count += PAGE_SIZE << page_order; + } + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += entry->seg_count << page_order; + dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); + + atomic_dec(&dev->buf_alloc); + return 0; +} + +int drm_infobufs(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_device_dma_t *dma = dev->dma; + drm_buf_info_t request; + int i; + int count; + + if (!dma) return -EINVAL; + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_info_t *)arg, + sizeof(request), + -EFAULT); + + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) ++count; + } + + DRM_DEBUG("count = %d\n", count); + + if (request.count >= count) { + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) { + copy_to_user_ret(&request.list[count].count, + &dma->bufs[i].buf_count, + sizeof(dma->bufs[0] + .buf_count), + -EFAULT); + copy_to_user_ret(&request.list[count].size, + &dma->bufs[i].buf_size, + sizeof(dma->bufs[0].buf_size), + -EFAULT); + copy_to_user_ret(&request.list[count].low_mark, + &dma->bufs[i] + .freelist.low_mark, + sizeof(dma->bufs[0] + .freelist.low_mark), + -EFAULT); + copy_to_user_ret(&request.list[count] + .high_mark, + &dma->bufs[i] + .freelist.high_mark, + sizeof(dma->bufs[0] + .freelist.high_mark), + -EFAULT); + DRM_DEBUG("%d %d %d %d %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].buf_size, + dma->bufs[i].freelist.low_mark, + dma->bufs[i].freelist.high_mark); + ++count; + } + } + } + request.count = count; + + copy_to_user_ret((drm_buf_info_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return 0; +} + +int drm_markbufs(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + int order; + drm_buf_entry_t *entry; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d, %d, %d\n", + request.size, request.low_mark, request.high_mark); + order = drm_order(request.size); + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + entry = &dma->bufs[order]; + + if (request.low_mark < 0 || request.low_mark > entry->buf_count) + return -EINVAL; + if (request.high_mark < 0 || request.high_mark > entry->buf_count) + return -EINVAL; + + entry->freelist.low_mark = request.low_mark; + entry->freelist.high_mark = request.high_mark; + + return 0; +} + +int drm_freebufs(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_device_dma_t *dma = dev->dma; + drm_buf_free_t request; + int i; + int idx; + drm_buf_t *buf; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_free_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d\n", request.count); + for (i = 0; i < request.count; i++) { + copy_from_user_ret(&idx, + &request.list[i], + sizeof(idx), + -EFAULT); + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + idx, dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[idx]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d freeing buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + drm_free_buffer(dev, buf); + } + + return 0; +} + +int drm_mapbufs(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_device_dma_t *dma = dev->dma; + int retcode = 0; + const int zero = 0; + unsigned long virtual; + unsigned long address; + drm_buf_map_t request; + int i; + + if (!dma) return -EINVAL; + + DRM_DEBUG("\n"); + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_map_t *)arg, + sizeof(request), + -EFAULT); + + if (request.count >= dma->buf_count) { + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); + if (virtual > -1024UL) { + /* Real error */ + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void *)virtual; + + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].used, + &zero, + sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; + if (copy_to_user(&request.list[i].address, + &address, + sizeof(address))) { + retcode = -EFAULT; + goto done; + } + } + } +done: + request.count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); + + copy_to_user_ret((drm_buf_map_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return retcode; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/context.c linux/drivers/char/drm/context.c --- v2.2.17/drivers/char/drm/context.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/context.c Fri Sep 1 14:12:32 2000 @@ -0,0 +1,308 @@ +/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx) +{ + DRM_DEBUG("\n"); + + if (atomic_read(&q->use_count) != 1 + || atomic_read(&q->finalization) + || atomic_read(&q->block_count)) { + DRM_ERROR("New queue is already in use: u%d f%d b%d\n", + atomic_read(&q->use_count), + atomic_read(&q->finalization), + atomic_read(&q->block_count)); + } + + atomic_set(&q->finalization, 0); + atomic_set(&q->block_count, 0); + atomic_set(&q->block_read, 0); + atomic_set(&q->block_write, 0); + atomic_set(&q->total_queued, 0); + atomic_set(&q->total_flushed, 0); + atomic_set(&q->total_locks, 0); + + init_waitqueue_head(&q->write_queue); + init_waitqueue_head(&q->read_queue); + init_waitqueue_head(&q->flush_queue); + + q->flags = ctx->flags; + + drm_waitlist_create(&q->waitlist, dev->dma->buf_count); + + return 0; +} + + +/* drm_alloc_queue: +PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not + disappear (so all deallocation must be done after IOCTLs are off) + 2) dev->queue_count < dev->queue_slots + 3) dev->queuelist[i].use_count == 0 and + dev->queuelist[i].finalization == 0 if i not in use +POST: 1) dev->queuelist[i].use_count == 1 + 2) dev->queue_count < dev->queue_slots */ + +static int drm_alloc_queue(drm_device_t *dev) +{ + int i; + drm_queue_t *queue; + int oldslots; + int newslots; + /* Check for a free queue */ + for (i = 0; i < dev->queue_count; i++) { + atomic_inc(&dev->queuelist[i]->use_count); + if (atomic_read(&dev->queuelist[i]->use_count) == 1 + && !atomic_read(&dev->queuelist[i]->finalization)) { + DRM_DEBUG("%d (free)\n", i); + return i; + } + atomic_dec(&dev->queuelist[i]->use_count); + } + /* Allocate a new queue */ + down(&dev->struct_sem); + + queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES); + memset(queue, 0, sizeof(*queue)); + atomic_set(&queue->use_count, 1); + + ++dev->queue_count; + if (dev->queue_count >= dev->queue_slots) { + oldslots = dev->queue_slots * sizeof(*dev->queuelist); + if (!dev->queue_slots) dev->queue_slots = 1; + dev->queue_slots *= 2; + newslots = dev->queue_slots * sizeof(*dev->queuelist); + + dev->queuelist = drm_realloc(dev->queuelist, + oldslots, + newslots, + DRM_MEM_QUEUES); + if (!dev->queuelist) { + up(&dev->struct_sem); + DRM_DEBUG("out of memory\n"); + return -ENOMEM; + } + } + dev->queuelist[dev->queue_count-1] = queue; + + up(&dev->struct_sem); + DRM_DEBUG("%d (new)\n", dev->queue_count - 1); + return dev->queue_count - 1; +} + +int drm_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 drm_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 = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Init kernel's context and get a new one. */ + drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); + ctx.handle = drm_alloc_queue(dev); + } + drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); + DRM_DEBUG("%d\n", ctx.handle); + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int drm_modctx(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; + drm_queue_t *q; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + if (DRM_BUFCOUNT(&q->waitlist)) { + atomic_dec(&q->use_count); + return -EBUSY; + } + + q->flags = ctx.flags; + + atomic_dec(&q->use_count); + return 0; +} + +int drm_getctx(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; + drm_queue_t *q; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + ctx.flags = q->flags; + atomic_dec(&q->use_count); + + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + + return 0; +} + +int drm_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 drm_context_switch(dev, dev->last_context, ctx.handle); +} + +int drm_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); + drm_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int drm_rmctx(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; + drm_queue_t *q; + drm_buf_t *buf; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + atomic_inc(&q->finalization); /* Mark queue in finalization state */ + atomic_sub(2, &q->use_count); /* Mark queue as unused (pending + finalization) */ + + while (test_and_set_bit(0, &dev->interrupt_flag)) { + schedule(); + if (signal_pending(current)) { + clear_bit(0, &dev->interrupt_flag); + return -EINTR; + } + } + /* Remove queued buffers */ + while ((buf = drm_waitlist_get(&q->waitlist))) { + drm_free_buffer(dev, buf); + } + clear_bit(0, &dev->interrupt_flag); + + /* Wakeup blocked processes */ + wake_up_interruptible(&q->read_queue); + wake_up_interruptible(&q->write_queue); + wake_up_interruptible(&q->flush_queue); + + /* Finalization over. Queue is made + available when both use_count and + finalization become 0, which won't + happen until all the waiting processes + stop waiting. */ + atomic_dec(&q->finalization); + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/ctxbitmap.c linux/drivers/char/drm/ctxbitmap.c --- v2.2.17/drivers/char/drm/ctxbitmap.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/ctxbitmap.c Fri Sep 1 14:12:32 2000 @@ -0,0 +1,85 @@ +/* ctxbitmap.c -- Context bitmap management -*- linux-c -*- + * Created: Thu Jan 6 03:56:42 2000 by jhartmann@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Author: Jeff Hartmann + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle) +{ + if (ctx_handle < 0) goto failed; + + if (ctx_handle < DRM_MAX_CTXBITMAP) { + clear_bit(ctx_handle, dev->ctx_bitmap); + return; + } +failed: + DRM_ERROR("Attempt to free invalid context handle: %d\n", + ctx_handle); + return; +} + +int drm_ctxbitmap_next(drm_device_t *dev) +{ + int bit; + + bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); + if (bit < DRM_MAX_CTXBITMAP) { + set_bit(bit, dev->ctx_bitmap); + DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit); + return bit; + } + return -1; +} + +int drm_ctxbitmap_init(drm_device_t *dev) +{ + int i; + int temp; + + dev->ctx_bitmap = (unsigned long *) drm_alloc(PAGE_SIZE, + DRM_MEM_CTXBITMAP); + if(dev->ctx_bitmap == NULL) { + return -ENOMEM; + } + memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE); + for(i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + temp = drm_ctxbitmap_next(dev); + DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp); + } + + return 0; +} + +void drm_ctxbitmap_cleanup(drm_device_t *dev) +{ + drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, + DRM_MEM_CTXBITMAP); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/dma.c linux/drivers/char/drm/dma.c --- v2.2.17/drivers/char/drm/dma.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/dma.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,540 @@ +/* dma.c -- DMA IOCTL and function support -*- linux-c -*- + * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +#include /* For task queue support */ + +void drm_dma_setup(drm_device_t *dev) +{ + int i; + + dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER); + memset(dev->dma, 0, sizeof(*dev->dma)); + for (i = 0; i <= DRM_MAX_ORDER; i++) + memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); +} + +void drm_dma_takedown(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i, j; + + if (!dma) return; + + /* Clear dma buffers */ + for (i = 0; i <= DRM_MAX_ORDER; i++) { + if (dma->bufs[i].seg_count) { + DRM_DEBUG("order %d: buf_count = %d," + " seg_count = %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].seg_count); + for (j = 0; j < dma->bufs[i].seg_count; j++) { + drm_free_pages(dma->bufs[i].seglist[j], + dma->bufs[i].page_order, + DRM_MEM_DMA); + } + drm_free(dma->bufs[i].seglist, + dma->bufs[i].seg_count + * sizeof(*dma->bufs[0].seglist), + DRM_MEM_SEGS); + } + if(dma->bufs[i].buf_count) { + for(j = 0; j < dma->bufs[i].buf_count; j++) { + if(dma->bufs[i].buflist[j].dev_private) { + drm_free(dma->bufs[i].buflist[j].dev_private, + dma->bufs[i].buflist[j].dev_priv_size, + DRM_MEM_BUFS); + } + } + drm_free(dma->bufs[i].buflist, + dma->bufs[i].buf_count * + sizeof(*dma->bufs[0].buflist), + DRM_MEM_BUFS); + drm_freelist_destroy(&dma->bufs[i].freelist); + } + } + + if (dma->buflist) { + drm_free(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + DRM_MEM_BUFS); + } + + if (dma->pagelist) { + drm_free(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + } + drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); + dev->dma = NULL; +} + +#if DRM_DMA_HISTOGRAM +/* This is slow, but is useful for debugging. */ +int drm_histogram_slot(unsigned long count) +{ + int value = DRM_DMA_HISTOGRAM_INITIAL; + int slot; + + for (slot = 0; + slot < DRM_DMA_HISTOGRAM_SLOTS; + ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) { + if (count < value) return slot; + } + return DRM_DMA_HISTOGRAM_SLOTS - 1; +} + +void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf) +{ + cycles_t queued_to_dispatched; + cycles_t dispatched_to_completed; + cycles_t completed_to_freed; + int q2d, d2c, c2f, q2c, q2f; + + if (buf->time_queued) { + queued_to_dispatched = (buf->time_dispatched + - buf->time_queued); + dispatched_to_completed = (buf->time_completed + - buf->time_dispatched); + completed_to_freed = (buf->time_freed + - buf->time_completed); + + q2d = drm_histogram_slot(queued_to_dispatched); + d2c = drm_histogram_slot(dispatched_to_completed); + c2f = drm_histogram_slot(completed_to_freed); + + q2c = drm_histogram_slot(queued_to_dispatched + + dispatched_to_completed); + q2f = drm_histogram_slot(queued_to_dispatched + + dispatched_to_completed + + completed_to_freed); + + atomic_inc(&dev->histo.total); + atomic_inc(&dev->histo.queued_to_dispatched[q2d]); + atomic_inc(&dev->histo.dispatched_to_completed[d2c]); + atomic_inc(&dev->histo.completed_to_freed[c2f]); + + atomic_inc(&dev->histo.queued_to_completed[q2c]); + atomic_inc(&dev->histo.queued_to_freed[q2f]); + + } + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +} +#endif + +void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf) +{ + drm_device_dma_t *dma = dev->dma; + + if (!buf) return; + + buf->waiting = 0; + buf->pending = 0; + buf->pid = 0; + buf->used = 0; +#if DRM_DMA_HISTOGRAM + buf->time_completed = get_cycles(); +#endif + if (waitqueue_active(&buf->dma_wait)) { + wake_up_interruptible(&buf->dma_wait); + } else { + /* If processes are waiting, the last one + to wake will put the buffer on the free + list. If no processes are waiting, we + put the buffer on the freelist here. */ + drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf); + } +} + +void drm_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + 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) { + case DRM_LIST_NONE: + drm_free_buffer(dev, dma->buflist[i]); + break; + case DRM_LIST_WAIT: + dma->buflist[i]->list = DRM_LIST_RECLAIM; + break; + default: + /* Buffer already on hardware. */ + break; + } + } + } +} + +int drm_context_switch(drm_device_t *dev, int old, int new) +{ + char buf[64]; + drm_queue_t *q; + + 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->queue_count) { + clear_bit(0, &dev->context_flag); + return -EINVAL; + } + + if (new == dev->last_context) { + clear_bit(0, &dev->context_flag); + return 0; + } + + q = dev->queuelist[new]; + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + atomic_dec(&q->use_count); + clear_bit(0, &dev->context_flag); + return -EINVAL; + } + + if (drm_flags & DRM_FLAG_NOCTX) { + drm_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + atomic_dec(&q->use_count); + + return 0; +} + +int drm_context_switch_complete(drm_device_t *dev, int new) +{ + drm_device_dma_t *dma = dev->dma; + + 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 (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("Cannot free lock\n"); + } + } + +#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_interruptible(&dev->context_wait); + + return 0; +} + +void drm_clear_next_buffer(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + + dma->next_buffer = NULL; + if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) { + wake_up_interruptible(&dma->next_queue->flush_queue); + } + dma->next_queue = NULL; +} + + +int drm_select_queue(drm_device_t *dev, void (*wrapper)(unsigned long)) +{ + int i; + int candidate = -1; + int j = jiffies; + + if (!dev) { + DRM_ERROR("No device\n"); + return -1; + } + if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) { + /* This only happens between the time the + interrupt is initialized and the time + the queues are initialized. */ + return -1; + } + + /* Doing "while locked" DMA? */ + if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { + return DRM_KERNEL_CONTEXT; + } + + /* If there are buffers on the last_context + queue, and we have not been executing + this context very long, continue to + execute this context. */ + if (dev->last_switch <= j + && dev->last_switch + DRM_TIME_SLICE > j + && DRM_WAITCOUNT(dev, dev->last_context)) { + return dev->last_context; + } + + /* Otherwise, find a candidate */ + for (i = dev->last_checked + 1; i < dev->queue_count; i++) { + if (DRM_WAITCOUNT(dev, i)) { + candidate = dev->last_checked = i; + break; + } + } + + if (candidate < 0) { + for (i = 0; i < dev->queue_count; i++) { + if (DRM_WAITCOUNT(dev, i)) { + candidate = dev->last_checked = i; + break; + } + } + } + + if (wrapper + && candidate >= 0 + && candidate != dev->last_context + && dev->last_switch <= j + && dev->last_switch + DRM_TIME_SLICE > j) { + if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) { + del_timer(&dev->timer); + dev->timer.function = wrapper; + dev->timer.data = (unsigned long)dev; + dev->timer.expires = dev->last_switch+DRM_TIME_SLICE; + add_timer(&dev->timer); + } + return -1; + } + + return candidate; +} + + +int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d) +{ + int i; + drm_queue_t *q; + drm_buf_t *buf; + int idx; + int while_locked = 0; + drm_device_dma_t *dma = dev->dma; + DECLARE_WAITQUEUE(entry, current); + + DRM_DEBUG("%d\n", d->send_count); + + if (d->flags & _DRM_DMA_WHILE_LOCKED) { + int context = dev->lock.hw_lock->lock; + + if (!_DRM_LOCK_IS_HELD(context)) { + DRM_ERROR("No lock held during \"while locked\"" + " request\n"); + return -EINVAL; + } + if (d->context != _DRM_LOCKING_CONTEXT(context) + && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) { + DRM_ERROR("Lock held by %d while %d makes" + " \"while locked\" request\n", + _DRM_LOCKING_CONTEXT(context), + d->context); + return -EINVAL; + } + q = dev->queuelist[DRM_KERNEL_CONTEXT]; + while_locked = 1; + } else { + q = dev->queuelist[d->context]; + } + + + atomic_inc(&q->use_count); + if (atomic_read(&q->block_write)) { + add_wait_queue(&q->write_queue, &entry); + atomic_inc(&q->block_count); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!atomic_read(&q->block_write)) break; + schedule(); + if (signal_pending(current)) { + atomic_dec(&q->use_count); + return -EINTR; + } + } + atomic_dec(&q->block_count); + current->state = TASK_RUNNING; + remove_wait_queue(&q->write_queue, &entry); + } + + for (i = 0; i < d->send_count; i++) { + idx = d->send_indices[i]; + if (idx < 0 || idx >= dma->buf_count) { + atomic_dec(&q->use_count); + DRM_ERROR("Index %d (of %d max)\n", + d->send_indices[i], dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[ idx ]; + if (buf->pid != current->pid) { + atomic_dec(&q->use_count); + DRM_ERROR("Process %d using buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + if (buf->list != DRM_LIST_NONE) { + atomic_dec(&q->use_count); + DRM_ERROR("Process %d using buffer %d on list %d\n", + current->pid, buf->idx, buf->list); + } + buf->used = d->send_sizes[i]; + buf->while_locked = while_locked; + buf->context = d->context; + if (!buf->used) { + DRM_ERROR("Queueing 0 length buffer\n"); + } + if (buf->pending) { + atomic_dec(&q->use_count); + DRM_ERROR("Queueing pending buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + return -EINVAL; + } + if (buf->waiting) { + atomic_dec(&q->use_count); + DRM_ERROR("Queueing waiting buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + return -EINVAL; + } + buf->waiting = 1; + if (atomic_read(&q->use_count) == 1 + || atomic_read(&q->finalization)) { + drm_free_buffer(dev, buf); + } else { + drm_waitlist_put(&q->waitlist, buf); + atomic_inc(&q->total_queued); + } + } + atomic_dec(&q->use_count); + + return 0; +} + +static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d, + int order) +{ + int i; + drm_buf_t *buf; + drm_device_dma_t *dma = dev->dma; + + for (i = d->granted_count; i < d->request_count; i++) { + buf = drm_freelist_get(&dma->bufs[order].freelist, + d->flags & _DRM_DMA_WAIT); + if (!buf) break; + if (buf->pending || buf->waiting) { + DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n", + buf->idx, + buf->pid, + buf->waiting, + buf->pending); + } + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++d->granted_count; + } + return 0; +} + + +int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma) +{ + int order; + int retcode = 0; + int tmp_order; + + order = drm_order(dma->request_size); + + dma->granted_count = 0; + retcode = drm_dma_get_buffers_of_order(dev, dma, order); + + if (dma->granted_count < dma->request_count + && (dma->flags & _DRM_DMA_SMALLER_OK)) { + for (tmp_order = order - 1; + !retcode + && dma->granted_count < dma->request_count + && tmp_order >= DRM_MIN_ORDER; + --tmp_order) { + + retcode = drm_dma_get_buffers_of_order(dev, dma, + tmp_order); + } + } + + if (dma->granted_count < dma->request_count + && (dma->flags & _DRM_DMA_LARGER_OK)) { + for (tmp_order = order + 1; + !retcode + && dma->granted_count < dma->request_count + && tmp_order <= DRM_MAX_ORDER; + ++tmp_order) { + + retcode = drm_dma_get_buffers_of_order(dev, dma, + tmp_order); + } + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/drawable.c linux/drivers/char/drm/drawable.c --- v2.2.17/drivers/char/drm/drawable.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/drawable.c Fri Sep 1 14:12:32 2000 @@ -0,0 +1,50 @@ +/* drawable.c -- IOCTLs for drawables -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_draw_t draw; + + draw.handle = 0; /* NOOP */ + DRM_DEBUG("%d\n", draw.handle); + copy_to_user_ret((drm_draw_t *)arg, &draw, sizeof(draw), -EFAULT); + return 0; +} + +int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; /* NOOP */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/drm.h linux/drivers/char/drm/drm.h --- v2.2.17/drivers/char/drm/drm.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/drm.h Tue Nov 28 18:36:47 2000 @@ -0,0 +1,367 @@ +/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + * Acknowledgements: + * Dec 1999, Richard Henderson , move to generic cmpxchg. + * + */ + +#ifndef _DRM_H_ +#define _DRM_H_ + +#include /* For _IO* macros */ + +#define DRM_PROC_DEVICES "/proc/devices" +#define DRM_PROC_MISC "/proc/misc" +#define DRM_PROC_DRM "/proc/drm" +#define DRM_DEV_DRM "/dev/drm" +#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) +#define DRM_DEV_UID 0 +#define DRM_DEV_GID 0 + + +#define DRM_NAME "drm" /* Name in kernel, /dev, and /proc */ +#define DRM_MIN_ORDER 5 /* At least 2^5 bytes = 32 bytes */ +#define DRM_MAX_ORDER 22 /* Up to 2^22 bytes = 4MB */ +#define DRM_RAM_PERCENT 10 /* How much system ram can we lock? */ + +#define _DRM_LOCK_HELD 0x80000000 /* Hardware lock is held */ +#define _DRM_LOCK_CONT 0x40000000 /* Hardware lock is contended */ +#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) +#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) +#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) + +typedef unsigned long drm_handle_t; +typedef unsigned int drm_context_t; +typedef unsigned int drm_drawable_t; +typedef unsigned int drm_magic_t; + +/* Warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well */ + +typedef struct drm_clip_rect { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; +} drm_clip_rect_t; + +/* Seperate include files for the i810/mga/r128 specific structures */ +#include "mga_drm.h" +#include "i810_drm.h" +#include "r128_drm.h" + +typedef struct drm_version { + int version_major; /* Major version */ + int version_minor; /* Minor version */ + int version_patchlevel;/* Patch level */ + size_t name_len; /* Length of name buffer */ + char *name; /* Name of driver */ + size_t date_len; /* Length of date buffer */ + char *date; /* User-space buffer to hold date */ + size_t desc_len; /* Length of desc buffer */ + char *desc; /* User-space buffer to hold desc */ +} drm_version_t; + +typedef struct drm_unique { + size_t unique_len; /* Length of unique */ + char *unique; /* Unique name for driver instantiation */ +} drm_unique_t; + +typedef struct drm_list { + int count; /* Length of user-space structures */ + drm_version_t *version; +} drm_list_t; + +typedef struct drm_block { + int unused; +} drm_block_t; + +typedef struct drm_control { + enum { + DRM_ADD_COMMAND, + DRM_RM_COMMAND, + DRM_INST_HANDLER, + DRM_UNINST_HANDLER + } func; + int irq; +} drm_control_t; + +typedef enum drm_map_type { + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3 /* AGP/GART */ +} drm_map_type_t; + +typedef enum drm_map_flags { + _DRM_RESTRICTED = 0x01, /* Cannot be mapped to user-virtual */ + _DRM_READ_ONLY = 0x02, + _DRM_LOCKED = 0x04, /* shared, cached, locked */ + _DRM_KERNEL = 0x08, /* kernel requires access */ + _DRM_WRITE_COMBINING = 0x10, /* use write-combining if available */ + _DRM_CONTAINS_LOCK = 0x20 /* SHM page that contains lock */ +} drm_map_flags_t; + +typedef struct drm_map { + unsigned long offset; /* Requested physical address (0 for SAREA)*/ + unsigned long size; /* Requested physical size (bytes) */ + drm_map_type_t type; /* Type of memory to map */ + drm_map_flags_t flags; /* Flags */ + void *handle; /* User-space: "Handle" to pass to mmap */ + /* Kernel-space: kernel-virtual address */ + int mtrr; /* MTRR slot used */ + /* Private data */ +} drm_map_t; + +typedef enum drm_lock_flags { + _DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */ + _DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */ + _DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */ + _DRM_LOCK_FLUSH_ALL = 0x08, /* Flush all DMA queues first */ + /* These *HALT* flags aren't supported yet + -- they will be used to support the + full-screen DGA-like mode. */ + _DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues */ + _DRM_HALT_CUR_QUEUES = 0x20 /* Halt all current queues */ +} drm_lock_flags_t; + +typedef struct drm_lock { + int context; + drm_lock_flags_t flags; +} drm_lock_t; + +typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */ + /* Flags for DMA buffer dispatch */ + _DRM_DMA_BLOCK = 0x01, /* Block until buffer dispatched. + Note, the buffer may not yet have + been processed by the hardware -- + getting a hardware lock with the + hardware quiescent will ensure + that the buffer has been + processed. */ + _DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held */ + _DRM_DMA_PRIORITY = 0x04, /* High priority dispatch */ + + /* Flags for DMA buffer request */ + _DRM_DMA_WAIT = 0x10, /* Wait for free buffers */ + _DRM_DMA_SMALLER_OK = 0x20, /* Smaller-than-requested buffers ok */ + _DRM_DMA_LARGER_OK = 0x40 /* Larger-than-requested buffers ok */ +} drm_dma_flags_t; + +typedef struct drm_buf_desc { + int count; /* Number of buffers of this size */ + int size; /* Size in bytes */ + int low_mark; /* Low water mark */ + int high_mark; /* High water mark */ + enum { + _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ + } flags; + unsigned long agp_start; /* Start address of where the agp buffers + * are in the agp aperture */ +} drm_buf_desc_t; + +typedef struct drm_buf_info { + int count; /* Entries in list */ + drm_buf_desc_t *list; +} drm_buf_info_t; + +typedef struct drm_buf_free { + int count; + int *list; +} drm_buf_free_t; + +typedef struct drm_buf_pub { + int idx; /* Index into master buflist */ + int total; /* Buffer size */ + int used; /* Amount of buffer in use (for DMA) */ + void *address; /* Address of buffer */ +} drm_buf_pub_t; + +typedef struct drm_buf_map { + int count; /* Length of buflist */ + void *virtual; /* Mmaped area in user-virtual */ + drm_buf_pub_t *list; /* Buffer information */ +} drm_buf_map_t; + +typedef struct drm_dma { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int context; /* Context handle */ + int send_count; /* Number of buffers to send */ + int *send_indices; /* List of handles to buffers */ + int *send_sizes; /* Lengths of data to send */ + drm_dma_flags_t flags; /* Flags */ + int request_count; /* Number of buffers requested */ + int request_size; /* Desired size for buffers */ + int *request_indices; /* Buffer information */ + int *request_sizes; + int granted_count; /* Number of buffers granted */ +} drm_dma_t; + +typedef enum { + _DRM_CONTEXT_PRESERVED = 0x01, + _DRM_CONTEXT_2DONLY = 0x02 +} drm_ctx_flags_t; + +typedef struct drm_ctx { + drm_context_t handle; + drm_ctx_flags_t flags; +} drm_ctx_t; + +typedef struct drm_ctx_res { + int count; + drm_ctx_t *contexts; +} drm_ctx_res_t; + +typedef struct drm_draw { + drm_drawable_t handle; +} drm_draw_t; + +typedef struct drm_auth { + drm_magic_t magic; +} drm_auth_t; + +typedef struct drm_irq_busid { + int irq; + int busnum; + int devnum; + int funcnum; +} drm_irq_busid_t; + +typedef struct drm_agp_mode { + unsigned long mode; +} drm_agp_mode_t; + + /* For drm_agp_alloc -- allocated a buffer */ +typedef struct drm_agp_buffer { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for BIND/UNBIND ioctls */ + unsigned long type; /* Type of memory to allocate */ + unsigned long physical; /* Physical used by i810 */ +} drm_agp_buffer_t; + + /* For drm_agp_bind */ +typedef struct drm_agp_binding { + unsigned long handle; /* From drm_agp_buffer */ + unsigned long offset; /* In bytes -- will round to page boundary */ +} drm_agp_binding_t; + +typedef struct drm_agp_info { + int agp_version_major; + int agp_version_minor; + unsigned long mode; + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ + unsigned long memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +} drm_agp_info_t; + +#define DRM_IOCTL_BASE 'd' +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) +#define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) +#define DRM_IOW(nr,size) _IOW(DRM_IOCTL_BASE,nr,size) +#define DRM_IOWR(nr,size) _IOWR(DRM_IOCTL_BASE,nr,size) + + +#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t) +#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t) +#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t) +#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t) + +#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) +#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) +#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t) +#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t) +#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t) +#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t) +#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t) +#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t) +#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t) +#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t) +#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t) + +#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t) +#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t) +#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t) +#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t) +#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t) +#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t) +#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t) +#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t) +#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t) +#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t) +#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t) +#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) +#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) + +#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) +#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) +#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t) +#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t) +#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t) +#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) +#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) + +/* Mga specific ioctls */ +#define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) +#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x41, drm_mga_swap_t) +#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x42, drm_mga_clear_t) +#define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) +#define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) +#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) + +/* I810 specific ioctls */ +#define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) +#define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) +#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) +#define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) +#define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) +#define DRM_IOCTL_I810_GETBUF DRM_IOWR(0x45, drm_i810_dma_t) +#define DRM_IOCTL_I810_SWAP DRM_IO ( 0x46) +#define DRM_IOCTL_I810_COPY DRM_IOW( 0x47, drm_i810_copy_t) +#define DRM_IOCTL_I810_DOCOPY DRM_IO ( 0x48) + +/* Rage 128 specific ioctls */ +#define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) +#define DRM_IOCTL_R128_RESET DRM_IO( 0x41) +#define DRM_IOCTL_R128_FLUSH DRM_IO( 0x42) +#define DRM_IOCTL_R128_IDLE DRM_IO( 0x43) +#define DRM_IOCTL_R128_PACKET DRM_IOW( 0x44, drm_r128_packet_t) +#define DRM_IOCTL_R128_VERTEX DRM_IOW( 0x45, drm_r128_vertex_t) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h --- v2.2.17/drivers/char/drm/drmP.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/drmP.h Sat Dec 9 21:26:39 2000 @@ -0,0 +1,771 @@ +/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#ifndef _DRM_P_H_ +#define _DRM_P_H_ + +#ifdef __KERNEL__ +#ifdef __alpha__ +/* add include of current.h so that "current" is defined + * before static inline funcs in wait.h. 4/21/2000 S + B */ +#include +#endif /* __alpha__ */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For (un)lock_kernel */ +#include +#include /* For pte_wrprotect */ +#include +#include +#include +#ifdef CONFIG_MTRR +#include +#endif +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +#include +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) +#include +#include +#endif +#include "drm.h" + +#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then + also include looping detection. */ +#define DRM_DMA_HISTOGRAM 1 /* Make histogram of DMA latency. */ + +#define DRM_HASH_SIZE 16 /* Size of key hash table */ +#define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */ +#define DRM_RESERVED_CONTEXTS 1 /* Change drm_resctx if changed */ +#define DRM_LOOPING_LIMIT 5000000 +#define DRM_BSZ 1024 /* Buffer size for /dev/drm? output */ +#define DRM_TIME_SLICE (HZ/20) /* Time slice for GLXContexts */ +#define DRM_LOCK_SLICE 1 /* Time slice for lock, in jiffies */ + +#define DRM_FLAG_DEBUG 0x01 +#define DRM_FLAG_NOCTX 0x02 + +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_AGPLISTS 15 +#define DRM_MEM_TOTALAGP 16 +#define DRM_MEM_BOUNDAGP 17 +#define DRM_MEM_CTXBITMAP 18 + +#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) + + /* Backward compatibility section */ + /* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */ +#ifndef _PAGE_PWT +#define _PAGE_PWT _PAGE_WT +#endif + /* 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 + + /* _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 + + /* module_init/module_exit added in 2.3.13 */ +#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 + + /* virt_to_page added in 2.4.0-test6 */ +#if LINUX_VERSION_CODE < 0x020400 +#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr)) +#endif + + /* Generic cmpxchg added in 2.3.x */ +#ifndef __HAVE_ARCH_CMPXCHG + /* Include this here so that driver can be + used with older kernels. */ + +#if __i386__ +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 /* i386 */ +#endif + + /* Macros to make printk easier */ +#define DRM_ERROR(fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg) +#define DRM_MEM_ERROR(area, fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \ + drm_mem_stats[area].name , ##arg) +#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) + +#if DRM_DEBUG_CODE +#define DRM_DEBUG(fmt, arg...) \ + do { \ + if (drm_flags&DRM_FLAG_DEBUG) \ + printk(KERN_DEBUG \ + "[" DRM_NAME ":" __FUNCTION__ "] " fmt , \ + ##arg); \ + } while (0) +#else +#define DRM_DEBUG(fmt, arg...) do { } while (0) +#endif + +#define DRM_PROC_LIMIT (PAGE_SIZE-80) + +#define DRM_PROC_PRINT(fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) return len; + +#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) { ret; return len; } + + /* Internal types and structures */ +#define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define DRM_MIN(a,b) ((a)<(b)?(a):(b)) +#define DRM_MAX(a,b) ((a)>(b)?(a):(b)) + +#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) +#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) +#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) + +typedef int drm_ioctl_t(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +typedef struct drm_ioctl_desc { + drm_ioctl_t *func; + int auth_needed; + int root_only; +} drm_ioctl_desc_t; + +typedef struct drm_devstate { + pid_t owner; /* X server pid holding x_lock */ + +} drm_devstate_t; + +typedef struct drm_magic_entry { + drm_magic_t magic; + struct drm_file *priv; + struct drm_magic_entry *next; +} drm_magic_entry_t; + +typedef struct drm_magic_head { + struct drm_magic_entry *head; + struct drm_magic_entry *tail; +} drm_magic_head_t; + +typedef struct drm_vma_entry { + struct vm_area_struct *vma; + struct drm_vma_entry *next; + pid_t pid; +} drm_vma_entry_t; + +typedef struct drm_buf { + int idx; /* Index into master buflist */ + int total; /* Buffer size */ + int order; /* log-base-2(total) */ + int used; /* Amount of buffer in use (for DMA) */ + unsigned long offset; /* Byte offset (used internally) */ + void *address; /* Address of buffer */ + unsigned long bus_address; /* Bus address of buffer */ + struct drm_buf *next; /* Kernel-only: used for free list */ + __volatile__ int waiting; /* On kernel DMA queue */ + __volatile__ int pending; /* On hardware DMA queue */ + wait_queue_head_t dma_wait; /* Processes waiting */ + pid_t pid; /* PID of holding process */ + int context; /* Kernel queue for this buffer */ + int while_locked;/* Dispatch this buffer while locked */ + enum { + DRM_LIST_NONE = 0, + DRM_LIST_FREE = 1, + DRM_LIST_WAIT = 2, + DRM_LIST_PEND = 3, + DRM_LIST_PRIO = 4, + DRM_LIST_RECLAIM = 5 + } list; /* Which list we're on */ + +#if DRM_DMA_HISTOGRAM + cycles_t time_queued; /* Queued to kernel DMA queue */ + cycles_t time_dispatched; /* Dispatched to hardware */ + cycles_t time_completed; /* Completed by hardware */ + cycles_t time_freed; /* Back on freelist */ +#endif + + int dev_priv_size; /* Size of buffer private stoarge */ + void *dev_private; /* Per-buffer private storage */ +} drm_buf_t; + +#if DRM_DMA_HISTOGRAM +#define DRM_DMA_HISTOGRAM_SLOTS 9 +#define DRM_DMA_HISTOGRAM_INITIAL 10 +#define DRM_DMA_HISTOGRAM_NEXT(current) ((current)*10) +typedef struct drm_histogram { + atomic_t total; + + atomic_t queued_to_dispatched[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t dispatched_to_completed[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t completed_to_freed[DRM_DMA_HISTOGRAM_SLOTS]; + + atomic_t queued_to_completed[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t queued_to_freed[DRM_DMA_HISTOGRAM_SLOTS]; + + atomic_t dma[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t schedule[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t ctx[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t lacq[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t lhld[DRM_DMA_HISTOGRAM_SLOTS]; +} drm_histogram_t; +#endif + + /* bufs is one longer than it has to be */ +typedef struct drm_waitlist { + int count; /* Number of possible buffers */ + drm_buf_t **bufs; /* List of pointers to buffers */ + drm_buf_t **rp; /* Read pointer */ + drm_buf_t **wp; /* Write pointer */ + drm_buf_t **end; /* End pointer */ + spinlock_t read_lock; + spinlock_t write_lock; +} drm_waitlist_t; + +typedef struct drm_freelist { + int initialized; /* Freelist in use */ + atomic_t count; /* Number of free buffers */ + drm_buf_t *next; /* End pointer */ + + wait_queue_head_t waiting; /* Processes waiting on free bufs */ + int low_mark; /* Low water mark */ + int high_mark; /* High water mark */ + atomic_t wfh; /* If waiting for high mark */ + spinlock_t lock; +} drm_freelist_t; + +typedef struct drm_buf_entry { + int buf_size; + int buf_count; + drm_buf_t *buflist; + int seg_count; + int page_order; + unsigned long *seglist; + + drm_freelist_t freelist; +} drm_buf_entry_t; + +typedef struct drm_hw_lock { + __volatile__ unsigned int lock; + char padding[60]; /* Pad to cache line */ +} drm_hw_lock_t; + +typedef struct drm_file { + int authenticated; + int minor; + pid_t pid; + uid_t uid; + drm_magic_t magic; + unsigned long ioctl_count; + struct drm_file *next; + struct drm_file *prev; + struct drm_device *dev; + int remove_auth_on_close; +} drm_file_t; + + +typedef struct drm_queue { + atomic_t use_count; /* Outstanding uses (+1) */ + atomic_t finalization; /* Finalization in progress */ + atomic_t block_count; /* Count of processes waiting */ + atomic_t block_read; /* Queue blocked for reads */ + wait_queue_head_t read_queue; /* Processes waiting on block_read */ + atomic_t block_write; /* Queue blocked for writes */ + wait_queue_head_t write_queue; /* Processes waiting on block_write */ + atomic_t total_queued; /* Total queued statistic */ + atomic_t total_flushed;/* Total flushes statistic */ + atomic_t total_locks; /* Total locks statistics */ + drm_ctx_flags_t flags; /* Context preserving and 2D-only */ + drm_waitlist_t waitlist; /* Pending buffers */ + wait_queue_head_t flush_queue; /* Processes waiting until flush */ +} drm_queue_t; + +typedef struct drm_lock_data { + drm_hw_lock_t *hw_lock; /* Hardware lock */ + pid_t pid; /* PID of lock holder (0=kernel) */ + wait_queue_head_t lock_queue; /* Queue of blocked processes */ + unsigned long lock_time; /* Time of last lock in jiffies */ +} drm_lock_data_t; + +typedef struct drm_device_dma { + /* Performance Counters */ + atomic_t total_prio; /* Total DRM_DMA_PRIORITY */ + atomic_t total_bytes; /* Total bytes DMA'd */ + atomic_t total_dmas; /* Total DMA buffers dispatched */ + + atomic_t total_missed_dma; /* Missed drm_do_dma */ + atomic_t total_missed_lock; /* Missed lock in drm_do_dma */ + atomic_t total_missed_free; /* Missed drm_free_this_buffer */ + atomic_t total_missed_sched;/* Missed drm_dma_schedule */ + + atomic_t total_tried; /* Tried next_buffer */ + atomic_t total_hit; /* Sent next_buffer */ + atomic_t total_lost; /* Lost interrupt */ + + drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; + int buf_count; + drm_buf_t **buflist; /* Vector of pointers info bufs */ + int seg_count; + int page_count; + unsigned long *pagelist; + unsigned long byte_count; + enum { + _DRM_DMA_USE_AGP = 0x01 + } flags; + + /* DMA support */ + drm_buf_t *this_buffer; /* Buffer being sent */ + drm_buf_t *next_buffer; /* Selected buffer to send */ + drm_queue_t *next_queue; /* Queue from which buffer selected*/ + wait_queue_head_t waiting; /* Processes waiting on free bufs */ +} drm_device_dma_t; + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +typedef struct drm_agp_mem { + unsigned long handle; + agp_memory *memory; + unsigned long bound; /* address */ + int pages; + struct drm_agp_mem *prev; + struct drm_agp_mem *next; +} drm_agp_mem_t; + +typedef struct drm_agp_head { + agp_kern_info agp_info; + const char *chipset; + drm_agp_mem_t *memory; + unsigned long mode; + int enabled; + int acquired; + unsigned long base; + int agp_mtrr; +} drm_agp_head_t; + +typedef struct { + void (*free_memory)(agp_memory *); + agp_memory *(*allocate_memory)(size_t, u32); + int (*bind_memory)(agp_memory *, off_t); + int (*unbind_memory)(agp_memory *); + void (*enable)(u32); + int (*acquire)(void); + void (*release)(void); + void (*copy_info)(agp_kern_info *); +} drm_agp_func_t; + +extern drm_agp_func_t drm_agp; +#endif + +typedef struct drm_device { + const char *name; /* Simple driver name */ + char *unique; /* Unique identifier: e.g., busid */ + int unique_len; /* Length of unique field */ + dev_t device; /* Device number for mknod */ + char *devname; /* For /proc/interrupts */ + + int blocked; /* Blocked due to VC switch? */ + struct proc_dir_entry *root; /* Root for this device's entries */ + + /* Locks */ + spinlock_t count_lock; /* For inuse, open_count, buf_use */ + struct semaphore struct_sem; /* For others */ + + /* Usage Counters */ + int open_count; /* Outstanding files open */ + atomic_t ioctl_count; /* Outstanding IOCTLs pending */ + atomic_t vma_count; /* Outstanding vma areas open */ + int buf_use; /* Buffers in use -- cannot alloc */ + atomic_t buf_alloc; /* Buffer allocation in progress */ + + /* Performance Counters */ + atomic_t total_open; + atomic_t total_close; + atomic_t total_ioctl; + atomic_t total_irq; /* Total interruptions */ + atomic_t total_ctx; /* Total context switches */ + + atomic_t total_locks; + atomic_t total_unlocks; + atomic_t total_contends; + atomic_t total_sleeps; + + /* Authentication */ + drm_file_t *file_first; + drm_file_t *file_last; + drm_magic_head_t magiclist[DRM_HASH_SIZE]; + + /* Memory management */ + drm_map_t **maplist; /* Vector of pointers to regions */ + int map_count; /* Number of mappable regions */ + + drm_vma_entry_t *vmalist; /* List of vmas (for debugging) */ + drm_lock_data_t lock; /* Information on hardware lock */ + + /* DMA queues (contexts) */ + int queue_count; /* Number of active DMA queues */ + int queue_reserved; /* Number of reserved DMA queues */ + int queue_slots; /* Actual length of queuelist */ + drm_queue_t **queuelist; /* Vector of pointers to DMA queues */ + drm_device_dma_t *dma; /* Optional pointer for DMA support */ + + /* Context support */ + int irq; /* Interrupt used by board */ + __volatile__ long context_flag; /* Context swapping flag */ + __volatile__ long interrupt_flag; /* Interruption handler flag */ + __volatile__ long dma_flag; /* DMA dispatch flag */ + struct timer_list timer; /* Timer for delaying ctx switch */ + wait_queue_head_t context_wait; /* Processes waiting on ctx switch */ + int last_checked; /* Last context checked for DMA */ + int last_context; /* Last current context */ + unsigned long last_switch; /* jiffies at last context switch */ + struct tq_struct tq; + cycles_t ctx_start; + cycles_t lck_start; +#if DRM_DMA_HISTOGRAM + drm_histogram_t histo; +#endif + + /* Callback to X server for context switch + and for heavy-handed reset. */ + char buf[DRM_BSZ]; /* Output buffer */ + char *buf_rp; /* Read pointer */ + char *buf_wp; /* Write pointer */ + char *buf_end; /* End pointer */ + struct fasync_struct *buf_async;/* Processes waiting for SIGIO */ + wait_queue_head_t buf_readers; /* Processes waiting to read */ + wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */ + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + drm_agp_head_t *agp; +#endif + unsigned long *ctx_bitmap; + void *dev_private; +} drm_device_t; + + + /* Internal function definitions */ + + /* 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) */ +extern int drm_open_helper(struct inode *inode, struct file *filp, + drm_device_t *dev); +extern int drm_flush(struct file *filp); +extern int drm_release(struct inode *inode, struct file *filp); +extern int drm_fasync(int fd, struct file *filp, int on); +extern ssize_t drm_read(struct file *filp, char *buf, size_t count, + loff_t *off); +extern int drm_write_string(drm_device_t *dev, const char *s); +extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); + + /* 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); +extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); +extern unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, + unsigned long address, + int write_access); +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_shm_nopage_lock(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, + struct vm_area_struct *vma); +extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); + + + /* Proc support (proc.c) */ +extern int drm_proc_init(drm_device_t *dev); +extern int drm_proc_cleanup(void); + + /* Memory management support (memory.c) */ +extern void drm_mem_init(void); +extern int drm_mem_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +extern void *drm_alloc(size_t size, int area); +extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, + int area); +extern char *drm_strdup(const char *s, int area); +extern void drm_strfree(const char *s, int area); +extern void drm_free(void *pt, size_t size, int area); +extern unsigned long drm_alloc_pages(int order, int area); +extern void drm_free_pages(unsigned long address, int order, + int area); +extern void *drm_ioremap(unsigned long offset, unsigned long size); +extern void drm_ioremapfree(void *pt, unsigned long size); + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +extern agp_memory *drm_alloc_agp(int pages, u32 type); +extern int drm_free_agp(agp_memory *handle, int pages); +extern int drm_bind_agp(agp_memory *handle, unsigned int start); +extern int drm_unbind_agp(agp_memory *handle); +#endif + + + /* Buffer management support (bufs.c) */ +extern int drm_order(unsigned long size); +extern int drm_addmap(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_addbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_infobufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_markbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_freebufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mapbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Buffer list management support (lists.c) */ +extern int drm_waitlist_create(drm_waitlist_t *bl, int count); +extern int drm_waitlist_destroy(drm_waitlist_t *bl); +extern int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf); +extern drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl); + +extern int drm_freelist_create(drm_freelist_t *bl, int count); +extern int drm_freelist_destroy(drm_freelist_t *bl); +extern int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, + drm_buf_t *buf); +extern drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block); + + /* DMA support (gen_dma.c) */ +extern void drm_dma_setup(drm_device_t *dev); +extern void drm_dma_takedown(drm_device_t *dev); +extern void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf); +extern void drm_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern int drm_context_switch(drm_device_t *dev, int old, int new); +extern int drm_context_switch_complete(drm_device_t *dev, int new); +extern void drm_clear_next_buffer(drm_device_t *dev); +extern int drm_select_queue(drm_device_t *dev, + void (*wrapper)(unsigned long)); +extern int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma); +extern int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma); +#if DRM_DMA_HISTOGRAM +extern int drm_histogram_slot(unsigned long count); +extern void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf); +#endif + + + /* Misc. IOCTL support (ioctl.c) */ +extern int drm_irq_busid(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_getunique(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_setunique(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Context IOCTL support (context.c) */ +extern int drm_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Drawable IOCTL support (drawable.c) */ +extern int drm_adddraw(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_rmdraw(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Authentication IOCTL support (auth.c) */ +extern int drm_add_magic(drm_device_t *dev, drm_file_t *priv, + drm_magic_t magic); +extern int drm_remove_magic(drm_device_t *dev, drm_magic_t magic); +extern int drm_getmagic(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_authmagic(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Locking IOCTL support (lock.c) */ +extern int drm_block(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_unblock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_lock_take(__volatile__ unsigned int *lock, + unsigned int context); +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, + unsigned int context); +extern int drm_finish(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_flush_unblock(drm_device_t *dev, int context, + drm_lock_flags_t flags); +extern int drm_flush_block_and_flush(drm_device_t *dev, int context, + drm_lock_flags_t flags); + + /* Context Bitmap support (ctxbitmap.c) */ +extern int drm_ctxbitmap_init(drm_device_t *dev); +extern void drm_ctxbitmap_cleanup(drm_device_t *dev); +extern int drm_ctxbitmap_next(drm_device_t *dev); +extern void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle); + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + /* AGP/GART support (agpsupport.c) */ +extern drm_agp_head_t *drm_agp_init(void); +extern void drm_agp_uninit(void); +extern int drm_agp_acquire(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_release(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_enable(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_unbind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_agp_bind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +#endif +#endif +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/drm_syms.c linux/drivers/char/drm/drm_syms.c --- v2.2.17/drivers/char/drm/drm_syms.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/drm_syms.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,149 @@ +#include +#include "drmP.h" + +/* Misc. support (init.c) */ +EXPORT_SYMBOL(drm_flags); +EXPORT_SYMBOL(drm_parse_options); +EXPORT_SYMBOL(drm_cpu_valid); + +/* Device support (fops.c) */ +EXPORT_SYMBOL(drm_open_helper); +EXPORT_SYMBOL(drm_flush); +EXPORT_SYMBOL(drm_release); +EXPORT_SYMBOL(drm_fasync); +EXPORT_SYMBOL(drm_read); +EXPORT_SYMBOL(drm_write_string); +EXPORT_SYMBOL(drm_poll); + +/* Mapping support (vm.c) */ +#if LINUX_VERSION_CODE < 0x020317 +EXPORT_SYMBOL(drm_vm_nopage); +EXPORT_SYMBOL(drm_vm_shm_nopage); +EXPORT_SYMBOL(drm_vm_dma_nopage); +#else +/* Return type changed in 2.3.23 */ +EXPORT_SYMBOL(drm_vm_nopage); +EXPORT_SYMBOL(drm_vm_shm_nopage); +EXPORT_SYMBOL(drm_vm_dma_nopage); +#endif + +EXPORT_SYMBOL(drm_vm_open); +EXPORT_SYMBOL(drm_vm_close); +EXPORT_SYMBOL(drm_mmap_dma); +EXPORT_SYMBOL(drm_mmap); +EXPORT_SYMBOL(drm_vm_ops); +EXPORT_SYMBOL(drm_vm_shm_ops); +EXPORT_SYMBOL(drm_vm_dma_ops); + +/* Proc support (proc.c) */ +EXPORT_SYMBOL(drm_proc_init); +EXPORT_SYMBOL(drm_proc_cleanup); + +/* Memory management support (memory.c) */ +EXPORT_SYMBOL(drm_mem_init); +EXPORT_SYMBOL(drm_mem_info); +EXPORT_SYMBOL(drm_alloc); +EXPORT_SYMBOL(drm_realloc); +EXPORT_SYMBOL(drm_strdup); +EXPORT_SYMBOL(drm_strfree); +EXPORT_SYMBOL(drm_free); +EXPORT_SYMBOL(drm_alloc_pages); +EXPORT_SYMBOL(drm_free_pages); +EXPORT_SYMBOL(drm_ioremap); +EXPORT_SYMBOL(drm_ioremapfree); +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +EXPORT_SYMBOL(drm_alloc_agp); +EXPORT_SYMBOL(drm_free_agp); +EXPORT_SYMBOL(drm_bind_agp); +EXPORT_SYMBOL(drm_unbind_agp); +#endif + +/* Buffer management support (bufs.c) */ +EXPORT_SYMBOL(drm_order); +EXPORT_SYMBOL(drm_addmap); +EXPORT_SYMBOL(drm_addbufs); +EXPORT_SYMBOL(drm_infobufs); +EXPORT_SYMBOL(drm_markbufs); +EXPORT_SYMBOL(drm_freebufs); +EXPORT_SYMBOL(drm_mapbufs); + +/* Buffer list management support (lists.c) */ +EXPORT_SYMBOL(drm_waitlist_create); +EXPORT_SYMBOL(drm_waitlist_destroy); +EXPORT_SYMBOL(drm_waitlist_put); +EXPORT_SYMBOL(drm_waitlist_get); +EXPORT_SYMBOL(drm_freelist_create); +EXPORT_SYMBOL(drm_freelist_destroy); +EXPORT_SYMBOL(drm_freelist_put); +EXPORT_SYMBOL(drm_freelist_get); + +/* DMA support (gen_dma.c) */ +EXPORT_SYMBOL(drm_dma_setup); +EXPORT_SYMBOL(drm_dma_takedown); +EXPORT_SYMBOL(drm_free_buffer); +EXPORT_SYMBOL(drm_reclaim_buffers); +EXPORT_SYMBOL(drm_context_switch); +EXPORT_SYMBOL(drm_context_switch_complete); +EXPORT_SYMBOL(drm_clear_next_buffer); +EXPORT_SYMBOL(drm_select_queue); +EXPORT_SYMBOL(drm_dma_enqueue); +EXPORT_SYMBOL(drm_dma_get_buffers); +#if DRM_DMA_HISTOGRAM +EXPORT_SYMBOL(drm_histogram_slot); +EXPORT_SYMBOL(drm_histogram_compute); +#endif + +/* Misc. IOCTL support (ioctl.c) */ +EXPORT_SYMBOL(drm_irq_busid); +EXPORT_SYMBOL(drm_getunique); +EXPORT_SYMBOL(drm_setunique); + +/* Context IOCTL support (context.c) */ +EXPORT_SYMBOL(drm_resctx); +EXPORT_SYMBOL(drm_addctx); +EXPORT_SYMBOL(drm_modctx); +EXPORT_SYMBOL(drm_getctx); +EXPORT_SYMBOL(drm_switchctx); +EXPORT_SYMBOL(drm_newctx); +EXPORT_SYMBOL(drm_rmctx); + +/* Drawable IOCTL support (drawable.c) */ +EXPORT_SYMBOL(drm_adddraw); +EXPORT_SYMBOL(drm_rmdraw); + +/* Authentication IOCTL support (auth.c) */ +EXPORT_SYMBOL(drm_add_magic); +EXPORT_SYMBOL(drm_remove_magic); +EXPORT_SYMBOL(drm_getmagic); +EXPORT_SYMBOL(drm_authmagic); + +/* Locking IOCTL support (lock.c) */ +EXPORT_SYMBOL(drm_block); +EXPORT_SYMBOL(drm_unblock); +EXPORT_SYMBOL(drm_lock_take); +EXPORT_SYMBOL(drm_lock_transfer); +EXPORT_SYMBOL(drm_lock_free); +EXPORT_SYMBOL(drm_finish); +EXPORT_SYMBOL(drm_flush_unblock); +EXPORT_SYMBOL(drm_flush_block_and_flush); + +/* Context Bitmap support (ctxbitmap.c) */ +EXPORT_SYMBOL(drm_ctxbitmap_init); +EXPORT_SYMBOL(drm_ctxbitmap_cleanup); +EXPORT_SYMBOL(drm_ctxbitmap_next); +EXPORT_SYMBOL(drm_ctxbitmap_free); + +/* AGP/GART support (agpsupport.c) */ +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +EXPORT_SYMBOL(drm_agp); +EXPORT_SYMBOL(drm_agp_init); +EXPORT_SYMBOL(drm_agp_uninit); +EXPORT_SYMBOL(drm_agp_acquire); +EXPORT_SYMBOL(drm_agp_release); +EXPORT_SYMBOL(drm_agp_enable); +EXPORT_SYMBOL(drm_agp_info); +EXPORT_SYMBOL(drm_agp_alloc); +EXPORT_SYMBOL(drm_agp_free); +EXPORT_SYMBOL(drm_agp_unbind); +EXPORT_SYMBOL(drm_agp_bind); +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/ffb_context.c linux/drivers/char/drm/ffb_context.c --- v2.2.17/drivers/char/drm/ffb_context.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/ffb_context.c Sun Sep 10 14:49:10 2000 @@ -0,0 +1,531 @@ +/* $Id: ffb_context.c,v 1.4.2.1 2000/09/05 00:10:45 davem Exp $ + * ffb_context.c: Creator/Creator3D DRI/DRM context switching. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + * + * Almost entirely stolen from tdfx_context.c, see there + * for authors. + */ + +#define __NO_VERSION__ +#include +#include + +#include "drmP.h" + +#include "ffb_drv.h" + +static int ffb_alloc_queue(drm_device_t *dev, int is_2d_only) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int i; + + for (i = 0; i < FFB_MAX_CTXS; i++) { + if (fpriv->hw_state[i] == NULL) + break; + } + if (i == FFB_MAX_CTXS) + return -1; + + fpriv->hw_state[i] = kmalloc(sizeof(struct ffb_hw_context), GFP_KERNEL); + if (fpriv->hw_state[i] == NULL) + return -1; + + fpriv->hw_state[i]->is_2d_only = is_2d_only; + + /* Plus one because 0 is the special DRM_KERNEL_CONTEXT. */ + return i + 1; +} + +static void ffb_save_context(ffb_dev_priv_t *fpriv, int idx) +{ + ffb_fbcPtr ffb = fpriv->regs; + struct ffb_hw_context *ctx; + int i; + + ctx = fpriv->hw_state[idx - 1]; + if (idx == 0 || ctx == NULL) + return; + + if (ctx->is_2d_only) { + /* 2D applications only care about certain pieces + * of state. + */ + ctx->drawop = upa_readl(&ffb->drawop); + ctx->ppc = upa_readl(&ffb->ppc); + ctx->wid = upa_readl(&ffb->wid); + ctx->fg = upa_readl(&ffb->fg); + ctx->bg = upa_readl(&ffb->bg); + ctx->xclip = upa_readl(&ffb->xclip); + ctx->fbc = upa_readl(&ffb->fbc); + ctx->rop = upa_readl(&ffb->rop); + ctx->cmp = upa_readl(&ffb->cmp); + ctx->matchab = upa_readl(&ffb->matchab); + ctx->magnab = upa_readl(&ffb->magnab); + ctx->pmask = upa_readl(&ffb->pmask); + ctx->xpmask = upa_readl(&ffb->xpmask); + ctx->lpat = upa_readl(&ffb->lpat); + ctx->fontxy = upa_readl(&ffb->fontxy); + ctx->fontw = upa_readl(&ffb->fontw); + ctx->fontinc = upa_readl(&ffb->fontinc); + + /* stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + ctx->stencil = upa_readl(&ffb->stencil); + ctx->stencilctl = upa_readl(&ffb->stencilctl); + } + + for (i = 0; i < 32; i++) + ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); + ctx->ucsr = upa_readl(&ffb->ucsr); + return; + } + + /* Fetch drawop. */ + ctx->drawop = upa_readl(&ffb->drawop); + + /* If we were saving the vertex registers, this is where + * we would do it. We would save 32 32-bit words starting + * at ffb->suvtx. + */ + + /* Capture rendering attributes. */ + + ctx->ppc = upa_readl(&ffb->ppc); /* Pixel Processor Control */ + ctx->wid = upa_readl(&ffb->wid); /* Current WID */ + ctx->fg = upa_readl(&ffb->fg); /* Constant FG color */ + ctx->bg = upa_readl(&ffb->bg); /* Constant BG color */ + ctx->consty = upa_readl(&ffb->consty); /* Constant Y */ + ctx->constz = upa_readl(&ffb->constz); /* Constant Z */ + ctx->xclip = upa_readl(&ffb->xclip); /* X plane clip */ + ctx->dcss = upa_readl(&ffb->dcss); /* Depth Cue Scale Slope */ + ctx->vclipmin = upa_readl(&ffb->vclipmin); /* Primary XY clip, minimum */ + ctx->vclipmax = upa_readl(&ffb->vclipmax); /* Primary XY clip, maximum */ + ctx->vclipzmin = upa_readl(&ffb->vclipzmin); /* Primary Z clip, minimum */ + ctx->vclipzmax = upa_readl(&ffb->vclipzmax); /* Primary Z clip, maximum */ + ctx->dcsf = upa_readl(&ffb->dcsf); /* Depth Cue Scale Front Bound */ + ctx->dcsb = upa_readl(&ffb->dcsb); /* Depth Cue Scale Back Bound */ + ctx->dczf = upa_readl(&ffb->dczf); /* Depth Cue Scale Z Front */ + ctx->dczb = upa_readl(&ffb->dczb); /* Depth Cue Scale Z Back */ + ctx->blendc = upa_readl(&ffb->blendc); /* Alpha Blend Control */ + ctx->blendc1 = upa_readl(&ffb->blendc1); /* Alpha Blend Color 1 */ + ctx->blendc2 = upa_readl(&ffb->blendc2); /* Alpha Blend Color 2 */ + ctx->fbc = upa_readl(&ffb->fbc); /* Frame Buffer Control */ + ctx->rop = upa_readl(&ffb->rop); /* Raster Operation */ + ctx->cmp = upa_readl(&ffb->cmp); /* Compare Controls */ + ctx->matchab = upa_readl(&ffb->matchab); /* Buffer A/B Match Ops */ + ctx->matchc = upa_readl(&ffb->matchc); /* Buffer C Match Ops */ + ctx->magnab = upa_readl(&ffb->magnab); /* Buffer A/B Magnitude Ops */ + ctx->magnc = upa_readl(&ffb->magnc); /* Buffer C Magnitude Ops */ + ctx->pmask = upa_readl(&ffb->pmask); /* RGB Plane Mask */ + ctx->xpmask = upa_readl(&ffb->xpmask); /* X Plane Mask */ + ctx->ypmask = upa_readl(&ffb->ypmask); /* Y Plane Mask */ + ctx->zpmask = upa_readl(&ffb->zpmask); /* Z Plane Mask */ + + /* Auxiliary Clips. */ + ctx->auxclip0min = upa_readl(&ffb->auxclip[0].min); + ctx->auxclip0max = upa_readl(&ffb->auxclip[0].max); + ctx->auxclip1min = upa_readl(&ffb->auxclip[1].min); + ctx->auxclip1max = upa_readl(&ffb->auxclip[1].max); + ctx->auxclip2min = upa_readl(&ffb->auxclip[2].min); + ctx->auxclip2max = upa_readl(&ffb->auxclip[2].max); + ctx->auxclip3min = upa_readl(&ffb->auxclip[3].min); + ctx->auxclip3max = upa_readl(&ffb->auxclip[3].max); + + ctx->lpat = upa_readl(&ffb->lpat); /* Line Pattern */ + ctx->fontxy = upa_readl(&ffb->fontxy); /* XY Font Coordinate */ + ctx->fontw = upa_readl(&ffb->fontw); /* Font Width */ + ctx->fontinc = upa_readl(&ffb->fontinc); /* Font X/Y Increment */ + + /* These registers/features only exist on FFB2 and later chips. */ + if (fpriv->ffb_type >= ffb2_prototype) { + ctx->dcss1 = upa_readl(&ffb->dcss1); /* Depth Cue Scale Slope 1 */ + ctx->dcss2 = upa_readl(&ffb->dcss2); /* Depth Cue Scale Slope 2 */ + ctx->dcss2 = upa_readl(&ffb->dcss3); /* Depth Cue Scale Slope 3 */ + ctx->dcs2 = upa_readl(&ffb->dcs2); /* Depth Cue Scale 2 */ + ctx->dcs3 = upa_readl(&ffb->dcs3); /* Depth Cue Scale 3 */ + ctx->dcs4 = upa_readl(&ffb->dcs4); /* Depth Cue Scale 4 */ + ctx->dcd2 = upa_readl(&ffb->dcd2); /* Depth Cue Depth 2 */ + ctx->dcd3 = upa_readl(&ffb->dcd3); /* Depth Cue Depth 3 */ + ctx->dcd4 = upa_readl(&ffb->dcd4); /* Depth Cue Depth 4 */ + + /* And stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + ctx->stencil = upa_readl(&ffb->stencil); + ctx->stencilctl = upa_readl(&ffb->stencilctl); + } + } + + /* Save the 32x32 area pattern. */ + for (i = 0; i < 32; i++) + ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); + + /* Finally, stash away the User Constol/Status Register. */ + ctx->ucsr = upa_readl(&ffb->ucsr); +} + +static void ffb_restore_context(ffb_dev_priv_t *fpriv, int old, int idx) +{ + ffb_fbcPtr ffb = fpriv->regs; + struct ffb_hw_context *ctx; + int i; + + ctx = fpriv->hw_state[idx - 1]; + if (idx == 0 || ctx == NULL) + return; + + if (ctx->is_2d_only) { + /* 2D applications only care about certain pieces + * of state. + */ + upa_writel(ctx->drawop, &ffb->drawop); + + /* If we were restoring the vertex registers, this is where + * we would do it. We would restore 32 32-bit words starting + * at ffb->suvtx. + */ + + upa_writel(ctx->ppc, &ffb->ppc); + upa_writel(ctx->wid, &ffb->wid); + upa_writel(ctx->fg, &ffb->fg); + upa_writel(ctx->bg, &ffb->bg); + upa_writel(ctx->xclip, &ffb->xclip); + upa_writel(ctx->fbc, &ffb->fbc); + upa_writel(ctx->rop, &ffb->rop); + upa_writel(ctx->cmp, &ffb->cmp); + upa_writel(ctx->matchab, &ffb->matchab); + upa_writel(ctx->magnab, &ffb->magnab); + upa_writel(ctx->pmask, &ffb->pmask); + upa_writel(ctx->xpmask, &ffb->xpmask); + upa_writel(ctx->lpat, &ffb->lpat); + upa_writel(ctx->fontxy, &ffb->fontxy); + upa_writel(ctx->fontw, &ffb->fontw); + upa_writel(ctx->fontinc, &ffb->fontinc); + + /* stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + upa_writel(ctx->stencil, &ffb->stencil); + upa_writel(ctx->stencilctl, &ffb->stencilctl); + upa_writel(0x80000000, &ffb->fbc); + upa_writel((ctx->stencilctl | 0x80000), + &ffb->rawstencilctl); + upa_writel(ctx->fbc, &ffb->fbc); + } + + for (i = 0; i < 32; i++) + upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); + upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); + return; + } + + /* Restore drawop. */ + upa_writel(ctx->drawop, &ffb->drawop); + + /* If we were restoring the vertex registers, this is where + * we would do it. We would restore 32 32-bit words starting + * at ffb->suvtx. + */ + + /* Restore rendering attributes. */ + + upa_writel(ctx->ppc, &ffb->ppc); /* Pixel Processor Control */ + upa_writel(ctx->wid, &ffb->wid); /* Current WID */ + upa_writel(ctx->fg, &ffb->fg); /* Constant FG color */ + upa_writel(ctx->bg, &ffb->bg); /* Constant BG color */ + upa_writel(ctx->consty, &ffb->consty); /* Constant Y */ + upa_writel(ctx->constz, &ffb->constz); /* Constant Z */ + upa_writel(ctx->xclip, &ffb->xclip); /* X plane clip */ + upa_writel(ctx->dcss, &ffb->dcss); /* Depth Cue Scale Slope */ + upa_writel(ctx->vclipmin, &ffb->vclipmin); /* Primary XY clip, minimum */ + upa_writel(ctx->vclipmax, &ffb->vclipmax); /* Primary XY clip, maximum */ + upa_writel(ctx->vclipzmin, &ffb->vclipzmin); /* Primary Z clip, minimum */ + upa_writel(ctx->vclipzmax, &ffb->vclipzmax); /* Primary Z clip, maximum */ + upa_writel(ctx->dcsf, &ffb->dcsf); /* Depth Cue Scale Front Bound */ + upa_writel(ctx->dcsb, &ffb->dcsb); /* Depth Cue Scale Back Bound */ + upa_writel(ctx->dczf, &ffb->dczf); /* Depth Cue Scale Z Front */ + upa_writel(ctx->dczb, &ffb->dczb); /* Depth Cue Scale Z Back */ + upa_writel(ctx->blendc, &ffb->blendc); /* Alpha Blend Control */ + upa_writel(ctx->blendc1, &ffb->blendc1); /* Alpha Blend Color 1 */ + upa_writel(ctx->blendc2, &ffb->blendc2); /* Alpha Blend Color 2 */ + upa_writel(ctx->fbc, &ffb->fbc); /* Frame Buffer Control */ + upa_writel(ctx->rop, &ffb->rop); /* Raster Operation */ + upa_writel(ctx->cmp, &ffb->cmp); /* Compare Controls */ + upa_writel(ctx->matchab, &ffb->matchab); /* Buffer A/B Match Ops */ + upa_writel(ctx->matchc, &ffb->matchc); /* Buffer C Match Ops */ + upa_writel(ctx->magnab, &ffb->magnab); /* Buffer A/B Magnitude Ops */ + upa_writel(ctx->magnc, &ffb->magnc); /* Buffer C Magnitude Ops */ + upa_writel(ctx->pmask, &ffb->pmask); /* RGB Plane Mask */ + upa_writel(ctx->xpmask, &ffb->xpmask); /* X Plane Mask */ + upa_writel(ctx->ypmask, &ffb->ypmask); /* Y Plane Mask */ + upa_writel(ctx->zpmask, &ffb->zpmask); /* Z Plane Mask */ + + /* Auxiliary Clips. */ + upa_writel(ctx->auxclip0min, &ffb->auxclip[0].min); + upa_writel(ctx->auxclip0max, &ffb->auxclip[0].max); + upa_writel(ctx->auxclip1min, &ffb->auxclip[1].min); + upa_writel(ctx->auxclip1max, &ffb->auxclip[1].max); + upa_writel(ctx->auxclip2min, &ffb->auxclip[2].min); + upa_writel(ctx->auxclip2max, &ffb->auxclip[2].max); + upa_writel(ctx->auxclip3min, &ffb->auxclip[3].min); + upa_writel(ctx->auxclip3max, &ffb->auxclip[3].max); + + upa_writel(ctx->lpat, &ffb->lpat); /* Line Pattern */ + upa_writel(ctx->fontxy, &ffb->fontxy); /* XY Font Coordinate */ + upa_writel(ctx->fontw, &ffb->fontw); /* Font Width */ + upa_writel(ctx->fontinc, &ffb->fontinc); /* Font X/Y Increment */ + + /* These registers/features only exist on FFB2 and later chips. */ + if (fpriv->ffb_type >= ffb2_prototype) { + upa_writel(ctx->dcss1, &ffb->dcss1); /* Depth Cue Scale Slope 1 */ + upa_writel(ctx->dcss2, &ffb->dcss2); /* Depth Cue Scale Slope 2 */ + upa_writel(ctx->dcss3, &ffb->dcss2); /* Depth Cue Scale Slope 3 */ + upa_writel(ctx->dcs2, &ffb->dcs2); /* Depth Cue Scale 2 */ + upa_writel(ctx->dcs3, &ffb->dcs3); /* Depth Cue Scale 3 */ + upa_writel(ctx->dcs4, &ffb->dcs4); /* Depth Cue Scale 4 */ + upa_writel(ctx->dcd2, &ffb->dcd2); /* Depth Cue Depth 2 */ + upa_writel(ctx->dcd3, &ffb->dcd3); /* Depth Cue Depth 3 */ + upa_writel(ctx->dcd4, &ffb->dcd4); /* Depth Cue Depth 4 */ + + /* And stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + /* Unfortunately, there is a hardware bug on + * the FFB2+ chips which prevents a normal write + * to the stencil control register from working + * as it should. + * + * The state controlled by the FFB stencilctl register + * really gets transferred to the per-buffer instances + * of the stencilctl register in the 3DRAM chips. + * + * The bug is that FFB does not update buffer C correctly, + * so we have to do it by hand for them. + */ + + /* This will update buffers A and B. */ + upa_writel(ctx->stencil, &ffb->stencil); + upa_writel(ctx->stencilctl, &ffb->stencilctl); + + /* Force FFB to use buffer C 3dram regs. */ + upa_writel(0x80000000, &ffb->fbc); + upa_writel((ctx->stencilctl | 0x80000), + &ffb->rawstencilctl); + + /* Now restore the correct FBC controls. */ + upa_writel(ctx->fbc, &ffb->fbc); + } + } + + /* Restore the 32x32 area pattern. */ + for (i = 0; i < 32; i++) + upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); + + /* Finally, stash away the User Constol/Status Register. + * The only state we really preserve here is the picking + * control. + */ + upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); +} + +#define FFB_UCSR_FB_BUSY 0x01000000 +#define FFB_UCSR_RP_BUSY 0x02000000 +#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) + +static void FFBWait(ffb_fbcPtr ffb) +{ + int limit = 100000; + + do { + u32 regval = upa_readl(&ffb->ucsr); + + if ((regval & FFB_UCSR_ALL_BUSY) == 0) + break; + } while (--limit); +} + +int ffb_context_switch(drm_device_t *dev, int old, int new) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + + atomic_inc(&dev->total_ctx); + +#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 || + dev->last_context == 0) { + dev->last_context = new; + return 0; + } + + FFBWait(fpriv->regs); + ffb_save_context(fpriv, old); + ffb_restore_context(fpriv, old, new); + FFBWait(fpriv->regs); + + dev->last_context = new; + + return 0; +} + +int ffb_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 ffb_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; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + idx = ffb_alloc_queue(dev, (ctx.flags & _DRM_CONTEXT_2DONLY)); + if (idx < 0) + return -ENFILE; + + DRM_DEBUG("%d\n", ctx.handle); + ctx.handle = idx; + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int ffb_modctx(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; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + struct ffb_hw_context *hwctx; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + + idx = ctx.handle; + if (idx <= 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + hwctx = fpriv->hw_state[idx - 1]; + if (hwctx == NULL) + return -EINVAL; + + if ((ctx.flags & _DRM_CONTEXT_2DONLY) == 0) + hwctx->is_2d_only = 0; + else + hwctx->is_2d_only = 1; + + return 0; +} + +int ffb_getctx(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; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + struct ffb_hw_context *hwctx; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + + idx = ctx.handle; + if (idx <= 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + hwctx = fpriv->hw_state[idx - 1]; + if (hwctx == NULL) + return -EINVAL; + + if (hwctx->is_2d_only != 0) + ctx.flags = _DRM_CONTEXT_2DONLY; + else + ctx.flags = 0; + + copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + + return 0; +} + +int ffb_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 ffb_context_switch(dev, dev->last_context, ctx.handle); +} + +int ffb_newctx(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); + + return 0; +} + +int ffb_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + + idx = ctx.handle - 1; + if (idx < 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + if (fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c --- v2.2.17/drivers/char/drm/ffb_drv.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/ffb_drv.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,881 @@ +/* $Id: ffb_drv.c,v 1.6.2.2 2000/09/07 03:51:06 davem Exp $ + * ffb_drv.c: Creator/Creator3D direct rendering driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +#include "drmP.h" + +#include +#include +#include +#include + +#include "ffb_drv.h" + +#include + +#define FFB_NAME "ffb" +#define FFB_DESC "Creator/Creator3D" +#define FFB_DATE "20000517" +#define FFB_MAJOR 0 +#define FFB_MINOR 0 +#define FFB_PATCHLEVEL 1 + +/* Forward declarations. */ +int ffb_init(void); +void ffb_cleanup(void); +static int ffb_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_open(struct inode *inode, struct file *filp); +static int ffb_release(struct inode *inode, struct file *filp); +static int ffb_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_mmap(struct file *filp, struct vm_area_struct *vma); + +/* From ffb_context.c */ +extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_addctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_modctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_getctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_switchctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_newctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_rmctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_context_switch(drm_device_t *, int, int); + +static struct file_operations ffb_fops = { +#if LINUX_VERSION_CODE >= 0x020322 + /* This started being used approx. 2.3.34 */ + owner: THIS_MODULE, +#endif + open: ffb_open, + flush: drm_flush, + release: ffb_release, + ioctl: ffb_ioctl, + mmap: ffb_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +/* This is just a template, we make a new copy for each FFB + * we discover at init time so that each one gets a unique + * misc device minor number. + */ +static struct miscdevice ffb_misc = { + minor: MISC_DYNAMIC_MINOR, + name: FFB_NAME, + fops: &ffb_fops, +}; + +static drm_ioctl_desc_t ffb_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { ffb_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 }, /* XXX */ + + [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 }, + + /* The implementation is currently a nop just like on tdfx. + * Later we can do something more clever. -DaveM + */ + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { ffb_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { ffb_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { ffb_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { ffb_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { ffb_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { ffb_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { ffb_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)] = { ffb_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { ffb_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +}; +#define FFB_IOCTL_COUNT DRM_ARRAY_SIZE(ffb_ioctls) + +#ifdef MODULE +static char *ffb = NULL; +#endif + +MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_DESCRIPTION("Sun Creator/Creator3D DRI"); + +static int ffb_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 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: + 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; + + default: + 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; +} + +drm_device_t **ffb_dev_table; +static int ffb_dev_table_size; + +static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance) +{ + volatile unsigned char *strap_bits; + unsigned char val; + +#if LINUX_VERSION_CODE < 0x020300 + strap_bits = (volatile unsigned char *) + __va(ffb_priv->card_phys_base + 0x00200000UL); +#else + strap_bits = (volatile unsigned char *) + (ffb_priv->card_phys_base + 0x00200000UL); +#endif + + /* Don't ask, you have to read the value twice for whatever + * reason to get correct contents. + */ + val = upa_readb(strap_bits); + val = upa_readb(strap_bits); + switch (val & 0x78) { + case (0x0 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb1_prototype; + printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance); + break; + case (0x0 << 5) | (0x1 << 3): + ffb_priv->ffb_type = ffb1_standard; + printk("ffb%d: Detected FFB1\n", instance); + break; + case (0x0 << 5) | (0x3 << 3): + ffb_priv->ffb_type = ffb1_speedsort; + printk("ffb%d: Detected FFB1-SpeedSort\n", instance); + break; + case (0x1 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb2_prototype; + printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance); + break; + case (0x1 << 5) | (0x1 << 3): + ffb_priv->ffb_type = ffb2_vertical; + printk("ffb%d: Detected FFB2/vertical\n", instance); + break; + case (0x1 << 5) | (0x2 << 3): + ffb_priv->ffb_type = ffb2_vertical_plus; + printk("ffb%d: Detected FFB2+/vertical\n", instance); + break; + case (0x2 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb2_horizontal; + printk("ffb%d: Detected FFB2/horizontal\n", instance); + break; + case (0x2 << 5) | (0x2 << 3): + ffb_priv->ffb_type = ffb2_horizontal; + printk("ffb%d: Detected FFB2+/horizontal\n", instance); + break; + default: + ffb_priv->ffb_type = ffb2_vertical; + printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val); + break; + }; +} + +static int ffb_init_one(int prom_node, int instance) +{ + struct linux_prom64_registers regs[2*PROMREG_MAX]; + drm_device_t *dev; + ffb_dev_priv_t *ffb_priv; + int ret, i; + + dev = kmalloc(sizeof(drm_device_t) + sizeof(ffb_dev_priv_t), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + memset(dev, 0, sizeof(*dev)); + spin_lock_init(&dev->count_lock); + sema_init(&dev->struct_sem, 1); + + ffb_priv = (ffb_dev_priv_t *) (dev + 1); + ffb_priv->prom_node = prom_node; + if (prom_getproperty(ffb_priv->prom_node, "reg", + (void *)regs, sizeof(regs)) <= 0) { + kfree(dev); + return -EINVAL; + } + ffb_priv->card_phys_base = regs[0].phys_addr; +#if LINUX_VERSION_CODE < 0x020300 + ffb_priv->regs = (ffb_fbcPtr) + __va(regs[0].phys_addr + 0x00600000UL); +#else + ffb_priv->regs = (ffb_fbcPtr) + (regs[0].phys_addr + 0x00600000UL); +#endif + get_ffb_type(ffb_priv, instance); + for (i = 0; i < FFB_MAX_CTXS; i++) + ffb_priv->hw_state[i] = NULL; + + ffb_dev_table[instance] = dev; + +#ifdef MODULE + drm_parse_options(ffb); +#endif + + memcpy(&ffb_priv->miscdev, &ffb_misc, sizeof(ffb_misc)); + ret = misc_register(&ffb_priv->miscdev); + if (ret) { + ffb_dev_table[instance] = NULL; + kfree(dev); + return ret; + } + + dev->device = MKDEV(MISC_MAJOR, ffb_priv->miscdev.minor); + dev->name = FFB_NAME; + + drm_mem_init(); + drm_proc_init(dev); + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d at %016lx\n", + FFB_NAME, + FFB_MAJOR, + FFB_MINOR, + FFB_PATCHLEVEL, + FFB_DATE, + ffb_priv->miscdev.minor, + ffb_priv->card_phys_base); + + return 0; +} + +static int ffb_init_dev_table(void) +{ + int root, node; + int total = 0; + + root = prom_getchild(prom_root_node); + for (node = prom_searchsiblings(root, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) + total++; + + ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL); + if (!ffb_dev_table) + return -ENOMEM; + + ffb_dev_table_size = total; + + return 0; +} + +int ffb_init(void) +{ + int root, node, instance, ret; + + ret = ffb_init_dev_table(); + if (ret) + return ret; + + instance = 0; + root = prom_getchild(prom_root_node); + for (node = prom_searchsiblings(root, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { + ret = ffb_init_one(node, instance); + if (ret) + return ret; + instance++; + } + + return 0; +} + +void ffb_cleanup(void) +{ + int instance; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + for (instance = 0; instance < ffb_dev_table_size; instance++) { + drm_device_t *dev = ffb_dev_table[instance]; + ffb_dev_priv_t *ffb_priv; + + if (!dev) + continue; + + ffb_priv = (ffb_dev_priv_t *) (dev + 1); + if (misc_deregister(&ffb_priv->miscdev)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + ffb_takedown(dev); + kfree(dev); + ffb_dev_table[instance] = NULL; + } + kfree(ffb_dev_table); + ffb_dev_table = NULL; + ffb_dev_table_size = 0; +} + +static int ffb_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + drm_version_t version; + int len, ret; + + ret = copy_from_user(&version, (drm_version_t *)arg, sizeof(version)); + if (ret) + return -EFAULT; + + version.version_major = FFB_MAJOR; + version.version_minor = FFB_MINOR; + version.version_patchlevel = FFB_PATCHLEVEL; + + len = strlen(FFB_NAME); + if (len > version.name_len) + len = version.name_len; + version.name_len = len; + if (len && version.name) { + ret = copy_to_user(version.name, FFB_NAME, len); + if (ret) + return -EFAULT; + } + + len = strlen(FFB_DATE); + if (len > version.date_len) + len = version.date_len; + version.date_len = len; + if (len && version.date) { + ret = copy_to_user(version.date, FFB_DATE, len); + if (ret) + return -EFAULT; + } + + len = strlen(FFB_DESC); + if (len > version.desc_len) + len = version.desc_len; + version.desc_len = len; + if (len && version.desc) { + ret = copy_to_user(version.desc, FFB_DESC, len); + if (ret) + return -EFAULT; + } + + ret = copy_to_user((drm_version_t *) arg, &version, sizeof(version)); + if (ret) + ret = -EFAULT; + + return ret; +} + +static int ffb_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); + + return 0; +} + +static int ffb_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev; + int minor, i; + int ret = 0; + + minor = MINOR(inode->i_rdev); + for (i = 0; i < ffb_dev_table_size; i++) { + ffb_dev_priv_t *ffb_priv; + + ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1); + + if (ffb_priv->miscdev.minor == minor) + break; + } + + if (i >= ffb_dev_table_size) + return -EINVAL; + + dev = ffb_dev_table[i]; + if (!dev) + return -EINVAL; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + ret = drm_open_helper(inode, filp, dev); + if (!ret) { + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return ffb_setup(dev); + } + spin_unlock(&dev->count_lock); + } + + return ret; +} + +static int ffb_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + int ret = 0; + + lock_kernel(); + dev = priv->dev; + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (dev->lock.hw_lock != NULL + && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); + int idx; + + /* We have to free up the rogue hw context state + * holding error or else we will leak it. + */ + idx = context - 1; + if (fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } + } + + ret = drm_release(inode, filp); + + if (!ret) { + 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); + unlock_kernel(); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + ret = ffb_takedown(dev); + unlock_kernel(); + return ret; + } + spin_unlock(&dev->count_lock); + } + + unlock_kernel(); + return ret; +} + +static int ffb_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; + drm_ioctl_desc_t *ioctl; + drm_ioctl_t *func; + int ret; + + 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 >= FFB_IOCTL_COUNT) { + ret = -EINVAL; + } else { + ioctl = &ffb_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function\n"); + ret = -EINVAL; + } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) + || (ioctl->auth_needed && !priv->authenticated)) { + ret = -EACCES; + } else { + ret = (func)(inode, filp, cmd, arg); + } + } + + atomic_dec(&dev->ioctl_count); + + return ret; +} + +static int ffb_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; + + ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)); + if (ret) + return -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); + + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + 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->policy |= SCHED_YIELD; + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + + if (!ret && + (dev->last_context != lock.context)) + ffb_context_switch(dev, dev->last_context, lock.context); + + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + + return ret; +} + +int ffb_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; + unsigned int old, new, prev, ctx; + int ret; + + ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)); + if (ret) + return -EFAULT; + + if ((ctx = 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); + + /* We no longer really hold it, but if we are the next + * agent to request it then we should just be able to + * take it immediately and not eat the ioctl. + */ + dev->lock.pid = 0; + { + __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; + + do { + old = *plock; + new = ctx; + prev = cmpxchg(plock, old, new); + } while (prev != old); + } + + wake_up_interruptible(&dev->lock.lock_queue); + + return 0; +} + +static void align_fb_mapping(struct vm_area_struct *vma) +{ + unsigned long j, alignment; + + j = vma->vm_end - vma->vm_start; + for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3) + if (j >= alignment) + break; + if (alignment > PAGE_SIZE) { + j = alignment; + alignment = j - (vma->vm_start & (j - 1)); + if (alignment != j) { + struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start); + + if (!vmm || vmm->vm_start >= vma->vm_end + alignment) { + vma->vm_start += alignment; + vma->vm_end += alignment; + } + } + } +} + +/* The problem here is, due to virtual cache aliasing, + * we must make sure the shared memory area lands in the + * same dcache line for both the kernel and all drm clients. + */ +static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt) +{ + kvirt &= PAGE_SIZE; + if ((vma->vm_start & PAGE_SIZE) != kvirt) { + struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start); + + if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) { + vma->vm_start += PAGE_SIZE; + vma->vm_end += PAGE_SIZE; + } + } +} + +extern struct vm_operations_struct drm_vm_ops; +extern struct vm_operations_struct drm_vm_shm_ops; + +static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + ffb_dev_priv_t *ffb_priv; + int i, minor; + + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + + lock_kernel(); + minor = MINOR(filp->f_dentry->d_inode->i_rdev); + ffb_priv = NULL; + for (i = 0; i < ffb_dev_table_size; i++) { + ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1); + if (ffb_priv->miscdev.minor == minor) + break; + } + if (i >= ffb_dev_table_size) { + unlock_kernel(); + return -EINVAL; + } + /* We don't support/need dma mappings, so... */ + if (!VM_OFFSET(vma)) { + unlock_kernel(); + return -EINVAL; + } + for (i = 0; i < dev->map_count; i++) { + unsigned long off; + + map = dev->maplist[i]; + + /* Ok, a little hack to make 32-bit apps work. */ + off = (map->offset & 0xffffffff); + if (off == VM_OFFSET(vma)) + break; + } + + if (i >= dev->map_count) { + unlock_kernel(); + return -EINVAL; + } + if (!map || + ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) { + unlock_kernel(); + return -EPERM; + } + if (map->size != (vma->vm_end - vma->vm_start)) { + unlock_kernel(); + return -EINVAL; + } + /* Set read-only attribute before mappings are created + * so it works for fb/reg maps too. + */ + if (map->flags & _DRM_READ_ONLY) + vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect( + __pte(pgprot_val(vma->vm_page_prot))))); + + switch (map->type) { + case _DRM_FRAME_BUFFER: + align_fb_mapping(vma); + /* FALLTHROUGH */ + + case _DRM_REGISTERS: + /* In order to handle 32-bit drm apps/xserver we + * play a trick. The mappings only really specify + * the 32-bit offset from the cards 64-bit base + * address, and we just add in the base here. + */ + vma->vm_flags |= VM_IO; + if (io_remap_page_range(vma->vm_start, + ffb_priv->card_phys_base + VM_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot, 0)) { + unlock_kernel(); + return -EAGAIN; + } + vma->vm_ops = &drm_vm_ops; + break; + case _DRM_SHM: + align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock); + vma->vm_ops = &drm_vm_shm_ops; + + /* Don't let this area swap. Change when + * DRM_KERNEL advisory is supported. + */ + vma->vm_flags |= VM_LOCKED; + break; + default: + unlock_kernel(); + return -EINVAL; /* This should never happen. */ + }; + unlock_kernel(); + + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + +#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ + /* In Linux 2.2.3 and above, this is + handled in do_mmap() in mm/mmap.c. */ + ++filp->f_count; +#endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ + drm_vm_open(vma); + return 0; +} + +module_init(ffb_init); +module_exit(ffb_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/ffb_drv.h linux/drivers/char/drm/ffb_drv.h --- v2.2.17/drivers/char/drm/ffb_drv.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/ffb_drv.h Sun Sep 10 14:49:10 2000 @@ -0,0 +1,286 @@ +/* $Id: ffb_drv.h,v 1.1.2.1 2000/09/05 00:10:45 davem Exp $ + * ffb_drv.h: Creator/Creator3D direct rendering driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +/* 2.2.x compat items. */ +#ifndef upa_readb +#define upa_readb(x) (*(volatile u8 *)(x)) +#define upa_readw(x) (*(volatile u16 *)(x)) +#define upa_readl(x) (*(volatile u32 *)(x)) +#define upa_writeb(val,x) ((*(volatile u8 *)(x)) = (val)) +#define upa_writew(val,x) ((*(volatile u16 *)(x)) = (val)) +#define upa_writel(val,x) ((*(volatile u32 *)(x)) = (val)) +#endif /* !defined(upa_readb) */ + +/* Auxilliary clips. */ +typedef struct { + volatile unsigned int min; + volatile unsigned int max; +} ffb_auxclip, *ffb_auxclipPtr; + +/* FFB register set. */ +typedef struct _ffb_fbc { + /* Next vertex registers, on the right we list which drawops + * use said register and the logical name the register has in + * that context. + */ /* DESCRIPTION DRAWOP(NAME) */ +/*0x00*/unsigned int pad1[3]; /* Reserved */ +/*0x0c*/volatile unsigned int alpha; /* ALPHA Transparency */ +/*0x10*/volatile unsigned int red; /* RED */ +/*0x14*/volatile unsigned int green; /* GREEN */ +/*0x18*/volatile unsigned int blue; /* BLUE */ +/*0x1c*/volatile unsigned int z; /* DEPTH */ +/*0x20*/volatile unsigned int y; /* Y triangle(DOYF) */ + /* aadot(DYF) */ + /* ddline(DYF) */ + /* aaline(DYF) */ +/*0x24*/volatile unsigned int x; /* X triangle(DOXF) */ + /* aadot(DXF) */ + /* ddline(DXF) */ + /* aaline(DXF) */ +/*0x28*/unsigned int pad2[2]; /* Reserved */ +/*0x30*/volatile unsigned int ryf; /* Y (alias to DOYF) ddline(RYF) */ + /* aaline(RYF) */ + /* triangle(RYF) */ +/*0x34*/volatile unsigned int rxf; /* X ddline(RXF) */ + /* aaline(RXF) */ + /* triangle(RXF) */ +/*0x38*/unsigned int pad3[2]; /* Reserved */ +/*0x40*/volatile unsigned int dmyf; /* Y (alias to DOYF) triangle(DMYF) */ +/*0x44*/volatile unsigned int dmxf; /* X triangle(DMXF) */ +/*0x48*/unsigned int pad4[2]; /* Reserved */ +/*0x50*/volatile unsigned int ebyi; /* Y (alias to RYI) polygon(EBYI) */ +/*0x54*/volatile unsigned int ebxi; /* X polygon(EBXI) */ +/*0x58*/unsigned int pad5[2]; /* Reserved */ +/*0x60*/volatile unsigned int by; /* Y brline(RYI) */ + /* fastfill(OP) */ + /* polygon(YI) */ + /* rectangle(YI) */ + /* bcopy(SRCY) */ + /* vscroll(SRCY) */ +/*0x64*/volatile unsigned int bx; /* X brline(RXI) */ + /* polygon(XI) */ + /* rectangle(XI) */ + /* bcopy(SRCX) */ + /* vscroll(SRCX) */ + /* fastfill(GO) */ +/*0x68*/volatile unsigned int dy; /* destination Y fastfill(DSTY) */ + /* bcopy(DSRY) */ + /* vscroll(DSRY) */ +/*0x6c*/volatile unsigned int dx; /* destination X fastfill(DSTX) */ + /* bcopy(DSTX) */ + /* vscroll(DSTX) */ +/*0x70*/volatile unsigned int bh; /* Y (alias to RYI) brline(DYI) */ + /* dot(DYI) */ + /* polygon(ETYI) */ + /* Height fastfill(H) */ + /* bcopy(H) */ + /* vscroll(H) */ + /* Y count fastfill(NY) */ +/*0x74*/volatile unsigned int bw; /* X dot(DXI) */ + /* brline(DXI) */ + /* polygon(ETXI) */ + /* fastfill(W) */ + /* bcopy(W) */ + /* vscroll(W) */ + /* fastfill(NX) */ +/*0x78*/unsigned int pad6[2]; /* Reserved */ +/*0x80*/unsigned int pad7[32]; /* Reserved */ + + /* Setup Unit's vertex state register */ +/*100*/ volatile unsigned int suvtx; +/*104*/ unsigned int pad8[63]; /* Reserved */ + + /* Frame Buffer Control Registers */ +/*200*/ volatile unsigned int ppc; /* Pixel Processor Control */ +/*204*/ volatile unsigned int wid; /* Current WID */ +/*208*/ volatile unsigned int fg; /* FG data */ +/*20c*/ volatile unsigned int bg; /* BG data */ +/*210*/ volatile unsigned int consty; /* Constant Y */ +/*214*/ volatile unsigned int constz; /* Constant Z */ +/*218*/ volatile unsigned int xclip; /* X Clip */ +/*21c*/ volatile unsigned int dcss; /* Depth Cue Scale Slope */ +/*220*/ volatile unsigned int vclipmin; /* Viewclip XY Min Bounds */ +/*224*/ volatile unsigned int vclipmax; /* Viewclip XY Max Bounds */ +/*228*/ volatile unsigned int vclipzmin; /* Viewclip Z Min Bounds */ +/*22c*/ volatile unsigned int vclipzmax; /* Viewclip Z Max Bounds */ +/*230*/ volatile unsigned int dcsf; /* Depth Cue Scale Front Bound */ +/*234*/ volatile unsigned int dcsb; /* Depth Cue Scale Back Bound */ +/*238*/ volatile unsigned int dczf; /* Depth Cue Z Front */ +/*23c*/ volatile unsigned int dczb; /* Depth Cue Z Back */ +/*240*/ unsigned int pad9; /* Reserved */ +/*244*/ volatile unsigned int blendc; /* Alpha Blend Control */ +/*248*/ volatile unsigned int blendc1; /* Alpha Blend Color 1 */ +/*24c*/ volatile unsigned int blendc2; /* Alpha Blend Color 2 */ +/*250*/ volatile unsigned int fbramitc; /* FB RAM Interleave Test Control */ +/*254*/ volatile unsigned int fbc; /* Frame Buffer Control */ +/*258*/ volatile unsigned int rop; /* Raster OPeration */ +/*25c*/ volatile unsigned int cmp; /* Frame Buffer Compare */ +/*260*/ volatile unsigned int matchab; /* Buffer AB Match Mask */ +/*264*/ volatile unsigned int matchc; /* Buffer C(YZ) Match Mask */ +/*268*/ volatile unsigned int magnab; /* Buffer AB Magnitude Mask */ +/*26c*/ volatile unsigned int magnc; /* Buffer C(YZ) Magnitude Mask */ +/*270*/ volatile unsigned int fbcfg0; /* Frame Buffer Config 0 */ +/*274*/ volatile unsigned int fbcfg1; /* Frame Buffer Config 1 */ +/*278*/ volatile unsigned int fbcfg2; /* Frame Buffer Config 2 */ +/*27c*/ volatile unsigned int fbcfg3; /* Frame Buffer Config 3 */ +/*280*/ volatile unsigned int ppcfg; /* Pixel Processor Config */ +/*284*/ volatile unsigned int pick; /* Picking Control */ +/*288*/ volatile unsigned int fillmode; /* FillMode */ +/*28c*/ volatile unsigned int fbramwac; /* FB RAM Write Address Control */ +/*290*/ volatile unsigned int pmask; /* RGB PlaneMask */ +/*294*/ volatile unsigned int xpmask; /* X PlaneMask */ +/*298*/ volatile unsigned int ypmask; /* Y PlaneMask */ +/*29c*/ volatile unsigned int zpmask; /* Z PlaneMask */ +/*2a0*/ ffb_auxclip auxclip[4]; /* Auxilliary Viewport Clip */ + + /* New 3dRAM III support regs */ +/*2c0*/ volatile unsigned int rawblend2; +/*2c4*/ volatile unsigned int rawpreblend; +/*2c8*/ volatile unsigned int rawstencil; +/*2cc*/ volatile unsigned int rawstencilctl; +/*2d0*/ volatile unsigned int threedram1; +/*2d4*/ volatile unsigned int threedram2; +/*2d8*/ volatile unsigned int passin; +/*2dc*/ volatile unsigned int rawclrdepth; +/*2e0*/ volatile unsigned int rawpmask; +/*2e4*/ volatile unsigned int rawcsrc; +/*2e8*/ volatile unsigned int rawmatch; +/*2ec*/ volatile unsigned int rawmagn; +/*2f0*/ volatile unsigned int rawropblend; +/*2f4*/ volatile unsigned int rawcmp; +/*2f8*/ volatile unsigned int rawwac; +/*2fc*/ volatile unsigned int fbramid; + +/*300*/ volatile unsigned int drawop; /* Draw OPeration */ +/*304*/ unsigned int pad10[2]; /* Reserved */ +/*30c*/ volatile unsigned int lpat; /* Line Pattern control */ +/*310*/ unsigned int pad11; /* Reserved */ +/*314*/ volatile unsigned int fontxy; /* XY Font coordinate */ +/*318*/ volatile unsigned int fontw; /* Font Width */ +/*31c*/ volatile unsigned int fontinc; /* Font Increment */ +/*320*/ volatile unsigned int font; /* Font bits */ +/*324*/ unsigned int pad12[3]; /* Reserved */ +/*330*/ volatile unsigned int blend2; +/*334*/ volatile unsigned int preblend; +/*338*/ volatile unsigned int stencil; +/*33c*/ volatile unsigned int stencilctl; + +/*340*/ unsigned int pad13[4]; /* Reserved */ +/*350*/ volatile unsigned int dcss1; /* Depth Cue Scale Slope 1 */ +/*354*/ volatile unsigned int dcss2; /* Depth Cue Scale Slope 2 */ +/*358*/ volatile unsigned int dcss3; /* Depth Cue Scale Slope 3 */ +/*35c*/ volatile unsigned int widpmask; +/*360*/ volatile unsigned int dcs2; +/*364*/ volatile unsigned int dcs3; +/*368*/ volatile unsigned int dcs4; +/*36c*/ unsigned int pad14; /* Reserved */ +/*370*/ volatile unsigned int dcd2; +/*374*/ volatile unsigned int dcd3; +/*378*/ volatile unsigned int dcd4; +/*37c*/ unsigned int pad15; /* Reserved */ +/*380*/ volatile unsigned int pattern[32]; /* area Pattern */ +/*400*/ unsigned int pad16[8]; /* Reserved */ +/*420*/ volatile unsigned int reset; /* chip RESET */ +/*424*/ unsigned int pad17[247]; /* Reserved */ +/*800*/ volatile unsigned int devid; /* Device ID */ +/*804*/ unsigned int pad18[63]; /* Reserved */ +/*900*/ volatile unsigned int ucsr; /* User Control & Status Register */ +/*904*/ unsigned int pad19[31]; /* Reserved */ +/*980*/ volatile unsigned int mer; /* Mode Enable Register */ +/*984*/ unsigned int pad20[1439]; /* Reserved */ +} ffb_fbc, *ffb_fbcPtr; + +struct ffb_hw_context { + int is_2d_only; + + unsigned int ppc; + unsigned int wid; + unsigned int fg; + unsigned int bg; + unsigned int consty; + unsigned int constz; + unsigned int xclip; + unsigned int dcss; + unsigned int vclipmin; + unsigned int vclipmax; + unsigned int vclipzmin; + unsigned int vclipzmax; + unsigned int dcsf; + unsigned int dcsb; + unsigned int dczf; + unsigned int dczb; + unsigned int blendc; + unsigned int blendc1; + unsigned int blendc2; + unsigned int fbc; + unsigned int rop; + unsigned int cmp; + unsigned int matchab; + unsigned int matchc; + unsigned int magnab; + unsigned int magnc; + unsigned int pmask; + unsigned int xpmask; + unsigned int ypmask; + unsigned int zpmask; + unsigned int auxclip0min; + unsigned int auxclip0max; + unsigned int auxclip1min; + unsigned int auxclip1max; + unsigned int auxclip2min; + unsigned int auxclip2max; + unsigned int auxclip3min; + unsigned int auxclip3max; + unsigned int drawop; + unsigned int lpat; + unsigned int fontxy; + unsigned int fontw; + unsigned int fontinc; + unsigned int area_pattern[32]; + unsigned int ucsr; + unsigned int stencil; + unsigned int stencilctl; + unsigned int dcss1; + unsigned int dcss2; + unsigned int dcss3; + unsigned int dcs2; + unsigned int dcs3; + unsigned int dcs4; + unsigned int dcd2; + unsigned int dcd3; + unsigned int dcd4; + unsigned int mer; +}; + +#define FFB_MAX_CTXS 32 + +enum ffb_chip_type { + ffb1_prototype = 0, /* Early pre-FCS FFB */ + ffb1_standard, /* First FCS FFB, 100Mhz UPA, 66MHz gclk */ + ffb1_speedsort, /* Second FCS FFB, 100Mhz UPA, 75MHz gclk */ + ffb2_prototype, /* Early pre-FCS vertical FFB2 */ + ffb2_vertical, /* First FCS FFB2/vertical, 100Mhz UPA, 100MHZ gclk, + 75(SingleBuffer)/83(DoubleBuffer) MHz fclk */ + ffb2_vertical_plus, /* Second FCS FFB2/vertical, same timings */ + ffb2_horizontal, /* First FCS FFB2/horizontal, same timings as FFB2/vert */ + ffb2_horizontal_plus, /* Second FCS FFB2/horizontal, same timings */ + afb_m3, /* FCS Elite3D, 3 float chips */ + afb_m6 /* FCS Elite3D, 6 float chips */ +}; + +typedef struct ffb_dev_priv { + /* Misc software state. */ + int prom_node; + enum ffb_chip_type ffb_type; + u64 card_phys_base; + struct miscdevice miscdev; + + /* Controller registers. */ + ffb_fbcPtr regs; + + /* Context table. */ + struct ffb_hw_context *hw_state[FFB_MAX_CTXS]; +} ffb_dev_priv_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c --- v2.2.17/drivers/char/drm/fops.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/fops.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,238 @@ +/* fops.c -- File operations for DRM -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * Daryll Strauss + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include + +/* drm_open is called whenever a process opens /dev/drm. */ + +int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev) +{ + kdev_t minor = MINOR(inode->i_rdev); + 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); + + priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); + memset(priv, 0, sizeof(*priv)); + filp->private_data = priv; + priv->uid = current->euid; + priv->pid = current->pid; + priv->minor = minor; + priv->dev = dev; + priv->ioctl_count = 0; + priv->authenticated = capable(CAP_SYS_ADMIN); + + down(&dev->struct_sem); + if (!dev->file_last) { + priv->next = NULL; + priv->prev = NULL; + dev->file_first = priv; + dev->file_last = priv; + } else { + priv->next = NULL; + priv->prev = dev->file_last; + dev->file_last->next = priv; + dev->file_last = priv; + } + up(&dev->struct_sem); + + return 0; +} + +int drm_flush(struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + return 0; +} + +/* drm_release is called whenever a process closes /dev/drm*. Linux calls + this only if any mappings have been closed. */ + +int drm_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (dev->lock.hw_lock + && _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); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + + return 0; +} + +int drm_fasync(int fd, struct file *filp, int on) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode; + + DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device); + retcode = fasync_helper(fd, filp, on, &dev->buf_async); + if (retcode < 0) return retcode; + return 0; +} + + +/* The drm_read and drm_write_string code (especially that which manages + the circular buffer), is based on Alessandro Rubini's LINUX DEVICE + DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */ + +ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int left; + int avail; + int send; + int cur; + + DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp); + + while (dev->buf_rp == dev->buf_wp) { + DRM_DEBUG(" sleeping\n"); + if (filp->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + interruptible_sleep_on(&dev->buf_readers); + if (signal_pending(current)) { + DRM_DEBUG(" interrupted\n"); + return -ERESTARTSYS; + } + DRM_DEBUG(" awake\n"); + } + + left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; + avail = DRM_BSZ - left; + send = DRM_MIN(avail, count); + + while (send) { + if (dev->buf_wp > dev->buf_rp) { + cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp); + } else { + cur = DRM_MIN(send, dev->buf_end - dev->buf_rp); + } + copy_to_user_ret(buf, dev->buf_rp, cur, -EINVAL); + dev->buf_rp += cur; + if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf; + send -= cur; + } + + wake_up_interruptible(&dev->buf_writers); + return DRM_MIN(avail, count);; +} + +int drm_write_string(drm_device_t *dev, const char *s) +{ + int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; + int send = strlen(s); + int count; + + DRM_DEBUG("%d left, %d to send (%p, %p)\n", + left, send, dev->buf_rp, dev->buf_wp); + + if (left == 1 || dev->buf_wp != dev->buf_rp) { + DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n", + left, + dev->buf_wp, + dev->buf_rp); + } + + while (send) { + if (dev->buf_wp >= dev->buf_rp) { + count = DRM_MIN(send, dev->buf_end - dev->buf_wp); + if (count == left) --count; /* Leave a hole */ + } else { + count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1); + } + strncpy(dev->buf_wp, s, count); + dev->buf_wp += count; + if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf; + send -= count; + } + +#if LINUX_VERSION_CODE < 0x020400 + if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); +#else + /* Type of first parameter changed in + Linux 2.4.0-test2... */ + 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; +} + +unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + poll_wait(filp, &dev->buf_readers, wait); + if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM; + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/gamma_dma.c linux/drivers/char/drm/gamma_dma.c --- v2.2.17/drivers/char/drm/gamma_dma.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/gamma_dma.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,824 @@ +/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*- + * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "gamma_drv.h" + +#include /* For task queue support */ + + +/* WARNING!!! MAGIC NUMBER!!! The number of regions already added to the + kernel must be specified here. Currently, the number is 2. This must + match the order the X server uses for instantiating register regions , + or must be passed in a new ioctl. */ +#define GAMMA_REG(reg) \ + (2 \ + + ((reg < 0x1000) \ + ? 0 \ + : ((reg < 0x10000) ? 1 : ((reg < 0x11000) ? 2 : 3)))) + +#define GAMMA_OFF(reg) \ + ((reg < 0x1000) \ + ? reg \ + : ((reg < 0x10000) \ + ? (reg - 0x1000) \ + : ((reg < 0x11000) \ + ? (reg - 0x10000) \ + : (reg - 0x11000)))) + +#define GAMMA_BASE(reg) ((unsigned long)dev->maplist[GAMMA_REG(reg)]->handle) +#define GAMMA_ADDR(reg) (GAMMA_BASE(reg) + GAMMA_OFF(reg)) +#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg) +#define GAMMA_READ(reg) GAMMA_DEREF(reg) +#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0) + +#define GAMMA_BROADCASTMASK 0x9378 +#define GAMMA_COMMANDINTENABLE 0x0c48 +#define GAMMA_DMAADDRESS 0x0028 +#define GAMMA_DMACOUNT 0x0030 +#define GAMMA_FILTERMODE 0x8c00 +#define GAMMA_GCOMMANDINTFLAGS 0x0c50 +#define GAMMA_GCOMMANDMODE 0x0c40 +#define GAMMA_GCOMMANDSTATUS 0x0c60 +#define GAMMA_GDELAYTIMER 0x0c38 +#define GAMMA_GDMACONTROL 0x0060 +#define GAMMA_GINTENABLE 0x0808 +#define GAMMA_GINTFLAGS 0x0810 +#define GAMMA_INFIFOSPACE 0x0018 +#define GAMMA_OUTFIFOWORDS 0x0020 +#define GAMMA_OUTPUTFIFO 0x2000 +#define GAMMA_SYNC 0x8c40 +#define GAMMA_SYNC_TAG 0x0188 + +static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address, + unsigned long length) +{ + GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address)); + while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4) + ; + GAMMA_WRITE(GAMMA_DMACOUNT, length / 4); +} + +static inline void gamma_dma_quiescent_single(drm_device_t *dev) +{ + while (GAMMA_READ(GAMMA_DMACOUNT)) + ; + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3) + ; + + GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10); + GAMMA_WRITE(GAMMA_SYNC, 0); + + do { + while (!GAMMA_READ(GAMMA_OUTFIFOWORDS)) + ; + } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG); +} + +static inline void gamma_dma_quiescent_dual(drm_device_t *dev) +{ + while (GAMMA_READ(GAMMA_DMACOUNT)) + ; + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3) + ; + + GAMMA_WRITE(GAMMA_BROADCASTMASK, 3); + + GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10); + GAMMA_WRITE(GAMMA_SYNC, 0); + + /* Read from first MX */ + do { + while (!GAMMA_READ(GAMMA_OUTFIFOWORDS)) + ; + } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG); + + /* Read from second MX */ + do { + while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000)) + ; + } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG); +} + +static inline void gamma_dma_ready(drm_device_t *dev) +{ + while (GAMMA_READ(GAMMA_DMACOUNT)) + ; +} + +static inline int gamma_dma_is_ready(drm_device_t *dev) +{ + return !GAMMA_READ(GAMMA_DMACOUNT); +} + +static void gamma_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + drm_device_dma_t *dma = dev->dma; + + atomic_inc(&dev->total_irq); + GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */ + GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8); + GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001); + if (gamma_dma_is_ready(dev)) { + /* Free previous buffer */ + if (test_and_set_bit(0, &dev->dma_flag)) { + atomic_inc(&dma->total_missed_free); + return; + } + if (dma->this_buffer) { + drm_free_buffer(dev, dma->this_buffer); + dma->this_buffer = NULL; + } + clear_bit(0, &dev->dma_flag); + + /* Dispatch new buffer */ + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } +} + +/* Only called by gamma_dma_schedule. */ +static int gamma_do_dma(drm_device_t *dev, int locked) +{ + unsigned long address; + unsigned long length; + drm_buf_t *buf; + int retcode = 0; + drm_device_dma_t *dma = dev->dma; +#if DRM_DMA_HISTOGRAM + cycles_t dma_start, dma_stop; +#endif + + if (test_and_set_bit(0, &dev->dma_flag)) { + atomic_inc(&dma->total_missed_dma); + return -EBUSY; + } + +#if DRM_DMA_HISTOGRAM + dma_start = get_cycles(); +#endif + + if (!dma->next_buffer) { + DRM_ERROR("No next_buffer\n"); + clear_bit(0, &dev->dma_flag); + return -EINVAL; + } + + buf = dma->next_buffer; + address = (unsigned long)buf->address; + length = buf->used; + + DRM_DEBUG("context %d, buffer %d (%ld bytes)\n", + buf->context, buf->idx, length); + + if (buf->list == DRM_LIST_RECLAIM) { + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + clear_bit(0, &dev->dma_flag); + return -EINVAL; + } + + if (!length) { + DRM_ERROR("0 length buffer\n"); + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + clear_bit(0, &dev->dma_flag); + return 0; + } + + if (!gamma_dma_is_ready(dev)) { + clear_bit(0, &dev->dma_flag); + return -EBUSY; + } + + if (buf->while_locked) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Dispatching buffer %d from pid %d" + " \"while locked\", but no lock held\n", + buf->idx, buf->pid); + } + } else { + if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + atomic_inc(&dma->total_missed_lock); + clear_bit(0, &dev->dma_flag); + return -EBUSY; + } + } + + if (dev->last_context != buf->context + && !(dev->queuelist[buf->context]->flags + & _DRM_CONTEXT_PRESERVED)) { + /* PRE: dev->last_context != buf->context */ + if (drm_context_switch(dev, dev->last_context, buf->context)) { + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + } + retcode = -EBUSY; + goto cleanup; + + /* POST: we will wait for the context + switch and will dispatch on a later call + when dev->last_context == buf->context. + NOTE WE HOLD THE LOCK THROUGHOUT THIS + TIME! */ + } + + drm_clear_next_buffer(dev); + buf->pending = 1; + buf->waiting = 0; + buf->list = DRM_LIST_PEND; +#if DRM_DMA_HISTOGRAM + buf->time_dispatched = get_cycles(); +#endif + + gamma_dma_dispatch(dev, address, length); + drm_free_buffer(dev, dma->this_buffer); + dma->this_buffer = buf; + + atomic_add(length, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + + if (!buf->while_locked && !dev->context_flag && !locked) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } +cleanup: + + clear_bit(0, &dev->dma_flag); + +#if DRM_DMA_HISTOGRAM + dma_stop = get_cycles(); + atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]); +#endif + + return retcode; +} + +static void gamma_dma_schedule_timer_wrapper(unsigned long dev) +{ + gamma_dma_schedule((drm_device_t *)dev, 0); +} + +static void gamma_dma_schedule_tq_wrapper(void *dev) +{ + gamma_dma_schedule(dev, 0); +} + +int gamma_dma_schedule(drm_device_t *dev, int locked) +{ + int next; + drm_queue_t *q; + drm_buf_t *buf; + int retcode = 0; + int processed = 0; + int missed; + int expire = 20; + drm_device_dma_t *dma = dev->dma; +#if DRM_DMA_HISTOGRAM + cycles_t schedule_start; +#endif + + if (test_and_set_bit(0, &dev->interrupt_flag)) { + /* Not reentrant */ + atomic_inc(&dma->total_missed_sched); + return -EBUSY; + } + missed = atomic_read(&dma->total_missed_sched); + +#if DRM_DMA_HISTOGRAM + schedule_start = get_cycles(); +#endif + +again: + if (dev->context_flag) { + clear_bit(0, &dev->interrupt_flag); + return -EBUSY; + } + if (dma->next_buffer) { + /* Unsent buffer that was previously + selected, but that couldn't be sent + because the lock could not be obtained + or the DMA engine wasn't ready. Try + again. */ + atomic_inc(&dma->total_tried); + if (!(retcode = gamma_do_dma(dev, locked))) { + atomic_inc(&dma->total_hit); + ++processed; + } + } else { + do { + next = drm_select_queue(dev, + gamma_dma_schedule_timer_wrapper); + if (next >= 0) { + q = dev->queuelist[next]; + buf = drm_waitlist_get(&q->waitlist); + dma->next_buffer = buf; + dma->next_queue = q; + if (buf && buf->list == DRM_LIST_RECLAIM) { + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + } + } + } while (next >= 0 && !dma->next_buffer); + if (dma->next_buffer) { + if (!(retcode = gamma_do_dma(dev, locked))) { + ++processed; + } + } + } + + if (--expire) { + if (missed != atomic_read(&dma->total_missed_sched)) { + atomic_inc(&dma->total_lost); + if (gamma_dma_is_ready(dev)) goto again; + } + if (processed && gamma_dma_is_ready(dev)) { + atomic_inc(&dma->total_lost); + processed = 0; + goto again; + } + } + + clear_bit(0, &dev->interrupt_flag); + +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles() + - schedule_start)]); +#endif + return retcode; +} + +static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d) +{ + unsigned long address; + unsigned long length; + int must_free = 0; + int retcode = 0; + int i; + int idx; + drm_buf_t *buf; + drm_buf_t *last_buf = NULL; + drm_device_dma_t *dma = dev->dma; + DECLARE_WAITQUEUE(entry, current); + + /* Turn off interrupt handling */ + while (test_and_set_bit(0, &dev->interrupt_flag)) { + schedule(); + if (signal_pending(current)) return -EINTR; + } + if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) { + while (!drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + schedule(); + if (signal_pending(current)) { + clear_bit(0, &dev->interrupt_flag); + return -EINTR; + } + } + ++must_free; + } + atomic_inc(&dma->total_prio); + + for (i = 0; i < d->send_count; i++) { + idx = d->send_indices[i]; + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + d->send_indices[i], dma->buf_count - 1); + continue; + } + buf = dma->buflist[ idx ]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d using buffer owned by %d\n", + current->pid, buf->pid); + retcode = -EINVAL; + goto cleanup; + } + if (buf->list != DRM_LIST_NONE) { + DRM_ERROR("Process %d using %d's buffer on list %d\n", + current->pid, buf->pid, buf->list); + retcode = -EINVAL; + goto cleanup; + } + /* This isn't a race condition on + buf->list, since our concern is the + buffer reclaim during the time the + process closes the /dev/drm? handle, so + it can't also be doing DMA. */ + buf->list = DRM_LIST_PRIO; + buf->used = d->send_sizes[i]; + buf->context = d->context; + buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED; + address = (unsigned long)buf->address; + length = buf->used; + if (!length) { + DRM_ERROR("0 length buffer\n"); + } + if (buf->pending) { + DRM_ERROR("Sending pending buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + retcode = -EINVAL; + goto cleanup; + } + if (buf->waiting) { + DRM_ERROR("Sending waiting buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + retcode = -EINVAL; + goto cleanup; + } + buf->pending = 1; + + if (dev->last_context != buf->context + && !(dev->queuelist[buf->context]->flags + & _DRM_CONTEXT_PRESERVED)) { + add_wait_queue(&dev->context_wait, &entry); + current->state = TASK_INTERRUPTIBLE; + /* PRE: dev->last_context != buf->context */ + drm_context_switch(dev, dev->last_context, + buf->context); + /* POST: we will wait for the context + switch and will dispatch on a later call + when dev->last_context == buf->context. + NOTE WE HOLD THE LOCK THROUGHOUT THIS + TIME! */ + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->context_wait, &entry); + if (signal_pending(current)) { + retcode = -EINTR; + goto cleanup; + } + if (dev->last_context != buf->context) { + DRM_ERROR("Context mismatch: %d %d\n", + dev->last_context, + buf->context); + } + } + +#if DRM_DMA_HISTOGRAM + buf->time_queued = get_cycles(); + buf->time_dispatched = buf->time_queued; +#endif + gamma_dma_dispatch(dev, address, length); + atomic_add(length, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + + if (last_buf) { + drm_free_buffer(dev, last_buf); + } + last_buf = buf; + } + + +cleanup: + if (last_buf) { + gamma_dma_ready(dev); + drm_free_buffer(dev, last_buf); + } + + if (must_free && !dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } + clear_bit(0, &dev->interrupt_flag); + return retcode; +} + +static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) +{ + DECLARE_WAITQUEUE(entry, current); + drm_buf_t *last_buf = NULL; + int retcode = 0; + drm_device_dma_t *dma = dev->dma; + + if (d->flags & _DRM_DMA_BLOCK) { + last_buf = dma->buflist[d->send_indices[d->send_count-1]]; + add_wait_queue(&last_buf->dma_wait, &entry); + } + + if ((retcode = drm_dma_enqueue(dev, d))) { + if (d->flags & _DRM_DMA_BLOCK) + remove_wait_queue(&last_buf->dma_wait, &entry); + return retcode; + } + + gamma_dma_schedule(dev, 0); + + if (d->flags & _DRM_DMA_BLOCK) { + DRM_DEBUG("%d waiting\n", current->pid); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!last_buf->waiting + && !last_buf->pending) + break; /* finished */ + schedule(); + if (signal_pending(current)) { + retcode = -EINTR; /* Can't restart */ + break; + } + } + current->state = TASK_RUNNING; + DRM_DEBUG("%d running\n", current->pid); + remove_wait_queue(&last_buf->dma_wait, &entry); + if (!retcode + || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) { + if (!waitqueue_active(&last_buf->dma_wait)) { + drm_free_buffer(dev, last_buf); + } + } + if (retcode) { + DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n", + d->context, + last_buf->waiting, + last_buf->pending, + DRM_WAITCOUNT(dev, d->context), + last_buf->idx, + last_buf->list, + last_buf->pid, + current->pid); + } + } + return retcode; +} + +int gamma_dma(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_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_dma_t d; + + copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) { + DRM_ERROR("Process %d using context %d\n", + current->pid, d.context); + return -EINVAL; + } + if (d.send_count < 0 || d.send_count > dma->buf_count) { + DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", + current->pid, d.send_count, dma->buf_count); + return -EINVAL; + } + if (d.request_count < 0 || d.request_count > dma->buf_count) { + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count); + return -EINVAL; + } + + if (d.send_count) { + if (d.flags & _DRM_DMA_PRIORITY) + retcode = gamma_dma_priority(dev, &d); + else + retcode = gamma_dma_send_buffers(dev, &d); + } + + d.granted_count = 0; + + if (!retcode && d.request_count) { + retcode = drm_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, d.granted_count); + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + + return retcode; +} + +int gamma_irq_install(drm_device_t *dev, int irq) +{ + int retcode; + + if (!irq) return -EINVAL; + + down(&dev->struct_sem); + if (dev->irq) { + up(&dev->struct_sem); + return -EBUSY; + } + dev->irq = irq; + up(&dev->struct_sem); + + DRM_DEBUG("%d\n", irq); + + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + + dev->dma->next_buffer = NULL; + dev->dma->next_queue = NULL; + dev->dma->this_buffer = NULL; + + dev->tq.next = NULL; + dev->tq.sync = 0; + dev->tq.routine = gamma_dma_schedule_tq_wrapper; + dev->tq.data = dev; + + + /* Before installing handler */ + GAMMA_WRITE(GAMMA_GCOMMANDMODE, 0); + GAMMA_WRITE(GAMMA_GDMACONTROL, 0); + + /* Install handler */ + if ((retcode = request_irq(dev->irq, + gamma_dma_service, + 0, + dev->devname, + dev))) { + down(&dev->struct_sem); + dev->irq = 0; + up(&dev->struct_sem); + return retcode; + } + + /* After installing handler */ + GAMMA_WRITE(GAMMA_GINTENABLE, 0x2001); + GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0x0008); + GAMMA_WRITE(GAMMA_GDELAYTIMER, 0x39090); + + return 0; +} + +int gamma_irq_uninstall(drm_device_t *dev) +{ + int irq; + + down(&dev->struct_sem); + irq = dev->irq; + dev->irq = 0; + up(&dev->struct_sem); + + if (!irq) return -EINVAL; + + DRM_DEBUG("%d\n", irq); + + GAMMA_WRITE(GAMMA_GDELAYTIMER, 0); + GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0); + GAMMA_WRITE(GAMMA_GINTENABLE, 0); + free_irq(irq, dev); + + return 0; +} + + +int gamma_control(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_control_t ctl; + int retcode; + + copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); + + switch (ctl.func) { + case DRM_INST_HANDLER: + if ((retcode = gamma_irq_install(dev, ctl.irq))) + return retcode; + break; + case DRM_UNINST_HANDLER: + if ((retcode = gamma_irq_uninstall(dev))) + return retcode; + break; + default: + return -EINVAL; + } + return 0; +} + +int gamma_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; + drm_queue_t *q; +#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 (lock.context < 0 || lock.context >= dev->queue_count) + return -EINVAL; + q = dev->queuelist[lock.context]; + + ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); + + if (!ret) { + if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) + != lock.context) { + long j = jiffies - dev->lock.lock_time; + + if (j > 0 && j <= DRM_LOCK_SLICE) { + /* Can't take lock if we just had it and + there is contention. */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(j); + } + } + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + 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); + atomic_inc(&q->total_locks); + break; /* Got lock */ + } + + /* Contention */ + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + + drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */ + + if (!ret) { + if (lock.flags & _DRM_LOCK_READY) + gamma_dma_ready(dev); + if (lock.flags & _DRM_LOCK_QUIESCENT) { + if (gamma_found() == 1) { + gamma_dma_quiescent_single(dev); + } else { + gamma_dma_quiescent_dual(dev); + } + } + } + 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; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c --- v2.2.17/drivers/char/drm/gamma_drv.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/gamma_drv.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,575 @@ +/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#include +#include "drmP.h" +#include "gamma_drv.h" + +#include + +static void __attribute__((unused)) unused(void) +{ + agp_enable(0); +} + +#ifndef PCI_DEVICE_ID_3DLABS_GAMMA +#define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008 +#endif +#ifndef PCI_DEVICE_ID_3DLABS_MX +#define PCI_DEVICE_ID_3DLABS_MX 0x0006 +#endif + +#define GAMMA_NAME "gamma" +#define GAMMA_DESC "3dlabs GMX 2000" +#define GAMMA_DATE "20000719" +#define GAMMA_MAJOR 1 +#define GAMMA_MINOR 0 +#define GAMMA_PATCHLEVEL 0 + +static drm_device_t gamma_device; + +static struct file_operations gamma_fops = { +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ + owner: THIS_MODULE, +#endif + open: gamma_open, + flush: drm_flush, + release: gamma_release, + ioctl: gamma_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +static struct miscdevice gamma_misc = { + minor: MISC_DYNAMIC_MINOR, + name: GAMMA_NAME, + fops: &gamma_fops, +}; + +static drm_ioctl_desc_t gamma_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { gamma_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_CONTROL)] = { gamma_control, 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_BUFS)] = { drm_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_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_DMA)] = { gamma_dma, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { gamma_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { gamma_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +}; +#define GAMMA_IOCTL_COUNT DRM_ARRAY_SIZE(gamma_ioctls) + +#ifdef MODULE +static char *gamma = NULL; +#endif +static int devices = 0; + +MODULE_AUTHOR("VA Linux Systems, Inc."); +MODULE_DESCRIPTION("3dlabs GMX 2000"); +MODULE_PARM(gamma, "s"); +MODULE_PARM(devices, "i"); +MODULE_PARM_DESC(devices, + "devices=x, where x is the number of MX chips on card\n"); +#ifndef MODULE +/* gamma_options 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 gamma_options(char *str) +{ + drm_parse_options(str); + return 1; +} + +__setup("gamma=", gamma_options); +#endif + +static int gamma_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); + + drm_dma_setup(dev); + + 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_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); +#if DRM_DMA_HISTO + memset(&dev->histo, 0, sizeof(dev->histo)); +#endif + 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); + + 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 gamma_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"); + + if (dev->irq) gamma_irq_uninstall(dev); + + 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; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + 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->queuelist) { + for (i = 0; i < dev->queue_count; i++) { + drm_waitlist_destroy(&dev->queuelist[i]->waitlist); + if (dev->queuelist[i]) { + drm_free(dev->queuelist[i], + sizeof(*dev->queuelist[0]), + DRM_MEM_QUEUES); + dev->queuelist[i] = NULL; + } + } + drm_free(dev->queuelist, + dev->queue_slots * sizeof(*dev->queuelist), + DRM_MEM_QUEUES); + dev->queuelist = NULL; + } + + drm_dma_takedown(dev); + + dev->queue_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; +} + +int gamma_found(void) +{ + return devices; +} + +int gamma_find_devices(void) +{ + struct pci_dev *d = NULL, *one = NULL, *two = NULL; + + d = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_GAMMA,d); + if (!d) return 0; + + one = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,d); + if (!one) return 0; + + /* Make sure it's on the same card, if not - no MX's found */ + if (PCI_SLOT(d->devfn) != PCI_SLOT(one->devfn)) return 0; + + two = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,one); + if (!two) return 1; + + /* Make sure it's on the same card, if not - only 1 MX found */ + if (PCI_SLOT(d->devfn) != PCI_SLOT(two->devfn)) return 1; + + /* Two MX's found - we don't currently support more than 2 */ + return 2; +} + +/* gamma_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +static int gamma_init(void) +{ + int retcode; + drm_device_t *dev = &gamma_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(gamma); +#endif + devices = gamma_find_devices(); + if (devices == 0) return -1; + + if ((retcode = misc_register(&gamma_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", GAMMA_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, gamma_misc.minor); + dev->name = GAMMA_NAME; + + drm_mem_init(); + drm_proc_init(dev); + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d with %d MX devices\n", + GAMMA_NAME, + GAMMA_MAJOR, + GAMMA_MINOR, + GAMMA_PATCHLEVEL, + GAMMA_DATE, + gamma_misc.minor, + devices); + + return 0; +} + +/* gamma_cleanup is called via cleanup_module at module unload time. */ + +static void gamma_cleanup(void) +{ + drm_device_t *dev = &gamma_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&gamma_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + gamma_takedown(dev); +} + +module_init(gamma_init); +module_exit(gamma_cleanup); + + +int gamma_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 = GAMMA_MAJOR; + version.version_minor = GAMMA_MINOR; + version.version_patchlevel = GAMMA_PATCHLEVEL; + + DRM_COPY(version.name, GAMMA_NAME); + DRM_COPY(version.date, GAMMA_DATE); + DRM_COPY(version.desc, GAMMA_DESC); + + copy_to_user_ret((drm_version_t *)arg, + &version, + sizeof(version), + -EFAULT); + return 0; +} + +int gamma_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &gamma_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return gamma_setup(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +int gamma_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + int retcode = 0; + + lock_kernel(); + dev = priv->dev; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_release(inode, filp))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + 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); + unlock_kernel(); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return gamma_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + unlock_kernel(); + return retcode; +} + +/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int gamma_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 >= GAMMA_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &gamma_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 gamma_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); + gamma_dma_schedule(dev, 1); + if (!dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles() + - dev->lck_start)]); +#endif + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/gamma_drv.h linux/drivers/char/drm/gamma_drv.h --- v2.2.17/drivers/char/drm/gamma_drv.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/gamma_drv.h Fri Sep 1 14:12:33 2000 @@ -0,0 +1,58 @@ +/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#ifndef _GAMMA_DRV_H_ +#define _GAMMA_DRV_H_ + + /* gamma_drv.c */ +extern int gamma_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_open(struct inode *inode, struct file *filp); +extern int gamma_release(struct inode *inode, struct file *filp); +extern int gamma_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* gamma_dma.c */ +extern int gamma_dma_schedule(drm_device_t *dev, int locked); +extern int gamma_dma(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_irq_install(drm_device_t *dev, int irq); +extern int gamma_irq_uninstall(drm_device_t *dev); +extern int gamma_control(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_find_devices(void); +extern int gamma_found(void); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/i810_bufs.c linux/drivers/char/drm/i810_bufs.c --- v2.2.17/drivers/char/drm/i810_bufs.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/i810_bufs.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,334 @@ +/* i810_bufs.c -- IOCTLs to manage buffers -*- linux-c -*- + * Created: Thu Jan 6 01:47:26 2000 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "i810_drv.h" +#include "linux/un.h" + +int i810_addbufs_agp(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + agp_offset = request.agp_start; + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + byte_count = 0; + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; + + while(entry->buf_count < count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = offset; + buf->bus_address = dev->agp->base + agp_offset + offset; + buf->address = (void *)(agp_offset + offset + dev->agp->base); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_private = drm_alloc(sizeof(drm_i810_buf_priv_t), + DRM_MEM_BUFS); + buf->dev_priv_size = sizeof(drm_i810_buf_priv_t); + memset(buf->dev_private, 0, sizeof(drm_i810_buf_priv_t)); + +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + offset = offset + alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); + + atomic_dec(&dev->buf_alloc); + dma->flags = _DRM_DMA_USE_AGP; + return 0; +} + +int i810_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_buf_desc_t request; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + if(request.flags & _DRM_AGP_BUFFER) + return i810_addbufs_agp(inode, filp, cmd, arg); + else + return -EINVAL; +} + +int i810_infobufs(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_device_dma_t *dma = dev->dma; + drm_buf_info_t request; + int i; + int count; + + if (!dma) return -EINVAL; + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_info_t *)arg, + sizeof(request), + -EFAULT); + + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) ++count; + } + + DRM_DEBUG("count = %d\n", count); + + if (request.count >= count) { + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) { + copy_to_user_ret(&request.list[count].count, + &dma->bufs[i].buf_count, + sizeof(dma->bufs[0] + .buf_count), + -EFAULT); + copy_to_user_ret(&request.list[count].size, + &dma->bufs[i].buf_size, + sizeof(dma->bufs[0].buf_size), + -EFAULT); + copy_to_user_ret(&request.list[count].low_mark, + &dma->bufs[i] + .freelist.low_mark, + sizeof(dma->bufs[0] + .freelist.low_mark), + -EFAULT); + copy_to_user_ret(&request.list[count] + .high_mark, + &dma->bufs[i] + .freelist.high_mark, + sizeof(dma->bufs[0] + .freelist.high_mark), + -EFAULT); + DRM_DEBUG("%d %d %d %d %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].buf_size, + dma->bufs[i].freelist.low_mark, + dma->bufs[i].freelist.high_mark); + ++count; + } + } + } + request.count = count; + + copy_to_user_ret((drm_buf_info_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return 0; +} + +int i810_markbufs(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + int order; + drm_buf_entry_t *entry; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d, %d, %d\n", + request.size, request.low_mark, request.high_mark); + order = drm_order(request.size); + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + entry = &dma->bufs[order]; + + if (request.low_mark < 0 || request.low_mark > entry->buf_count) + return -EINVAL; + if (request.high_mark < 0 || request.high_mark > entry->buf_count) + return -EINVAL; + + entry->freelist.low_mark = request.low_mark; + entry->freelist.high_mark = request.high_mark; + + return 0; +} + +int i810_freebufs(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_device_dma_t *dma = dev->dma; + drm_buf_free_t request; + int i; + int idx; + drm_buf_t *buf; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_free_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d\n", request.count); + for (i = 0; i < request.count; i++) { + copy_from_user_ret(&idx, + &request.list[i], + sizeof(idx), + -EFAULT); + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + idx, dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[idx]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d freeing buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + drm_free_buffer(dev, buf); + } + + return 0; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/i810_context.c linux/drivers/char/drm/i810_context.c --- v2.2.17/drivers/char/drm/i810_context.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/i810_context.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,203 @@ +/* i810_context.c -- IOCTLs for i810 contexts -*- linux-c -*- + * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "i810_drv.h" + +static int i810_alloc_queue(drm_device_t *dev) +{ + int temp = drm_ctxbitmap_next(dev); + DRM_DEBUG("i810_alloc_queue: %d\n", temp); + return temp; +} + +int i810_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) { + i810_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int i810_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 i810_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 i810_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 = i810_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = i810_alloc_queue(dev); + } + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + DRM_DEBUG("%d\n", ctx.handle); + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int i810_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + /* This does nothing for the i810 */ + return 0; +} + +int i810_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 i810_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 i810_context_switch(dev, dev->last_context, ctx.handle); +} + +int i810_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); + i810_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int i810_rmctx(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); + if(ctx.handle != DRM_KERNEL_CONTEXT) { + drm_ctxbitmap_free(dev, ctx.handle); + } + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c --- v2.2.17/drivers/char/drm/i810_dma.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/i810_dma.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,1417 @@ +/* i810_dma.c -- DMA support for the i810 -*- linux-c -*- + * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * Keith Whitwell + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "i810_drv.h" +#include /* For task queue support */ + +/* in case we don't have a 2.3.99-pre6 kernel or later: */ +#ifndef VM_DONTCOPY +#define VM_DONTCOPY 0 +#endif + +#define I810_BUF_FREE 2 +#define I810_BUF_CLIENT 1 +#define I810_BUF_HARDWARE 0 + +#define I810_BUF_UNMAPPED 0 +#define I810_BUF_MAPPED 1 + +#define I810_REG(reg) 2 +#define I810_BASE(reg) ((unsigned long) \ + dev->maplist[I810_REG(reg)]->handle) +#define I810_ADDR(reg) (I810_BASE(reg) + reg) +#define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg) +#define I810_READ(reg) I810_DEREF(reg) +#define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0) +#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg) +#define I810_READ16(reg) I810_DEREF16(reg) +#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) + +#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i810_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + dev_priv->ring.tail = outring; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +#define OUT_RING(n) do { \ + if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0); + +static inline void i810_print_status_page(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = dev->dev_private; + u32 *temp = (u32 *)dev_priv->hw_status_page; + int i; + + DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); + DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); + DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); + DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); + for(i = 6; i < dma->buf_count + 6; i++) { + DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]); + } +} + +static drm_buf_t *i810_freelist_get(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i; + int used; + + /* Linear search might not be the best solution */ + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, + I810_BUF_CLIENT); + if(used == I810_BUF_FREE) { + return buf; + } + } + return NULL; +} + +/* This should only be called if the buffer is not sent to the hardware + * yet, the hardware updates in use for us once its on the ring buffer. + */ + +static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) +{ + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + int used; + + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); + if(used != I810_BUF_CLIENT) { + DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); + return -EINVAL; + } + + return 0; +} + +static struct file_operations i810_buffer_fops = { + open: i810_open, + flush: drm_flush, + release: i810_release, + ioctl: i810_ioctl, + mmap: i810_mmap_buffers, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + drm_i810_private_t *dev_priv; + drm_buf_t *buf; + drm_i810_buf_priv_t *buf_priv; + + lock_kernel(); + dev = priv->dev; + dev_priv = dev->dev_private; + buf = dev_priv->mmap_buffer; + buf_priv = buf->dev_private; + + vma->vm_flags |= (VM_IO | VM_DONTCOPY); + vma->vm_file = filp; + + buf_priv->currently_mapped = I810_BUF_MAPPED; + unlock_kernel(); + + if (remap_page_range(vma->vm_start, + VM_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) return -EAGAIN; + return 0; +} + +static int i810_map_buffer(drm_buf_t *buf, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_i810_private_t *dev_priv = dev->dev_private; + struct file_operations *old_fops; + int retcode = 0; + + if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL; + + if(VM_DONTCOPY != 0) { + down(¤t->mm->mmap_sem); + old_fops = filp->f_op; + filp->f_op = &i810_buffer_fops; + dev_priv->mmap_buffer = buf; + buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, + PROT_READ|PROT_WRITE, + MAP_SHARED, + buf->bus_address); + dev_priv->mmap_buffer = NULL; + filp->f_op = old_fops; + if ((unsigned long)buf_priv->virtual > -1024UL) { + /* Real error */ + DRM_DEBUG("mmap error\n"); + retcode = (signed int)buf_priv->virtual; + buf_priv->virtual = 0; + } + up(¤t->mm->mmap_sem); + } else { + buf_priv->virtual = buf_priv->kernel_virtual; + buf_priv->currently_mapped = I810_BUF_MAPPED; + } + return retcode; +} + +static int i810_unmap_buffer(drm_buf_t *buf) +{ + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + int retcode = 0; + + if(VM_DONTCOPY != 0) { + if(buf_priv->currently_mapped != I810_BUF_MAPPED) + return -EINVAL; + down(¤t->mm->mmap_sem); +#if LINUX_VERSION_CODE < 0x020399 + retcode = do_munmap((unsigned long)buf_priv->virtual, + (size_t) buf->total); +#else + retcode = do_munmap(current->mm, + (unsigned long)buf_priv->virtual, + (size_t) buf->total); +#endif + up(¤t->mm->mmap_sem); + } + buf_priv->currently_mapped = I810_BUF_UNMAPPED; + buf_priv->virtual = 0; + + return retcode; +} + +static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d, + struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_buf_t *buf; + drm_i810_buf_priv_t *buf_priv; + int retcode = 0; + + buf = i810_freelist_get(dev); + if (!buf) { + retcode = -ENOMEM; + DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode); + goto out_get_buf; + } + + retcode = i810_map_buffer(buf, filp); + if(retcode) { + i810_freelist_put(dev, buf); + DRM_DEBUG("mapbuf failed in %s retcode %d\n", + __FUNCTION__, retcode); + goto out_get_buf; + } + buf->pid = priv->pid; + buf_priv = buf->dev_private; + d->granted = 1; + d->request_idx = buf->idx; + d->request_size = buf->total; + d->virtual = buf_priv->virtual; + +out_get_buf: + return retcode; +} + +static unsigned long i810_alloc_page(drm_device_t *dev) +{ + unsigned long address; + + address = __get_free_page(GFP_KERNEL); + if(address == 0UL) + return 0; + + atomic_inc(&virt_to_page(address)->count); + set_bit(PG_locked, &virt_to_page(address)->flags); + + return address; +} + +static void i810_free_page(drm_device_t *dev, unsigned long page) +{ + if(page == 0UL) + return; + + atomic_dec(&virt_to_page(page)->count); + clear_bit(PG_locked, &virt_to_page(page)->flags); + wake_up(&virt_to_page(page)->wait); + free_page(page); + return; +} + +static int i810_dma_cleanup(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + + if(dev->dev_private) { + int i; + drm_i810_private_t *dev_priv = + (drm_i810_private_t *) dev->dev_private; + + if(dev_priv->ring.virtual_start) { + drm_ioremapfree((void *) dev_priv->ring.virtual_start, + dev_priv->ring.Size); + } + if(dev_priv->hw_status_page != 0UL) { + i810_free_page(dev, dev_priv->hw_status_page); + /* Need to rewrite hardware status page */ + I810_WRITE(0x02080, 0x1ffff000); + } + drm_free(dev->dev_private, sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_ioremapfree(buf_priv->kernel_virtual, buf->total); + } + } + return 0; +} + +static int i810_wait_ring(drm_device_t *dev, int n) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + int iters = 0; + unsigned long end; + unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + + end = jiffies + (HZ*3); + while (ring->space < n) { + int i; + + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; + + if (ring->head != last_head) + end = jiffies + (HZ*3); + + iters++; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("space: %d wanted %d\n", ring->space, n); + DRM_ERROR("lockup\n"); + goto out_wait_ring; + } + + for (i = 0 ; i < 2000 ; i++) ; + } + +out_wait_ring: + return iters; +} + +static void i810_kernel_lost_context(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_ring_buffer_t *ring = &(dev_priv->ring); + + ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I810_READ(LP_RING + RING_TAIL); + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; +} + +static int i810_freelist_init(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + int my_idx = 24; + u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx); + int i; + + if(dma->buf_count > 1019) { + /* Not enough space in the status page for the freelist */ + return -EINVAL; + } + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + buf_priv->in_use = hw_status++; + buf_priv->my_use_idx = my_idx; + my_idx += 4; + + *buf_priv->in_use = I810_BUF_FREE; + + buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, + buf->total); + } + return 0; +} + +static int i810_dma_initialize(drm_device_t *dev, + drm_i810_private_t *dev_priv, + drm_i810_init_t *init) +{ + drm_map_t *sarea_map; + + dev->dev_private = (void *) dev_priv; + memset(dev_priv, 0, sizeof(drm_i810_private_t)); + + if (init->ring_map_idx >= dev->map_count || + init->buffer_map_idx >= dev->map_count) { + i810_dma_cleanup(dev); + DRM_ERROR("ring_map or buffer_map are invalid\n"); + return -EINVAL; + } + + dev_priv->ring_map_idx = init->ring_map_idx; + dev_priv->buffer_map_idx = init->buffer_map_idx; + sarea_map = dev->maplist[0]; + dev_priv->sarea_priv = (drm_i810_sarea_t *) + ((u8 *)sarea_map->handle + + init->sarea_priv_offset); + + atomic_set(&dev_priv->flush_done, 0); + init_waitqueue_head(&dev_priv->flush_queue); + + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; + + dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + + init->ring_start, + init->ring_size); + + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + if (dev_priv->ring.virtual_start == NULL) { + i810_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; + } + + dev_priv->w = init->w; + dev_priv->h = init->h; + dev_priv->pitch = init->pitch; + dev_priv->back_offset = init->back_offset; + dev_priv->depth_offset = init->depth_offset; + + dev_priv->front_di1 = init->front_offset | init->pitch_bits; + dev_priv->back_di1 = init->back_offset | init->pitch_bits; + dev_priv->zi1 = init->depth_offset | init->pitch_bits; + + + /* Program Hardware Status Page */ + dev_priv->hw_status_page = i810_alloc_page(dev); + memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); + if(dev_priv->hw_status_page == 0UL) { + i810_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return -ENOMEM; + } + DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); + + I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page)); + DRM_DEBUG("Enabled hardware status page\n"); + + /* Now we need to init our freelist */ + if(i810_freelist_init(dev) != 0) { + i810_dma_cleanup(dev); + DRM_ERROR("Not enough space in the status page for" + " the freelist\n"); + return -ENOMEM; + } + return 0; +} + +int i810_dma_init(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_i810_private_t *dev_priv; + drm_i810_init_t init; + int retcode = 0; + + copy_from_user_ret(&init, (drm_i810_init_t *)arg, + sizeof(init), -EFAULT); + + switch(init.func) { + case I810_INIT_DMA: + dev_priv = drm_alloc(sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + retcode = i810_dma_initialize(dev, dev_priv, &init); + break; + case I810_CLEANUP_DMA: + retcode = i810_dma_cleanup(dev); + break; + default: + retcode = -EINVAL; + break; + } + + return retcode; +} + + + +/* Most efficient way to verify state for the i810 is as it is + * emitted. Non-conformant state is silently dropped. + * + * Use 'volatile' & local var tmp to force the emitted values to be + * identical to the verified ones. + */ +static void i810EmitContextVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + int i, j = 0; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I810_CTX_SETUP_SIZE ); + + OUT_RING( GFX_OP_COLOR_FACTOR ); + OUT_RING( code[I810_CTXREG_CF1] ); + + OUT_RING( GFX_OP_STIPPLE ); + OUT_RING( code[I810_CTXREG_ST1] ); + + for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) { + tmp = code[i]; + + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) + { + OUT_RING( tmp ); + j++; + } + } + + if (j & 1) + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + +static void i810EmitTexVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + int i, j = 0; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I810_TEX_SETUP_SIZE ); + + OUT_RING( GFX_OP_MAP_INFO ); + OUT_RING( code[I810_TEXREG_MI1] ); + OUT_RING( code[I810_TEXREG_MI2] ); + OUT_RING( code[I810_TEXREG_MI3] ); + + for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) { + tmp = code[i]; + + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) + { + OUT_RING( tmp ); + j++; + } + } + + if (j & 1) + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + + +/* Need to do some additional checking when setting the dest buffer. + */ +static void i810EmitDestVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 ); + + tmp = code[I810_DESTREG_DI1]; + if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) { + OUT_RING( CMD_OP_DESTBUFFER_INFO ); + OUT_RING( tmp ); + } else + DRM_DEBUG("bad di1 %x (allow %x or %x)\n", + tmp, dev_priv->front_di1, dev_priv->back_di1); + + /* invarient: + */ + OUT_RING( CMD_OP_Z_BUFFER_INFO ); + OUT_RING( dev_priv->zi1 ); + + OUT_RING( GFX_OP_DESTBUFFER_VARS ); + OUT_RING( code[I810_DESTREG_DV1] ); + + OUT_RING( GFX_OP_DRAWRECT_INFO ); + OUT_RING( code[I810_DESTREG_DR1] ); + OUT_RING( code[I810_DESTREG_DR2] ); + OUT_RING( code[I810_DESTREG_DR3] ); + OUT_RING( code[I810_DESTREG_DR4] ); + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + + + +static void i810EmitState( drm_device_t *dev ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + + if (dirty & I810_UPLOAD_BUFFERS) { + i810EmitDestVerified( dev, sarea_priv->BufferState ); + sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS; + } + + if (dirty & I810_UPLOAD_CTX) { + i810EmitContextVerified( dev, sarea_priv->ContextState ); + sarea_priv->dirty &= ~I810_UPLOAD_CTX; + } + + if (dirty & I810_UPLOAD_TEX0) { + i810EmitTexVerified( dev, sarea_priv->TexState[0] ); + sarea_priv->dirty &= ~I810_UPLOAD_TEX0; + } + + if (dirty & I810_UPLOAD_TEX1) { + i810EmitTexVerified( dev, sarea_priv->TexState[1] ); + sarea_priv->dirty &= ~I810_UPLOAD_TEX1; + } +} + + + +/* need to verify + */ +static void i810_dma_dispatch_clear( drm_device_t *dev, int flags, + unsigned int clear_color, + unsigned int clear_zval ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int pitch = dev_priv->pitch; + int cpp = 2; + int i; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + for (i = 0 ; i < nbox ; i++, pbox++) { + unsigned int x = pbox->x1; + unsigned int y = pbox->y1; + unsigned int width = (pbox->x2 - x) * cpp; + unsigned int height = pbox->y2 - y; + unsigned int start = y * pitch + x * cpp; + + if (pbox->x1 > pbox->x2 || + pbox->y1 > pbox->y2 || + pbox->x2 > dev_priv->w || + pbox->y2 > dev_priv->h) + continue; + + if ( flags & I810_FRONT ) { + DRM_DEBUG("clear front\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | + BR00_OP_COLOR_BLT | 0x3 ); + OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); + OUT_RING( (height << 16) | width ); + OUT_RING( start ); + OUT_RING( clear_color ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + } + + if ( flags & I810_BACK ) { + DRM_DEBUG("clear back\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | + BR00_OP_COLOR_BLT | 0x3 ); + OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); + OUT_RING( (height << 16) | width ); + OUT_RING( dev_priv->back_offset + start ); + OUT_RING( clear_color ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + } + + if ( flags & I810_DEPTH ) { + DRM_DEBUG("clear depth\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | + BR00_OP_COLOR_BLT | 0x3 ); + OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); + OUT_RING( (height << 16) | width ); + OUT_RING( dev_priv->depth_offset + start ); + OUT_RING( clear_zval ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + } + } +} + +static void i810_dma_dispatch_swap( drm_device_t *dev ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int pitch = dev_priv->pitch; + int cpp = 2; + int ofs = dev_priv->back_offset; + int i; + RING_LOCALS; + + DRM_DEBUG("swapbuffers\n"); + + i810_kernel_lost_context(dev); + + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + for (i = 0 ; i < nbox; i++, pbox++) + { + unsigned int w = pbox->x2 - pbox->x1; + unsigned int h = pbox->y2 - pbox->y1; + unsigned int dst = pbox->x1*cpp + pbox->y1*pitch; + unsigned int start = ofs + dst; + + if (pbox->x1 > pbox->x2 || + pbox->y1 > pbox->y2 || + pbox->x2 > dev_priv->w || + pbox->y2 > dev_priv->h) + continue; + + DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", + pbox[i].x1, pbox[i].y1, + pbox[i].x2, pbox[i].y2); + + BEGIN_LP_RING( 6 ); + OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); + OUT_RING( pitch | (0xCC << 16)); + OUT_RING( (h << 16) | (w * cpp)); + OUT_RING( dst ); + OUT_RING( pitch ); + OUT_RING( start ); + ADVANCE_LP_RING(); + } +} + + +static void i810_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf, + int discard, + int used) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_clip_rect_t *box = sarea_priv->boxes; + int nbox = sarea_priv->nbox; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + int i = 0, u; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + if (nbox > I810_NR_SAREA_CLIPRECTS) + nbox = I810_NR_SAREA_CLIPRECTS; + + if (discard) { + u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, + I810_BUF_HARDWARE); + if(u != I810_BUF_CLIENT) { + DRM_DEBUG("xxxx 2\n"); + } + } + + if (used > 4*1024) + used = 0; + + if (sarea_priv->dirty) + i810EmitState( dev ); + + DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", + address, used, nbox); + + dev_priv->counter++; + DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG( "i810_dma_dispatch\n"); + DRM_DEBUG( "start : %lx\n", start); + DRM_DEBUG( "used : %d\n", used); + DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); + + if (buf_priv->currently_mapped == I810_BUF_MAPPED) { + *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE | + sarea_priv->vertex_prim | + ((used/4)-2)); + + if (used & 4) { + *(u32 *)((u32)buf_priv->virtual + used) = 0; + used += 4; + } + + i810_unmap_buffer(buf); + } + + if (used) { + do { + if (i < nbox) { + BEGIN_LP_RING(4); + OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | + SC_ENABLE ); + OUT_RING( GFX_OP_SCISSOR_INFO ); + OUT_RING( box[i].x1 | (box[i].y1<<16) ); + OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) ); + ADVANCE_LP_RING(); + } + + BEGIN_LP_RING(4); + OUT_RING( CMD_OP_BATCH_BUFFER ); + OUT_RING( start | BB1_PROTECTED ); + OUT_RING( start + used - 4 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + } while (++i < nbox); + } + + BEGIN_LP_RING(10); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 20 ); + OUT_RING( dev_priv->counter ); + OUT_RING( 0 ); + + if (discard) { + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I810_BUF_FREE ); + OUT_RING( 0 ); + } + + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} + + +/* Interrupts are only for flushing */ +static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + u16 temp; + + atomic_inc(&dev->total_irq); + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + else + return; + + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static void i810_dma_task_queue(void *device) +{ + drm_device_t *dev = (drm_device_t *) device; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + + atomic_set(&dev_priv->flush_done, 1); + wake_up_interruptible(&dev_priv->flush_queue); +} + +int i810_irq_install(drm_device_t *dev, int irq) +{ + int retcode; + u16 temp; + + if (!irq) return -EINVAL; + + down(&dev->struct_sem); + if (dev->irq) { + up(&dev->struct_sem); + return -EBUSY; + } + dev->irq = irq; + up(&dev->struct_sem); + + DRM_DEBUG( "Interrupt Install : %d\n", irq); + DRM_DEBUG("%d\n", irq); + + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + + dev->dma->next_buffer = NULL; + dev->dma->next_queue = NULL; + dev->dma->this_buffer = NULL; + + dev->tq.next = NULL; + dev->tq.sync = 0; + dev->tq.routine = i810_dma_task_queue; + dev->tq.data = dev; + + /* Before installing handler */ + temp = I810_READ16(I810REG_HWSTAM); + temp = temp & 0x6000; + I810_WRITE16(I810REG_HWSTAM, temp); + + temp = I810_READ16(I810REG_INT_MASK_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */ + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */ + + /* Install handler */ + if ((retcode = request_irq(dev->irq, + i810_dma_service, + SA_SHIRQ, + dev->devname, + dev))) { + down(&dev->struct_sem); + dev->irq = 0; + up(&dev->struct_sem); + return retcode; + } + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + temp = temp | 0x0003; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Enable bp & user interrupts */ + return 0; +} + +int i810_irq_uninstall(drm_device_t *dev) +{ + int irq; + u16 temp; + + +/* return 0; */ + + down(&dev->struct_sem); + irq = dev->irq; + dev->irq = 0; + up(&dev->struct_sem); + + if (!irq) return -EINVAL; + + DRM_DEBUG( "Interrupt UnInstall: %d\n", irq); + DRM_DEBUG("%d\n", irq); + + temp = I810_READ16(I810REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + + temp = I810_READ16(I810REG_INT_ENABLE_R); + temp = temp & 0x6000; + I810_WRITE16(I810REG_INT_ENABLE_R, + temp); /* Disable all interrupts */ + + free_irq(irq, dev); + + return 0; +} + +int i810_control(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_control_t ctl; + int retcode; + + DRM_DEBUG( "i810_control\n"); + + copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); + + switch (ctl.func) { + case DRM_INST_HANDLER: + if ((retcode = i810_irq_install(dev, ctl.irq))) + return retcode; + break; + case DRM_UNINST_HANDLER: + if ((retcode = i810_irq_uninstall(dev))) + return retcode; + break; + default: + return -EINVAL; + } + return 0; +} + +static inline void i810_dma_emit_flush(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + BEGIN_LP_RING(2); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); + +/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */ +/* atomic_set(&dev_priv->flush_done, 1); */ +/* wake_up_interruptible(&dev_priv->flush_queue); */ +} + +static inline void i810_dma_quiescent_emit(drm_device_t *dev) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + BEGIN_LP_RING(4); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); + +/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */ +/* atomic_set(&dev_priv->flush_done, 1); */ +/* wake_up_interruptible(&dev_priv->flush_queue); */ +} + +static void i810_dma_quiescent(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + unsigned long end; + + if(dev_priv == NULL) { + return; + } + atomic_set(&dev_priv->flush_done, 0); + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + + for (;;) { + current->state = TASK_INTERRUPTIBLE; + i810_dma_quiescent_emit(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + return; +} + +static int i810_flush_queue(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + unsigned long end; + int i, ret = 0; + + if(dev_priv == NULL) { + return 0; + } + atomic_set(&dev_priv->flush_done, 0); + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + i810_dma_emit_flush(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE, + I810_BUF_FREE); + + if (used == I810_BUF_HARDWARE) + DRM_DEBUG("reclaimed from HARDWARE\n"); + if (used == I810_BUF_CLIENT) + DRM_DEBUG("still on client HARDWARE\n"); + } + + return ret; +} + +/* Must be called with the lock held */ +void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if (!dev->dev_private) return; + if (!dma->buflist) return; + + i810_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + + if (buf->pid == pid && buf_priv) { + int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, + I810_BUF_FREE); + + if (used == I810_BUF_CLIENT) + DRM_DEBUG("reclaimed from client\n"); + if(buf_priv->currently_mapped == I810_BUF_MAPPED) + buf_priv->currently_mapped = I810_BUF_UNMAPPED; + } + } +} + +int i810_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; + + 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 (lock.context < 0) { + return -EINVAL; + } + /* Only one queue: + */ + + if (!ret) { + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + 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); + DRM_DEBUG("Calling lock schedule\n"); + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + + if (!ret) { + if (lock.flags & _DRM_LOCK_QUIESCENT) { + DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); + DRM_DEBUG("fred\n"); + i810_dma_quiescent(dev); + } + } + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + return ret; +} + +int i810_flush_ioctl(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_DEBUG("i810_flush_ioctl\n"); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + i810_flush_queue(dev); + return 0; +} + + +int i810_dma_vertex(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_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + drm_i810_vertex_t vertex; + + copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", + vertex.idx, vertex.used, vertex.discard); + + i810_dma_dispatch_vertex( dev, + dma->buflist[ vertex.idx ], + vertex.discard, vertex.used ); + + atomic_add(vertex.used, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return 0; +} + + + +int i810_clear_bufs(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_i810_clear_t clear; + + copy_from_user_ret(&clear, (drm_i810_clear_t *)arg, sizeof(clear), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_clear_bufs called without lock held\n"); + return -EINVAL; + } + + i810_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth ); + return 0; +} + +int i810_swap_bufs(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_DEBUG("i810_swap_bufs\n"); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_swap_buf called without lock held\n"); + return -EINVAL; + } + + i810_dma_dispatch_swap( dev ); + return 0; +} + +int i810_getage(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_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + sarea_priv->last_dispatch = (int) hw_status[5]; + return 0; +} + +int i810_getbuf(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; + int retcode = 0; + drm_i810_dma_t d; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + + DRM_DEBUG("getbuf\n"); + copy_from_user_ret(&d, (drm_i810_dma_t *)arg, sizeof(d), -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma called without lock held\n"); + return -EINVAL; + } + + d.granted = 0; + + retcode = i810_dma_get_buffer(dev, &d, filp); + + DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n", + current->pid, retcode, d.granted); + + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; +} + +int i810_copybuf(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_i810_copy_t d; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + drm_buf_t *buf; + drm_i810_buf_priv_t *buf_priv; + drm_device_dma_t *dma = dev->dma; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma called without lock held\n"); + return -EINVAL; + } + + copy_from_user_ret(&d, (drm_i810_copy_t *)arg, sizeof(d), -EFAULT); + + if(d.idx > dma->buf_count) return -EINVAL; + buf = dma->buflist[ d.idx ]; + buf_priv = buf->dev_private; + if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM; + + copy_from_user_ret(buf_priv->virtual, d.address, d.used, -EFAULT); + + sarea_priv->last_dispatch = (int) hw_status[5]; + + return 0; +} + +int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + if(VM_DONTCOPY == 0) return 1; + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/i810_drm.h linux/drivers/char/drm/i810_drm.h --- v2.2.17/drivers/char/drm/i810_drm.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/i810_drm.h Fri Sep 1 14:12:33 2000 @@ -0,0 +1,194 @@ +#ifndef _I810_DRM_H_ +#define _I810_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _I810_DEFINES_ +#define _I810_DEFINES_ + +#define I810_DMA_BUF_ORDER 12 +#define I810_DMA_BUF_SZ (1< + * Jeff Hartmann + * + */ + +#include +#include "drmP.h" +#include "i810_drv.h" + +#include + +static void __attribute__((unused)) unused(void) +{ + agp_enable(0); +} + +#define I810_NAME "i810" +#define I810_DESC "Intel I810" +#define I810_DATE "20000719" +#define I810_MAJOR 1 +#define I810_MINOR 1 +#define I810_PATCHLEVEL 0 + +static drm_device_t i810_device; +drm_ctx_t i810_res_ctx; + +static struct file_operations i810_fops = { +#if LINUX_VERSION_CODE >= 0x020322 + /* This started being used approx. 2.3.34 */ + owner: THIS_MODULE, +#endif + open: i810_open, + flush: drm_flush, + release: i810_release, + ioctl: i810_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +static struct miscdevice i810_misc = { + minor: MISC_DYNAMIC_MINOR, + name: I810_NAME, + fops: &i810_fops, +}; + +static drm_ioctl_desc_t i810_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { i810_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_CONTROL)] = { i810_control, 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_BUFS)] = { i810_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { i810_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { i810_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { i810_freebufs, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { i810_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { i810_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { i810_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { i810_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { i810_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { i810_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { i810_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)] = { i810_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { i810_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)] = { i810_dma_init, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)] = { i810_clear_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)] = { i810_flush_ioctl,1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)] = { i810_copybuf, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 }, +}; + +#define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls) + +#ifdef MODULE +static char *i810 = NULL; +#endif + +MODULE_AUTHOR("VA Linux Systems, Inc."); +MODULE_DESCRIPTION("Intel I810"); +MODULE_PARM(i810, "s"); + +#ifndef MODULE +/* i810_options 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. + */ + +static int __init i810_options(char *str) +{ + drm_parse_options(str); + return 1; +} + +__setup("i810=", i810_options); +#endif + +static int i810_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); + + drm_dma_setup(dev); + + 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_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); +#if DRM_DMA_HISTO + memset(&dev->histo, 0, sizeof(dev->histo)); +#endif + 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); + + 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 i810_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"); + + if (dev->irq) i810_irq_uninstall(dev); + + 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 AGP information */ + if (dev->agp) { + drm_agp_mem_t *entry; + drm_agp_mem_t *nexte; + + /* Remove AGP resources, but leave dev->agp + intact until r128_cleanup is called. */ + for (entry = dev->agp->memory; entry; entry = nexte) { + nexte = entry->next; + if (entry->bound) drm_unbind_agp(entry->memory); + drm_free_agp(entry->memory, entry->pages); + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + } + dev->agp->memory = NULL; + + if (dev->agp->acquired && drm_agp.release) + (*drm_agp.release)(); + + dev->agp->acquired = 0; + dev->agp->enabled = 0; + } + /* 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; + case _DRM_AGP: + 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->queuelist) { + for (i = 0; i < dev->queue_count; i++) { + drm_waitlist_destroy(&dev->queuelist[i]->waitlist); + if (dev->queuelist[i]) { + drm_free(dev->queuelist[i], + sizeof(*dev->queuelist[0]), + DRM_MEM_QUEUES); + dev->queuelist[i] = NULL; + } + } + drm_free(dev->queuelist, + dev->queue_slots * sizeof(*dev->queuelist), + DRM_MEM_QUEUES); + dev->queuelist = NULL; + } + + drm_dma_takedown(dev); + + dev->queue_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; +} + +/* i810_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +static int i810_init(void) +{ + int retcode; + drm_device_t *dev = &i810_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(i810); +#endif + DRM_DEBUG("doing misc_register\n"); + if ((retcode = misc_register(&i810_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", I810_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, i810_misc.minor); + dev->name = I810_NAME; + + DRM_DEBUG("doing mem init\n"); + drm_mem_init(); + DRM_DEBUG("doing proc init\n"); + drm_proc_init(dev); + DRM_DEBUG("doing agp init\n"); + dev->agp = drm_agp_init(); + if(dev->agp == NULL) { + DRM_INFO("The i810 drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the i810 module\n"); + drm_proc_cleanup(); + misc_deregister(&i810_misc); + i810_takedown(dev); + return -ENOMEM; + } + DRM_DEBUG("doing ctxbitmap init\n"); + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&i810_misc); + i810_takedown(dev); + return retcode; + } + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + I810_NAME, + I810_MAJOR, + I810_MINOR, + I810_PATCHLEVEL, + I810_DATE, + i810_misc.minor); + + return 0; +} + +/* i810_cleanup is called via cleanup_module at module unload time. */ + +static void i810_cleanup(void) +{ + drm_device_t *dev = &i810_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&i810_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + drm_ctxbitmap_cleanup(dev); + i810_takedown(dev); + if (dev->agp) { + drm_agp_uninit(); + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +} + +module_init(i810_init); +module_exit(i810_cleanup); + + +int i810_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 = I810_MAJOR; + version.version_minor = I810_MINOR; + version.version_patchlevel = I810_PATCHLEVEL; + + DRM_COPY(version.name, I810_NAME); + DRM_COPY(version.date, I810_DATE); + DRM_COPY(version.desc, I810_DESC); + + copy_to_user_ret((drm_version_t *)arg, + &version, + sizeof(version), + -EFAULT); + return 0; +} + +int i810_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &i810_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return i810_setup(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +int i810_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + int retcode = 0; + + lock_kernel(); + dev = priv->dev; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + i810_reclaim_buffers(dev, priv->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. */ + } else if (dev->lock.hw_lock) { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + i810_reclaim_buffers(dev, priv->pid); + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } + } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + 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); + unlock_kernel(); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return i810_takedown(dev); + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return retcode; +} + +/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int i810_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 >= I810_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &i810_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 i810_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); + if (!dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles() + - dev->lck_start)]); +#endif + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/i810_drv.h linux/drivers/char/drm/i810_drv.h --- v2.2.17/drivers/char/drm/i810_drv.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/i810_drv.h Fri Sep 1 14:12:33 2000 @@ -0,0 +1,225 @@ +/* i810_drv.h -- Private header for the Matrox g200/g400 driver -*- linux-c -*- + * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#ifndef _I810_DRV_H_ +#define _I810_DRV_H_ + +typedef struct drm_i810_buf_priv { + u32 *in_use; + int my_use_idx; + int currently_mapped; + void *virtual; + void *kernel_virtual; + int map_count; + struct vm_area_struct *vma; +} drm_i810_buf_priv_t; + +typedef struct _drm_i810_ring_buffer{ + int tail_mask; + unsigned long Start; + unsigned long End; + unsigned long Size; + u8 *virtual_start; + int head; + int tail; + int space; +} drm_i810_ring_buffer_t; + +typedef struct drm_i810_private { + int ring_map_idx; + int buffer_map_idx; + + drm_i810_ring_buffer_t ring; + drm_i810_sarea_t *sarea_priv; + + unsigned long hw_status_page; + unsigned long counter; + + atomic_t flush_done; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ + drm_buf_t *mmap_buffer; + + + u32 front_di1, back_di1, zi1; + + int back_offset; + int depth_offset; + int w, h; + int pitch; +} drm_i810_private_t; + + /* i810_drv.c */ +extern int i810_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_open(struct inode *inode, struct file *filp); +extern int i810_release(struct inode *inode, struct file *filp); +extern int i810_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* i810_dma.c */ +extern int i810_dma_schedule(drm_device_t *dev, int locked); +extern int i810_getbuf(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_irq_install(drm_device_t *dev, int irq); +extern int i810_irq_uninstall(drm_device_t *dev); +extern int i810_control(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma); +extern int i810_copybuf(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_docopy(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* i810_bufs.c */ +extern int i810_addbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_infobufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_markbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_freebufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_addmap(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* i810_context.c */ +extern int i810_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int i810_context_switch(drm_device_t *dev, int old, int new); +extern int i810_context_switch_complete(drm_device_t *dev, int new); + +#define I810_VERBOSE 0 + + +int i810_dma_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +int i810_swap_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +int i810_clear_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD (7<<23) +#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define BB1_START_ADDR_MASK (~0x7) +#define BB1_PROTECTED (1<<0) +#define BB1_UNPROTECTED (0<<0) +#define BB2_END_ADDR_MASK (~0x7) + +#define I810REG_HWSTAM 0x02098 +#define I810REG_INT_IDENTITY_R 0x020a4 +#define I810REG_INT_MASK_R 0x020a8 +#define I810REG_INT_ENABLE_R 0x020a0 + +#define LP_RING 0x2030 +#define HP_RING 0x2040 +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_START 0x08 +#define START_ADDR 0x00FFFFF8 +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x000FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) + +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) + +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x2) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) +#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24)) + +#define CMD_OP_Z_BUFFER_INFO ((0x0<<29)|(0x16<<23)) +#define CMD_OP_DESTBUFFER_INFO ((0x0<<29)|(0x15<<23)) + +#define BR00_BITBLT_CLIENT 0x40000000 +#define BR00_OP_COLOR_BLT 0x10000000 +#define BR00_OP_SRC_COPY_BLT 0x10C00000 +#define BR13_SOLID_PATTERN 0x80000000 + + + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/init.c linux/drivers/char/drm/init.c --- v2.2.17/drivers/char/drm/init.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/init.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,113 @@ +/* init.c -- Setup/Cleanup for DRM -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_flags = 0; + +/* drm_parse_option parses a single option. See description for + drm_parse_options for details. */ + +static void drm_parse_option(char *s) +{ + char *c, *r; + + DRM_DEBUG("\"%s\"\n", s); + if (!s || !*s) return; + for (c = s; *c && *c != ':'; c++); /* find : or \0 */ + if (*c) r = c + 1; else r = NULL; /* remember remainder */ + *c = '\0'; /* terminate */ + if (!strcmp(s, "noctx")) { + drm_flags |= DRM_FLAG_NOCTX; + DRM_INFO("Server-mediated context switching OFF\n"); + return; + } + if (!strcmp(s, "debug")) { + drm_flags |= DRM_FLAG_DEBUG; + DRM_INFO("Debug messages ON\n"); + return; + } + DRM_ERROR("\"%s\" is not a valid option\n", s); + return; +} + +/* drm_parse_options parse the insmod "drm=" options, or the command-line + * options passed to the kernel via LILO. The grammar of the format is as + * follows: + * + * drm ::= 'drm=' option_list + * option_list ::= option [ ';' option_list ] + * option ::= 'device:' major + * | 'debug' + * | 'noctx' + * major ::= INTEGER + * + * Note that 's' contains option_list without the 'drm=' part. + * + * device=major,minor specifies the device number used for /dev/drm + * if major == 0 then the misc device is used + * if major == 0 and minor == 0 then dynamic misc allocation is used + * debug=on specifies that debugging messages will be printk'd + * debug=trace specifies that each function call will be logged via printk + * debug=off turns off all debugging options + * + */ + +void drm_parse_options(char *s) +{ + char *h, *t, *n; + + DRM_DEBUG("\"%s\"\n", s ?: ""); + if (!s || !*s) return; + + for (h = t = n = s; h && *h; h = n) { + for (; *t && *t != ';'; t++); /* find ; or \0 */ + if (*t) n = t + 1; else n = NULL; /* remember next */ + *t = '\0'; /* terminate */ + drm_parse_option(h); /* parse */ + } +} + +/* 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 +#if defined(__sparc__) && !defined(__sparc_v9__) + if (1) + return 0; /* No cmpxchg before v9 sparc. */ +#endif + return 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/ioctl.c linux/drivers/char/drm/ioctl.c --- v2.2.17/drivers/char/drm/ioctl.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/ioctl.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,91 @@ +/* ioctl.c -- IOCTL processing for DRM -*- linux-c -*- + * Created: Fri Jan 8 09:01:26 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_irq_busid(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_irq_busid_t p; + struct pci_dev *dev; + + copy_from_user_ret(&p, (drm_irq_busid_t *)arg, sizeof(p), -EFAULT); + dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); + if (dev) p.irq = dev->irq; + else p.irq = 0; + DRM_DEBUG("%d:%d:%d => IRQ %d\n", + p.busnum, p.devnum, p.funcnum, p.irq); + copy_to_user_ret((drm_irq_busid_t *)arg, &p, sizeof(p), -EFAULT); + return 0; +} + +int drm_getunique(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_unique_t u; + + copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT); + if (u.unique_len >= dev->unique_len) { + copy_to_user_ret(u.unique, dev->unique, dev->unique_len, + -EFAULT); + } + u.unique_len = dev->unique_len; + copy_to_user_ret((drm_unique_t *)arg, &u, sizeof(u), -EFAULT); + return 0; +} + +int drm_setunique(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_unique_t u; + + if (dev->unique_len || dev->unique) return -EBUSY; + + copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT); + if (!u.unique_len) return -EINVAL; + + dev->unique_len = u.unique_len; + dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER); + copy_from_user_ret(dev->unique, u.unique, dev->unique_len, + -EFAULT); + dev->unique[dev->unique_len] = '\0'; + + dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2, + DRM_MEM_DRIVER); + sprintf(dev->devname, "%s@%s", dev->name, dev->unique); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/lists.c linux/drivers/char/drm/lists.c --- v2.2.17/drivers/char/drm/lists.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/lists.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,230 @@ +/* lists.c -- Buffer list handling routines -*- linux-c -*- + * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_waitlist_create(drm_waitlist_t *bl, int count) +{ + DRM_DEBUG("%d\n", count); + if (bl->count) return -EINVAL; + + bl->count = count; + bl->bufs = drm_alloc((bl->count + 2) * sizeof(*bl->bufs), + DRM_MEM_BUFLISTS); + bl->rp = bl->bufs; + bl->wp = bl->bufs; + bl->end = &bl->bufs[bl->count+1]; + bl->write_lock = SPIN_LOCK_UNLOCKED; + bl->read_lock = SPIN_LOCK_UNLOCKED; + return 0; +} + +int drm_waitlist_destroy(drm_waitlist_t *bl) +{ + DRM_DEBUG("\n"); + if (bl->rp != bl->wp) return -EINVAL; + if (bl->bufs) drm_free(bl->bufs, + (bl->count + 2) * sizeof(*bl->bufs), + DRM_MEM_BUFLISTS); + bl->count = 0; + bl->bufs = NULL; + bl->rp = NULL; + bl->wp = NULL; + bl->end = NULL; + return 0; +} + +int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf) +{ + int left; + unsigned long flags; + + left = DRM_LEFTCOUNT(bl); + DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n", + buf->idx, left, bl->rp, bl->wp); + if (!left) { + DRM_ERROR("Overflow while adding buffer %d from pid %d\n", + buf->idx, buf->pid); + return -EINVAL; + } +#if DRM_DMA_HISTOGRAM + buf->time_queued = get_cycles(); +#endif + buf->list = DRM_LIST_WAIT; + + spin_lock_irqsave(&bl->write_lock, flags); + *bl->wp = buf; + if (++bl->wp >= bl->end) bl->wp = bl->bufs; + spin_unlock_irqrestore(&bl->write_lock, flags); + + return 0; +} + +drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl) +{ + drm_buf_t *buf; + unsigned long flags; + + spin_lock_irqsave(&bl->read_lock, flags); + buf = *bl->rp; + if (bl->rp == bl->wp) { + spin_unlock_irqrestore(&bl->read_lock, flags); + return NULL; + } + if (++bl->rp >= bl->end) bl->rp = bl->bufs; + spin_unlock_irqrestore(&bl->read_lock, flags); + + DRM_DEBUG("get %d\n", buf->idx); + return buf; +} + +int drm_freelist_create(drm_freelist_t *bl, int count) +{ + DRM_DEBUG("\n"); + atomic_set(&bl->count, 0); + bl->next = NULL; + init_waitqueue_head(&bl->waiting); + bl->low_mark = 0; + bl->high_mark = 0; + atomic_set(&bl->wfh, 0); + bl->lock = SPIN_LOCK_UNLOCKED; + ++bl->initialized; + return 0; +} + +int drm_freelist_destroy(drm_freelist_t *bl) +{ + DRM_DEBUG("\n"); + atomic_set(&bl->count, 0); + bl->next = NULL; + return 0; +} + +int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) +{ + drm_device_dma_t *dma = dev->dma; + + if (!dma) { + DRM_ERROR("No DMA support\n"); + return 1; + } + + if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) { + DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n", + buf->idx, buf->waiting, buf->pending, buf->list); + } + DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", + buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh), + buf->waiting, buf->pending); + if (!bl) return 1; +#if DRM_DMA_HISTOGRAM + buf->time_freed = get_cycles(); + drm_histogram_compute(dev, buf); +#endif + buf->list = DRM_LIST_FREE; + + spin_lock(&bl->lock); + buf->next = bl->next; + bl->next = buf; + spin_unlock(&bl->lock); + + atomic_inc(&bl->count); + if (atomic_read(&bl->count) > dma->buf_count) { + DRM_ERROR("%d of %d buffers free after addition of %d\n", + atomic_read(&bl->count), dma->buf_count, buf->idx); + return 1; + } + /* Check for high water mark */ + if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) { + atomic_set(&bl->wfh, 0); + wake_up_interruptible(&bl->waiting); + } + return 0; +} + +static drm_buf_t *drm_freelist_try(drm_freelist_t *bl) +{ + drm_buf_t *buf; + + if (!bl) return NULL; + + /* Get buffer */ + spin_lock(&bl->lock); + if (!bl->next) { + spin_unlock(&bl->lock); + return NULL; + } + buf = bl->next; + bl->next = bl->next->next; + spin_unlock(&bl->lock); + + atomic_dec(&bl->count); + buf->next = NULL; + buf->list = DRM_LIST_NONE; + if (buf->waiting || buf->pending) { + DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n", + buf->idx, buf->waiting, buf->pending, buf->list); + } + + return buf; +} + +drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block) +{ + drm_buf_t *buf = NULL; + DECLARE_WAITQUEUE(entry, current); + + if (!bl || !bl->initialized) return NULL; + + /* Check for low water mark */ + if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */ + atomic_set(&bl->wfh, 1); + if (atomic_read(&bl->wfh)) { + if (block) { + add_wait_queue(&bl->waiting, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!atomic_read(&bl->wfh) + && (buf = drm_freelist_try(bl))) break; + schedule(); + if (signal_pending(current)) break; + } + current->state = TASK_RUNNING; + remove_wait_queue(&bl->waiting, &entry); + } + return buf; + } + + DRM_DEBUG("Count = %d, wfh = %d\n", + atomic_read(&bl->count), atomic_read(&bl->wfh)); + return drm_freelist_try(bl); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/lock.c linux/drivers/char/drm/lock.c --- v2.2.17/drivers/char/drm/lock.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/lock.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,225 @@ +/* lock.c -- IOCTLs for locking -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_block(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + DRM_DEBUG("\n"); + return 0; +} + +int drm_unblock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + DRM_DEBUG("\n"); + return 0; +} + +int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) +{ + 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; + prev = cmpxchg(lock, old, new); + } while (prev != old); + if (_DRM_LOCKING_CONTEXT(old) == context) { + if (old & _DRM_LOCK_HELD) { + if (context != DRM_KERNEL_CONTEXT) { + DRM_ERROR("%d holds heavyweight lock\n", + context); + } + return 0; + } + } + if (new == (context | _DRM_LOCK_HELD)) { + /* Have lock */ + DRM_DEBUG("%d\n", context); + return 1; + } + DRM_DEBUG("%d unable to get lock held by %d\n", + context, _DRM_LOCKING_CONTEXT(old)); + return 0; +} + +/* 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(drm_device_t *dev, + __volatile__ unsigned int *lock, unsigned int context) +{ + unsigned int old, new, prev; + + dev->lock.pid = 0; + do { + 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; +} + +int drm_lock_free(drm_device_t *dev, + __volatile__ unsigned int *lock, unsigned int context) +{ + 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; + 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 (pid %d)\n", + context, + _DRM_LOCKING_CONTEXT(old), + pid); + return 1; + } + wake_up_interruptible(&dev->lock.lock_queue); + return 0; +} + +static int drm_flush_queue(drm_device_t *dev, int context) +{ + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_queue_t *q = dev->queuelist[context]; + + DRM_DEBUG("\n"); + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) > 1) { + atomic_inc(&q->block_write); + add_wait_queue(&q->flush_queue, &entry); + atomic_inc(&q->block_count); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!DRM_BUFCOUNT(&q->waitlist)) break; + schedule(); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + atomic_dec(&q->block_count); + current->state = TASK_RUNNING; + remove_wait_queue(&q->flush_queue, &entry); + } + atomic_dec(&q->use_count); + atomic_inc(&q->total_flushed); + + /* NOTE: block_write is still incremented! + Use drm_flush_unlock_queue to decrement. */ + return ret; +} + +static int drm_flush_unblock_queue(drm_device_t *dev, int context) +{ + drm_queue_t *q = dev->queuelist[context]; + + DRM_DEBUG("\n"); + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) > 1) { + if (atomic_read(&q->block_write)) { + atomic_dec(&q->block_write); + wake_up_interruptible(&q->write_queue); + } + } + atomic_dec(&q->use_count); + return 0; +} + +int drm_flush_block_and_flush(drm_device_t *dev, int context, + drm_lock_flags_t flags) +{ + int ret = 0; + int i; + + DRM_DEBUG("\n"); + + if (flags & _DRM_LOCK_FLUSH) { + ret = drm_flush_queue(dev, DRM_KERNEL_CONTEXT); + if (!ret) ret = drm_flush_queue(dev, context); + } + if (flags & _DRM_LOCK_FLUSH_ALL) { + for (i = 0; !ret && i < dev->queue_count; i++) { + ret = drm_flush_queue(dev, i); + } + } + return ret; +} + +int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags) +{ + int ret = 0; + int i; + + DRM_DEBUG("\n"); + + if (flags & _DRM_LOCK_FLUSH) { + ret = drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT); + if (!ret) ret = drm_flush_unblock_queue(dev, context); + } + if (flags & _DRM_LOCK_FLUSH_ALL) { + for (i = 0; !ret && i < dev->queue_count; i++) { + ret = drm_flush_unblock_queue(dev, i); + } + } + + return ret; +} + +int drm_finish(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; + int ret = 0; + drm_lock_t lock; + + DRM_DEBUG("\n"); + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); + drm_flush_unblock(dev, lock.context, lock.flags); + return ret; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/memory.c linux/drivers/char/drm/memory.c --- v2.2.17/drivers/char/drm/memory.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/memory.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,460 @@ +/* memory.c -- Memory management wrappers for DRM -*- linux-c -*- + * Created: Thu Feb 4 14:00:34 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include +#include "drmP.h" +#include + +typedef struct drm_mem_stats { + const char *name; + int succeed_count; + int free_count; + int fail_count; + unsigned long bytes_allocated; + unsigned long bytes_freed; +} drm_mem_stats_t; + +static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED; +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" }, + [DRM_MEM_SAREA] = { "sareas" }, + [DRM_MEM_DRIVER] = { "driver" }, + [DRM_MEM_MAGIC] = { "magic" }, + [DRM_MEM_IOCTLS] = { "ioctltab" }, + [DRM_MEM_MAPS] = { "maplist" }, + [DRM_MEM_VMAS] = { "vmalist" }, + [DRM_MEM_BUFS] = { "buflist" }, + [DRM_MEM_SEGS] = { "seglist" }, + [DRM_MEM_PAGES] = { "pagelist" }, + [DRM_MEM_FILES] = { "files" }, + [DRM_MEM_QUEUES] = { "queues" }, + [DRM_MEM_CMDS] = { "commands" }, + [DRM_MEM_MAPPINGS] = { "mappings" }, + [DRM_MEM_BUFLISTS] = { "buflists" }, + [DRM_MEM_AGPLISTS] = { "agplist" }, + [DRM_MEM_TOTALAGP] = { "totalagp" }, + [DRM_MEM_BOUNDAGP] = { "boundagp" }, + [DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, + { NULL, 0, } /* Last entry must be null */ +}; + +void drm_mem_init(void) +{ + drm_mem_stats_t *mem; + struct sysinfo si; + + for (mem = drm_mem_stats; mem->name; ++mem) { + mem->succeed_count = 0; + mem->free_count = 0; + mem->fail_count = 0; + mem->bytes_allocated = 0; + mem->bytes_freed = 0; + } + + 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; +} + +/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ + +static int _drm_mem_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_mem_stats_t *pt; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT(" total counts " + " | outstanding \n"); + DRM_PROC_PRINT("type alloc freed fail bytes freed" + " | allocs bytes\n\n"); + 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", + pt->name, + pt->succeed_count, + pt->free_count, + pt->fail_count, + pt->bytes_allocated, + pt->bytes_freed, + pt->succeed_count - pt->free_count, + (long)pt->bytes_allocated + - (long)pt->bytes_freed); + } + + return len; +} + +int drm_mem_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + int ret; + + spin_lock(&drm_mem_lock); + ret = _drm_mem_info(buf, start, offset, len, eof, data); + spin_unlock(&drm_mem_lock); + return ret; +} + +void *drm_alloc(size_t size, int area) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); + return NULL; + } + + if (!(pt = kmalloc(size, GFP_KERNEL))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].fail_count; + spin_unlock(&drm_mem_lock); + return NULL; + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_allocated += size; + spin_unlock(&drm_mem_lock); + return pt; +} + +void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) +{ + void *pt; + + if (!(pt = drm_alloc(size, area))) return NULL; + if (oldpt && oldsize) { + memcpy(pt, oldpt, oldsize); + drm_free(oldpt, oldsize, area); + } + return pt; +} + +char *drm_strdup(const char *s, int area) +{ + char *pt; + int length = s ? strlen(s) : 0; + + if (!(pt = drm_alloc(length+1, area))) return NULL; + strcpy(pt, s); + return pt; +} + +void drm_strfree(const char *s, int area) +{ + unsigned int size; + + if (!s) return; + + size = 1 + (s ? strlen(s) : 0); + drm_free((void *)s, size, area); +} + +void drm_free(void *pt, size_t size, int area) +{ + int alloc_count; + int free_count; + + if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); + else kfree(pt); + spin_lock(&drm_mem_lock); + drm_mem_stats[area].bytes_freed += size; + free_count = ++drm_mem_stats[area].free_count; + alloc_count = drm_mem_stats[area].succeed_count; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +unsigned long drm_alloc_pages(int order, int area) +{ + unsigned long address; + unsigned long bytes = PAGE_SIZE << order; + unsigned long addr; + unsigned int sz; + + spin_lock(&drm_mem_lock); + if ((drm_ram_used >> PAGE_SHIFT) + > (DRM_RAM_PERCENT * drm_ram_available) / 100) { + spin_unlock(&drm_mem_lock); + return 0; + } + spin_unlock(&drm_mem_lock); + + address = __get_free_pages(GFP_KERNEL, order); + if (!address) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].fail_count; + spin_unlock(&drm_mem_lock); + return 0; + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_allocated += bytes; + drm_ram_used += bytes; + spin_unlock(&drm_mem_lock); + + + /* Zero outside the lock */ + memset((void *)address, 0, bytes); + + /* Reserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { +#if LINUX_VERSION_CODE >= 0x020400 + /* Argument type changed in 2.4.0-test6/pre8 */ + mem_map_reserve(virt_to_page(addr)); +#else + mem_map_reserve(MAP_NR(addr)); +#endif + } + + return address; +} + +void drm_free_pages(unsigned long address, int order, int area) +{ + unsigned long bytes = PAGE_SIZE << order; + int alloc_count; + int free_count; + unsigned long addr; + unsigned int sz; + + if (!address) { + DRM_MEM_ERROR(area, "Attempt to free address 0\n"); + } else { + /* Unreserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { +#if LINUX_VERSION_CODE >= 0x020400 + /* Argument type changed in 2.4.0-test6/pre8 */ + mem_map_unreserve(virt_to_page(addr)); +#else + mem_map_unreserve(MAP_NR(addr)); +#endif + } + free_pages(address, order); + } + + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[area].free_count; + alloc_count = drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_freed += bytes; + drm_ram_used -= bytes; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +void *drm_ioremap(unsigned long offset, unsigned long size) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Mapping 0 bytes at 0x%08lx\n", offset); + return NULL; + } + + if (!(pt = ioremap(offset, size))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&drm_mem_lock); + return NULL; + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&drm_mem_lock); + return pt; +} + +void drm_ioremapfree(void *pt, unsigned long size) +{ + int alloc_count; + int free_count; + + if (!pt) + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Attempt to free NULL pointer\n"); + else + iounmap(pt); + + spin_lock(&drm_mem_lock); + drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size; + free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count; + alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +agp_memory *drm_alloc_agp(int pages, u32 type) +{ + agp_memory *handle; + + if (!pages) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); + return NULL; + } + + if (drm_agp.allocate_memory) { + if ((handle = (*drm_agp.allocate_memory)(pages, + type))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated + += pages << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + return handle; + } + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count; + spin_unlock(&drm_mem_lock); + return NULL; +} + +int drm_free_agp(agp_memory *handle, int pages) +{ + int alloc_count; + int free_count; + int retval = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Attempt to free NULL AGP handle\n"); + return retval;; + } + + if (drm_agp.free_memory) { + (*drm_agp.free_memory)(handle); + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count; + alloc_count = drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed + += pages << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + return 0; + } + return retval; +} + +int drm_bind_agp(agp_memory *handle, unsigned int start) +{ + int retcode = -EINVAL; + + DRM_DEBUG("drm_bind_agp called\n"); + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to bind NULL AGP handle\n"); + return retcode; + } + + DRM_DEBUG("drm_agp.bind_memory : %p\n", drm_agp.bind_memory); + if (drm_agp.bind_memory) { + if (!(retcode = (*drm_agp.bind_memory)(handle, start))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated + += handle->page_count << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + DRM_DEBUG("drm_agp.bind_memory: retcode %d\n", retcode); + return retcode; + } + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count; + spin_unlock(&drm_mem_lock); + return retcode; +} + +int drm_unbind_agp(agp_memory *handle) +{ + int alloc_count; + int free_count; + int retcode = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to unbind NULL AGP handle\n"); + return retcode; + } + + if (drm_agp.unbind_memory) { + int c = handle->page_count; + if ((retcode = (*drm_agp.unbind_memory)(handle))) + return retcode; + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count; + alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed += c << PAGE_SHIFT; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + } + return retcode; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/mga_bufs.c linux/drivers/char/drm/mga_bufs.c --- v2.2.17/drivers/char/drm/mga_bufs.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/mga_bufs.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,639 @@ +/* mga_bufs.c -- IOCTLs to manage buffers -*- linux-c -*- + * Created: Thu Jan 6 01:47:26 2000 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "mga_drv.h" +#include "linux/un.h" + + +int mga_addbufs_agp(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + agp_offset = request.agp_start; + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + byte_count = 0; + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + DRM_DEBUG("byte_count: %d\n", byte_count); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; + + + while(entry->buf_count < count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + + DRM_DEBUG("offset : %ld\n", offset); + + buf->offset = offset; /* Hrm */ + buf->bus_address = dev->agp->base + agp_offset + offset; + buf->address = (void *)(agp_offset + offset + dev->agp->base); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t), DRM_MEM_BUFS); + buf->dev_priv_size = sizeof(drm_mga_buf_priv_t); + +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + offset = offset + alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + + DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); + + dma->byte_count += byte_count; + + DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); + + atomic_dec(&dev->buf_alloc); + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + DRM_DEBUG("byte_count: %d\n", byte_count); + + dma->flags = _DRM_DMA_USE_AGP; + + DRM_DEBUG("dma->flags : %x\n", dma->flags); + + return 0; +} + +int mga_addbufs_pci(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + int count; + int order; + int size; + int total; + int page_order; + drm_buf_entry_t *entry; + unsigned long page; + drm_buf_t *buf; + int alignment; + unsigned long offset; + int i; + int byte_count; + int page_count; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + + DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n", + request.count, request.size, size, order, dev->queue_count); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->seglist = drm_alloc(count * sizeof(*entry->seglist), + DRM_MEM_SEGS); + if (!entry->seglist) { + drm_free(entry->buflist, + count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->seglist, 0, count * sizeof(*entry->seglist)); + + dma->pagelist = drm_realloc(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + DRM_DEBUG("pagelist: %d entries\n", + dma->page_count + (count << page_order)); + + + entry->buf_size = size; + entry->page_order = page_order; + byte_count = 0; + page_count = 0; + while (entry->buf_count < count) { + if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break; + entry->seglist[entry->seg_count++] = page; + for (i = 0; i < (1 << page_order); i++) { + DRM_DEBUG("page %d @ 0x%08lx\n", + dma->page_count + page_count, + page + PAGE_SIZE * i); + dma->pagelist[dma->page_count + page_count++] + = page + PAGE_SIZE * i; + } + for (offset = 0; + offset + size <= total && entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + byte_count + offset); + buf->address = (void *)(page + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + byte_count += PAGE_SIZE << page_order; + } + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += entry->seg_count << page_order; + dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); + + atomic_dec(&dev->buf_alloc); + return 0; +} + +int mga_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_buf_desc_t request; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + if(request.flags & _DRM_AGP_BUFFER) + return mga_addbufs_agp(inode, filp, cmd, arg); + else + return mga_addbufs_pci(inode, filp, cmd, arg); +} + +int mga_infobufs(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_device_dma_t *dma = dev->dma; + drm_buf_info_t request; + int i; + int count; + + if (!dma) return -EINVAL; + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_info_t *)arg, + sizeof(request), + -EFAULT); + + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) ++count; + } + + DRM_DEBUG("count = %d\n", count); + + if (request.count >= count) { + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) { + copy_to_user_ret(&request.list[count].count, + &dma->bufs[i].buf_count, + sizeof(dma->bufs[0] + .buf_count), + -EFAULT); + copy_to_user_ret(&request.list[count].size, + &dma->bufs[i].buf_size, + sizeof(dma->bufs[0].buf_size), + -EFAULT); + copy_to_user_ret(&request.list[count].low_mark, + &dma->bufs[i] + .freelist.low_mark, + sizeof(dma->bufs[0] + .freelist.low_mark), + -EFAULT); + copy_to_user_ret(&request.list[count] + .high_mark, + &dma->bufs[i] + .freelist.high_mark, + sizeof(dma->bufs[0] + .freelist.high_mark), + -EFAULT); + DRM_DEBUG("%d %d %d %d %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].buf_size, + dma->bufs[i].freelist.low_mark, + dma->bufs[i].freelist.high_mark); + ++count; + } + } + } + request.count = count; + + copy_to_user_ret((drm_buf_info_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return 0; +} + +int mga_markbufs(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + int order; + drm_buf_entry_t *entry; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d, %d, %d\n", + request.size, request.low_mark, request.high_mark); + order = drm_order(request.size); + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + entry = &dma->bufs[order]; + + if (request.low_mark < 0 || request.low_mark > entry->buf_count) + return -EINVAL; + if (request.high_mark < 0 || request.high_mark > entry->buf_count) + return -EINVAL; + + entry->freelist.low_mark = request.low_mark; + entry->freelist.high_mark = request.high_mark; + + return 0; +} + +int mga_freebufs(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_device_dma_t *dma = dev->dma; + drm_buf_free_t request; + int i; + int idx; + drm_buf_t *buf; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_free_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d\n", request.count); + for (i = 0; i < request.count; i++) { + copy_from_user_ret(&idx, + &request.list[i], + sizeof(idx), + -EFAULT); + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + idx, dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[idx]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d freeing buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + drm_free_buffer(dev, buf); + } + + return 0; +} + +int mga_mapbufs(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_device_dma_t *dma = dev->dma; + int retcode = 0; + const int zero = 0; + unsigned long virtual; + unsigned long address; + drm_buf_map_t request; + int i; + + if (!dma) return -EINVAL; + + DRM_DEBUG("\n"); + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + DRM_DEBUG("Busy\n"); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_map_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("mga_mapbufs\n"); + DRM_DEBUG("dma->flags : %x\n", dma->flags); + + if (request.count >= dma->buf_count) { + if(dma->flags & _DRM_DMA_USE_AGP) { + drm_mga_private_t *dev_priv = dev->dev_private; + drm_map_t *map = NULL; + + map = dev->maplist[dev_priv->buffer_map_idx]; + if (!map) { + DRM_DEBUG("map is null\n"); + retcode = -EINVAL; + goto done; + } + + DRM_DEBUG("map->offset : %lx\n", map->offset); + DRM_DEBUG("map->size : %lx\n", map->size); + DRM_DEBUG("map->type : %d\n", map->type); + DRM_DEBUG("map->flags : %x\n", map->flags); + DRM_DEBUG("map->handle : %p\n", map->handle); + DRM_DEBUG("map->mtrr : %d\n", map->mtrr); + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, map->size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + (unsigned long)map->offset); + up(¤t->mm->mmap_sem); + } else { + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); + } + if (virtual > -1024UL) { + /* Real error */ + DRM_DEBUG("mmap error\n"); + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void *)virtual; + + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].used, + &zero, + sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; + if (copy_to_user(&request.list[i].address, + &address, + sizeof(address))) { + retcode = -EFAULT; + goto done; + } + } + } + done: + request.count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); + + copy_to_user_ret((drm_buf_map_t *)arg, + &request, + sizeof(request), + -EFAULT); + + DRM_DEBUG("retcode : %d\n", retcode); + + return retcode; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/mga_context.c linux/drivers/char/drm/mga_context.c --- v2.2.17/drivers/char/drm/mga_context.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/mga_context.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,207 @@ +/* mga_context.c -- IOCTLs for mga contexts -*- linux-c -*- + * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Author: Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "mga_drv.h" + +static int mga_alloc_queue(drm_device_t *dev) +{ + int temp = drm_ctxbitmap_next(dev); + DRM_DEBUG("mga_alloc_queue: %d\n", temp); + return temp; +} + +int mga_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) { + mga_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int mga_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 mga_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 mga_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 = mga_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = mga_alloc_queue(dev); + } + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + DRM_DEBUG("%d\n", ctx.handle); + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int mga_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + /* This does nothing for the mga */ + return 0; +} + +int mga_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 mga_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 mga_context_switch(dev, dev->last_context, ctx.handle); +} + +int mga_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); + mga_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int mga_rmctx(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); + if(ctx.handle == DRM_KERNEL_CONTEXT+1) { + priv->remove_auth_on_close = 1; + } + + if(ctx.handle != DRM_KERNEL_CONTEXT) { + drm_ctxbitmap_free(dev, ctx.handle); + } + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/mga_dma.c linux/drivers/char/drm/mga_dma.c --- v2.2.17/drivers/char/drm/mga_dma.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/mga_dma.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,1065 @@ +/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*- + * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * Keith Whitwell + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "mga_drv.h" + +#include /* For task queue support */ + +#define MGA_REG(reg) 2 +#define MGA_BASE(reg) ((unsigned long) \ + ((drm_device_t *)dev)->maplist[MGA_REG(reg)]->handle) +#define MGA_ADDR(reg) (MGA_BASE(reg) + reg) +#define MGA_DEREF(reg) *(__volatile__ int *)MGA_ADDR(reg) +#define MGA_READ(reg) MGA_DEREF(reg) +#define MGA_WRITE(reg,val) do { MGA_DEREF(reg) = val; } while (0) + +#define PDEA_pagpxfer_enable 0x2 + +static int mga_flush_queue(drm_device_t *dev); + +static unsigned long mga_alloc_page(drm_device_t *dev) +{ + unsigned long address; + + address = __get_free_page(GFP_KERNEL); + if(address == 0UL) { + return 0; + } + atomic_inc(&virt_to_page(address)->count); + set_bit(PG_reserved, &virt_to_page(address)->flags); + + return address; +} + +static void mga_free_page(drm_device_t *dev, unsigned long page) +{ + if(!page) return; + atomic_dec(&virt_to_page(page)->count); + clear_bit(PG_reserved, &virt_to_page(page)->flags); + free_page(page); + return; +} + +static void mga_delay(void) +{ + return; +} + +/* These are two age tags that will never be sent to + * the hardware */ +#define MGA_BUF_USED 0xffffffff +#define MGA_BUF_FREE 0 + +static int mga_freelist_init(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_freelist_t *item; + int i; + + DRM_DEBUG("%s\n", __FUNCTION__); + + dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + if(dev_priv->head == NULL) return -ENOMEM; + memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); + dev_priv->head->age = MGA_BUF_USED; + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + item = drm_alloc(sizeof(drm_mga_freelist_t), + DRM_MEM_DRIVER); + if(item == NULL) return -ENOMEM; + memset(item, 0, sizeof(drm_mga_freelist_t)); + item->age = MGA_BUF_FREE; + item->prev = dev_priv->head; + item->next = dev_priv->head->next; + if(dev_priv->head->next != NULL) + dev_priv->head->next->prev = item; + if(item->next == NULL) dev_priv->tail = item; + item->buf = buf; + buf_priv->my_freelist = item; + buf_priv->discard = 0; + buf_priv->dispatched = 0; + dev_priv->head->next = item; + } + + return 0; +} + +static void mga_freelist_cleanup(drm_device_t *dev) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_freelist_t *item; + drm_mga_freelist_t *prev; + + DRM_DEBUG("%s\n", __FUNCTION__); + + item = dev_priv->head; + while(item) { + prev = item; + item = item->next; + drm_free(prev, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + } + + dev_priv->head = dev_priv->tail = NULL; +} + +/* Frees dispatch lock */ +static inline void mga_dma_quiescent(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned long end; + int i; + + DRM_DEBUG("dispatch_status = 0x%02x\n", dev_priv->dispatch_status); + end = jiffies + (HZ*3); + while(1) { + if(!test_and_set_bit(MGA_IN_DISPATCH, + &dev_priv->dispatch_status)) { + break; + } + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup: dispatch_status = 0x%02x," + " jiffies = %lu, end = %lu\n", + dev_priv->dispatch_status, jiffies, end); + goto out_nolock; + } + for (i = 0 ; i < 2000 ; i++) mga_delay(); + } + end = jiffies + (HZ*3); + DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS)); + while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup\n"); + goto out_status; + } + for (i = 0 ; i < 2000 ; i++) mga_delay(); + } + sarea_priv->dirty |= MGA_DMA_FLUSH; + +out_status: + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); +out_nolock: +} + +static void mga_reset_freelist(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + int i; + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + buf_priv->my_freelist->age = MGA_BUF_FREE; + } +} + +/* Least recently used : + * These operations are not atomic b/c they are protected by the + * hardware lock */ + +drm_buf_t *mga_freelist_get(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_mga_freelist_t *prev; + drm_mga_freelist_t *next; + static int failed = 0; + int return_null = 0; + + if(failed >= 1000 && dev_priv->tail->age >= dev_priv->last_prim_age) { + DRM_DEBUG("Waiting on freelist," + " tail->age = %d, last_prim_age= %d\n", + dev_priv->tail->age, + dev_priv->last_prim_age); + add_wait_queue(&dev_priv->buf_queue, &entry); + set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + mga_dma_schedule(dev, 0); + if(dev_priv->tail->age < dev_priv->last_prim_age) + break; + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + ++return_null; + break; + } + } + clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->buf_queue, &entry); + if (return_null) return NULL; + } + + if(dev_priv->tail->age < dev_priv->last_prim_age) { + prev = dev_priv->tail->prev; + next = dev_priv->tail; + prev->next = NULL; + next->prev = next->next = NULL; + dev_priv->tail = prev; + next->age = MGA_BUF_USED; + failed = 0; + return next->buf; + } + + failed++; + return NULL; +} + +int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) +{ + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_freelist_t *prev; + drm_mga_freelist_t *head; + drm_mga_freelist_t *next; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if(buf_priv->my_freelist->age == MGA_BUF_USED) { + /* Discarded buffer, put it on the tail */ + next = buf_priv->my_freelist; + next->age = MGA_BUF_FREE; + prev = dev_priv->tail; + prev->next = next; + next->prev = prev; + next->next = NULL; + dev_priv->tail = next; + DRM_DEBUG("Discarded\n"); + } else { + /* Normally aged buffer, put it on the head + 1, + * as the real head is a sentinal element + */ + next = buf_priv->my_freelist; + head = dev_priv->head; + prev = head->next; + head->next = next; + prev->prev = next; + next->prev = head; + next->next = prev; + } + + return 0; +} + +static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_prim_buf_t *prim_buffer; + int i, temp, size_of_buf; + int offset = init->reserved_map_agpstart; + + dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / + PAGE_SIZE) * PAGE_SIZE; + size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS; + dev_priv->warp_ucode_size = init->warp_ucode_size; + dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + if(dev_priv->prim_bufs == NULL) { + DRM_ERROR("Unable to allocate memory for prim_buf\n"); + return -ENOMEM; + } + memset(dev_priv->prim_bufs, + 0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1)); + + temp = init->warp_ucode_size + dev_priv->primary_size; + temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; + + dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, + temp); + if(dev_priv->ioremap == NULL) { + DRM_ERROR("Ioremap failed\n"); + return -ENOMEM; + } + init_waitqueue_head(&dev_priv->wait_queue); + + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), + DRM_MEM_DRIVER); + if(prim_buffer == NULL) return -ENOMEM; + memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t)); + prim_buffer->phys_head = offset + dev->agp->base; + prim_buffer->current_dma_ptr = + prim_buffer->head = + (u32 *) (dev_priv->ioremap + + offset - + init->reserved_map_agpstart); + prim_buffer->num_dwords = 0; + prim_buffer->max_dwords = size_of_buf / sizeof(u32); + prim_buffer->max_dwords -= 5; /* Leave room for the softrap */ + prim_buffer->sec_used = 0; + prim_buffer->idx = i; + prim_buffer->prim_age = i + 1; + offset = offset + size_of_buf; + dev_priv->prim_bufs[i] = prim_buffer; + } + dev_priv->current_prim_idx = 0; + dev_priv->next_prim = + dev_priv->last_prim = + dev_priv->current_prim = + dev_priv->prim_bufs[0]; + dev_priv->next_prim_age = 2; + dev_priv->last_prim_age = 1; + set_bit(MGA_BUF_IN_USE, &dev_priv->current_prim->buffer_status); + return 0; +} + +void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + int use_agp = PDEA_pagpxfer_enable; + unsigned long end; + int i; + int next_idx; + PRIMLOCALS; + + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv->last_prim = prim; + + /* We never check for overflow, b/c there is always room */ + PRIMPTR(prim); + if(num_dwords <= 0) { + DRM_DEBUG("num_dwords == 0 when dispatched\n"); + goto out_prim_wait; + } + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SOFTRAP, 0); + PRIMFINISH(prim); + + end = jiffies + (HZ*3); + if(sarea_priv->dirty & MGA_DMA_FLUSH) { + DRM_DEBUG("Dma top flush\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup in fire primary " + "(Dma Top Flush)\n"); + goto out_prim_wait; + } + + for (i = 0 ; i < 4096 ; i++) mga_delay(); + } + sarea_priv->dirty &= ~(MGA_DMA_FLUSH); + } else { + DRM_DEBUG("Status wait\n"); + while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) { + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), + atomic_read(&dma->total_lost)); + DRM_ERROR("lockup in fire primary " + "(Status Wait)\n"); + goto out_prim_wait; + } + + for (i = 0 ; i < 4096 ; i++) mga_delay(); + } + } + + mga_flush_write_combine(); + atomic_inc(&dev_priv->pending_bufs); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); + MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); + prim->num_dwords = 0; + sarea_priv->last_enqueue = prim->prim_age; + + next_idx = prim->idx + 1; + if(next_idx >= MGA_NUM_PRIM_BUFS) + next_idx = 0; + + dev_priv->next_prim = dev_priv->prim_bufs[next_idx]; + return; + + out_prim_wait: + prim->num_dwords = 0; + prim->sec_used = 0; + clear_bit(MGA_BUF_IN_USE, &prim->buffer_status); + wake_up_interruptible(&dev_priv->wait_queue); + clear_bit(MGA_BUF_SWAP_PENDING, &prim->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); +} + +int mga_advance_primary(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_prim_buf_t *prim_buffer; + drm_device_dma_t *dma = dev->dma; + int next_prim_idx; + int ret = 0; + + /* This needs to reset the primary buffer if available, + * we should collect stats on how many times it bites + * it's tail */ + DRM_DEBUG("%s\n", __FUNCTION__); + + next_prim_idx = dev_priv->current_prim_idx + 1; + if(next_prim_idx >= MGA_NUM_PRIM_BUFS) + next_prim_idx = 0; + prim_buffer = dev_priv->prim_bufs[next_prim_idx]; + set_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); + + /* In use is cleared in interrupt handler */ + + if(test_and_set_bit(MGA_BUF_IN_USE, &prim_buffer->buffer_status)) { + add_wait_queue(&dev_priv->wait_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + mga_dma_schedule(dev, 0); + if(!test_and_set_bit(MGA_BUF_IN_USE, + &prim_buffer->buffer_status)) + break; + atomic_inc(&dev->total_sleeps); + atomic_inc(&dma->total_missed_sched); + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->wait_queue, &entry); + if(ret) return ret; + } + clear_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); + + /* This primary buffer is now free to use */ + prim_buffer->current_dma_ptr = prim_buffer->head; + prim_buffer->num_dwords = 0; + prim_buffer->sec_used = 0; + prim_buffer->prim_age = dev_priv->next_prim_age++; + if(prim_buffer->prim_age == 0 || prim_buffer->prim_age == 0xffffffff) { + mga_flush_queue(dev); + mga_dma_quiescent(dev); + mga_reset_freelist(dev); + prim_buffer->prim_age = (dev_priv->next_prim_age += 2); + } + + /* Reset all buffer status stuff */ + clear_bit(MGA_BUF_NEEDS_OVERFLOW, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_FORCE_FIRE, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_SWAP_PENDING, &prim_buffer->buffer_status); + + dev_priv->current_prim = prim_buffer; + dev_priv->current_prim_idx = next_prim_idx; + return 0; +} + +/* More dynamic performance decisions */ +static inline int mga_decide_to_fire(drm_device_t *dev) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + + if(test_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status)) { + return 1; + } + + if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { + return 1; + } + + if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { + return 1; + } + + if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) { + if(test_bit(MGA_BUF_SWAP_PENDING, + &dev_priv->next_prim->buffer_status)) { + return 1; + } + } + + if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS / 2) { + if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 8) { + return 1; + } + } + + if(atomic_read(&dev_priv->pending_bufs) >= MGA_NUM_PRIM_BUFS / 2) { + if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 4) { + return 1; + } + } + + return 0; +} + +int mga_dma_schedule(drm_device_t *dev, int locked) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + int retval = 0; + + if (!dev_priv) return -EBUSY; + + if (test_and_set_bit(0, &dev->dma_flag)) { + retval = -EBUSY; + goto sch_out_wakeup; + } + + DRM_DEBUG("%s\n", __FUNCTION__); + + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) || + test_bit(MGA_IN_WAIT, &dev_priv->dispatch_status) || + test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { + locked = 1; + } + + if (!locked && + !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { + clear_bit(0, &dev->dma_flag); + retval = -EBUSY; + goto sch_out_wakeup; + } + + if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) { + /* Fire dma buffer */ + if(mga_decide_to_fire(dev)) { + clear_bit(MGA_BUF_FORCE_FIRE, + &dev_priv->next_prim->buffer_status); + if(dev_priv->current_prim == dev_priv->next_prim) { + /* Schedule overflow for a later time */ + set_bit(MGA_BUF_NEEDS_OVERFLOW, + &dev_priv->next_prim->buffer_status); + } + mga_fire_primary(dev, dev_priv->next_prim); + } else { + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); + } + } + + if (!locked) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } + + clear_bit(0, &dev->dma_flag); + +sch_out_wakeup: + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + atomic_read(&dev_priv->pending_bufs) == 0) { + /* Everything has been processed by the hardware */ + clear_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); + wake_up_interruptible(&dev_priv->flush_queue); + } + + if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->tail->age < dev_priv->last_prim_age) + wake_up_interruptible(&dev_priv->buf_queue); + + return retval; +} + +static void mga_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_prim_buf_t *last_prim_buffer; + + atomic_inc(&dev->total_irq); + if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return; + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); + last_prim_buffer = dev_priv->last_prim; + last_prim_buffer->num_dwords = 0; + last_prim_buffer->sec_used = 0; + dev_priv->sarea_priv->last_dispatch = + dev_priv->last_prim_age = last_prim_buffer->prim_age; + clear_bit(MGA_BUF_IN_USE, &last_prim_buffer->buffer_status); + clear_bit(MGA_BUF_SWAP_PENDING, &last_prim_buffer->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); + atomic_dec(&dev_priv->pending_bufs); + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + wake_up_interruptible(&dev_priv->wait_queue); +} + +static void mga_dma_task_queue(void *device) +{ + mga_dma_schedule((drm_device_t *)device, 0); +} + +int mga_dma_cleanup(drm_device_t *dev) +{ + if(dev->dev_private) { + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + + if (dev->irq) mga_flush_queue(dev); + mga_dma_quiescent(dev); + + if(dev_priv->ioremap) { + int temp = (dev_priv->warp_ucode_size + + dev_priv->primary_size + + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; + + drm_ioremapfree((void *) dev_priv->ioremap, temp); + } + if(dev_priv->status_page != NULL) { + iounmap(dev_priv->status_page); + } + if(dev_priv->real_status_page != 0UL) { + mga_free_page(dev, dev_priv->real_status_page); + } + if(dev_priv->prim_bufs != NULL) { + int i; + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { + if(dev_priv->prim_bufs[i] != NULL) { + drm_free(dev_priv->prim_bufs[i], + sizeof(drm_mga_prim_buf_t), + DRM_MEM_DRIVER); + } + } + drm_free(dev_priv->prim_bufs, sizeof(void *) * + (MGA_NUM_PRIM_BUFS + 1), + DRM_MEM_DRIVER); + } + if(dev_priv->head != NULL) { + mga_freelist_cleanup(dev); + } + + + drm_free(dev->dev_private, sizeof(drm_mga_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; + } + + return 0; +} + +static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { + drm_mga_private_t *dev_priv; + drm_map_t *sarea_map = NULL; + + dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + dev->dev_private = (void *) dev_priv; + + memset(dev_priv, 0, sizeof(drm_mga_private_t)); + + if((init->reserved_map_idx >= dev->map_count) || + (init->buffer_map_idx >= dev->map_count)) { + mga_dma_cleanup(dev); + DRM_DEBUG("reserved_map or buffer_map are invalid\n"); + return -EINVAL; + } + + dev_priv->reserved_map_idx = init->reserved_map_idx; + dev_priv->buffer_map_idx = init->buffer_map_idx; + sarea_map = dev->maplist[0]; + dev_priv->sarea_priv = (drm_mga_sarea_t *) + ((u8 *)sarea_map->handle + + init->sarea_priv_offset); + + /* Scale primary size to the next page */ + dev_priv->chipset = init->chipset; + dev_priv->frontOffset = init->frontOffset; + dev_priv->backOffset = init->backOffset; + dev_priv->depthOffset = init->depthOffset; + dev_priv->textureOffset = init->textureOffset; + dev_priv->textureSize = init->textureSize; + dev_priv->cpp = init->cpp; + dev_priv->sgram = init->sgram; + dev_priv->stride = init->stride; + + dev_priv->mAccess = init->mAccess; + init_waitqueue_head(&dev_priv->flush_queue); + init_waitqueue_head(&dev_priv->buf_queue); + dev_priv->WarpPipe = 0xff000000; + dev_priv->vertexsize = 0; + + DRM_DEBUG("chipset=%d ucode_size=%d backOffset=%x depthOffset=%x\n", + dev_priv->chipset, dev_priv->warp_ucode_size, + dev_priv->backOffset, dev_priv->depthOffset); + DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n", + dev_priv->cpp, dev_priv->sgram, dev_priv->stride, + dev_priv->mAccess); + + memcpy(&dev_priv->WarpIndex, &init->WarpIndex, + sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES); + + if(mga_init_primary_bufs(dev, init) != 0) { + DRM_ERROR("Can not initialize primary buffers\n"); + mga_dma_cleanup(dev); + return -ENOMEM; + } + dev_priv->real_status_page = mga_alloc_page(dev); + if(dev_priv->real_status_page == 0UL) { + mga_dma_cleanup(dev); + DRM_ERROR("Can not allocate status page\n"); + return -ENOMEM; + } + + dev_priv->status_page = + ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page), + PAGE_SIZE); + + if(dev_priv->status_page == NULL) { + mga_dma_cleanup(dev); + DRM_ERROR("Can not remap status page\n"); + return -ENOMEM; + } + + /* Write status page when secend or softrap occurs */ + MGA_WRITE(MGAREG_PRIMPTR, + virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); + + + /* Private is now filled in, initialize the hardware */ + { + PRIMLOCALS; + PRIMGETPTR( dev_priv ); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0x0100); + PRIMOUTREG(MGAREG_SOFTRAP, 0); + /* Poll for the first buffer to insure that + * the status register will be correct + */ + + mga_flush_write_combine(); + MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); + + MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | + PDEA_pagpxfer_enable)); + + while(MGA_READ(MGAREG_DWGSYNC) != 0x0100) ; + } + + if(mga_freelist_init(dev) != 0) { + DRM_ERROR("Could not initialize freelist\n"); + mga_dma_cleanup(dev); + return -ENOMEM; + } + return 0; +} + +int mga_dma_init(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_mga_init_t init; + + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); + + switch(init.func) { + case MGA_INIT_DMA: + return mga_dma_initialize(dev, &init); + case MGA_CLEANUP_DMA: + return mga_dma_cleanup(dev); + } + + return -EINVAL; +} + +int mga_irq_install(drm_device_t *dev, int irq) +{ + int retcode; + + if (!irq) return -EINVAL; + + down(&dev->struct_sem); + if (dev->irq) { + up(&dev->struct_sem); + return -EBUSY; + } + dev->irq = irq; + up(&dev->struct_sem); + + DRM_DEBUG("install irq handler %d\n", irq); + + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + dev->dma->next_buffer = NULL; + dev->dma->next_queue = NULL; + dev->dma->this_buffer = NULL; + dev->tq.next = NULL; + dev->tq.sync = 0; + dev->tq.routine = mga_dma_task_queue; + dev->tq.data = dev; + + /* Before installing handler */ + MGA_WRITE(MGAREG_IEN, 0); + /* Install handler */ + if ((retcode = request_irq(dev->irq, + mga_dma_service, + SA_SHIRQ, + dev->devname, + dev))) { + down(&dev->struct_sem); + dev->irq = 0; + up(&dev->struct_sem); + return retcode; + } + /* After installing handler */ + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); + MGA_WRITE(MGAREG_IEN, 0x00000001); + return 0; +} + +int mga_irq_uninstall(drm_device_t *dev) +{ + int irq; + + down(&dev->struct_sem); + irq = dev->irq; + dev->irq = 0; + up(&dev->struct_sem); + + if (!irq) return -EINVAL; + DRM_DEBUG("remove irq handler %d\n", irq); + MGA_WRITE(MGAREG_ICLEAR, 0x00000001); + MGA_WRITE(MGAREG_IEN, 0); + free_irq(irq, dev); + return 0; +} + +int mga_control(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_control_t ctl; + + copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); + + DRM_DEBUG("%s\n", __FUNCTION__); + + switch (ctl.func) { + case DRM_INST_HANDLER: + return mga_irq_install(dev, ctl.irq); + case DRM_UNINST_HANDLER: + return mga_irq_uninstall(dev); + default: + return -EINVAL; + } +} + +static int mga_flush_queue(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + int ret = 0; + + if(!dev_priv) return 0; + + if(dev_priv->next_prim->num_dwords != 0) { + add_wait_queue(&dev_priv->flush_queue, &entry); + if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status)) + DRM_ERROR("Incorrect mga_flush_queue logic\n"); + set_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); + mga_dma_schedule(dev, 0); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!test_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status)) + break; + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + clear_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status); + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + } + return ret; +} + +/* Must be called with the lock held */ +void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if(dev->dev_private == NULL) return; + if(dma->buflist == NULL) return; + + DRM_DEBUG("buf_count=%d\n", dma->buf_count); + + mga_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + + /* Only buffers that need to get reclaimed ever + * get set to free + */ + if (buf->pid == pid && buf_priv) { + if(buf_priv->my_freelist->age == MGA_BUF_USED) + buf_priv->my_freelist->age = MGA_BUF_FREE; + } + } +} + +int mga_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; + + DRM_DEBUG("%s\n", __FUNCTION__); + 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 (lock.context < 0) { + return -EINVAL; + } + + /* Only one queue: + */ + + if (!ret) { + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + 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); + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + + if (!ret) { + if (lock.flags & _DRM_LOCK_QUIESCENT) { + DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); + mga_flush_queue(dev); + mga_dma_quiescent(dev); + } + } + + if (ret) DRM_DEBUG("%d %s\n", lock.context, + ret ? "interrupted" : "has lock"); + return ret; +} + +int mga_flush_ioctl(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; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + if(lock.flags & _DRM_LOCK_FLUSH || lock.flags & _DRM_LOCK_FLUSH_ALL) { + drm_mga_prim_buf_t *temp_buf; + + temp_buf = dev_priv->current_prim; + + if(temp_buf && temp_buf->num_dwords) { + set_bit(MGA_BUF_FORCE_FIRE, &temp_buf->buffer_status); + mga_advance_primary(dev); + } + mga_dma_schedule(dev, 1); + } + if(lock.flags & _DRM_LOCK_QUIESCENT) { + mga_flush_queue(dev); + mga_dma_quiescent(dev); + } + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/mga_drm.h linux/drivers/char/drm/mga_drm.h --- v2.2.17/drivers/char/drm/mga_drm.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/mga_drm.h Tue Nov 28 17:33:24 2000 @@ -0,0 +1,274 @@ +/* mga_drm.h -- Public header for the Matrox g200/g400 driver -*- linux-c -*- + * Created: Tue Jan 25 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Jeff Hartmann + * Keith Whitwell + * + */ + +#ifndef _MGA_DRM_H_ +#define _MGA_DRM_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmMga.h) + */ +#ifndef _MGA_DEFINES_ +#define _MGA_DEFINES_ + +#define MGA_F 0x1 /* fog */ +#define MGA_A 0x2 /* alpha */ +#define MGA_S 0x4 /* specular */ +#define MGA_T2 0x8 /* multitexture */ + +#define MGA_WARP_TGZ 0 +#define MGA_WARP_TGZF (MGA_F) +#define MGA_WARP_TGZA (MGA_A) +#define MGA_WARP_TGZAF (MGA_F|MGA_A) +#define MGA_WARP_TGZS (MGA_S) +#define MGA_WARP_TGZSF (MGA_S|MGA_F) +#define MGA_WARP_TGZSA (MGA_S|MGA_A) +#define MGA_WARP_TGZSAF (MGA_S|MGA_F|MGA_A) +#define MGA_WARP_T2GZ (MGA_T2) +#define MGA_WARP_T2GZF (MGA_T2|MGA_F) +#define MGA_WARP_T2GZA (MGA_T2|MGA_A) +#define MGA_WARP_T2GZAF (MGA_T2|MGA_A|MGA_F) +#define MGA_WARP_T2GZS (MGA_T2|MGA_S) +#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F) +#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A) +#define MGA_WARP_T2GZSAF (MGA_T2|MGA_S|MGA_F|MGA_A) + +#define MGA_MAX_G400_PIPES 16 +#define MGA_MAX_G200_PIPES 8 /* no multitex */ +#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES + +#define MGA_CARD_TYPE_G200 1 +#define MGA_CARD_TYPE_G400 2 + +#define MGA_FRONT 0x1 +#define MGA_BACK 0x2 +#define MGA_DEPTH 0x4 + +/* 3d state excluding texture units: + */ +#define MGA_CTXREG_DSTORG 0 /* validated */ +#define MGA_CTXREG_MACCESS 1 +#define MGA_CTXREG_PLNWT 2 +#define MGA_CTXREG_DWGCTL 3 +#define MGA_CTXREG_ALPHACTRL 4 +#define MGA_CTXREG_FOGCOLOR 5 +#define MGA_CTXREG_WFLAG 6 +#define MGA_CTXREG_TDUAL0 7 +#define MGA_CTXREG_TDUAL1 8 +#define MGA_CTXREG_FCOL 9 +#define MGA_CTXREG_STENCIL 10 +#define MGA_CTXREG_STENCILCTL 11 +#define MGA_CTX_SETUP_SIZE 12 + +/* 2d state + */ +#define MGA_2DREG_PITCH 0 +#define MGA_2D_SETUP_SIZE 1 + +/* Each texture unit has a state: + */ +#define MGA_TEXREG_CTL 0 +#define MGA_TEXREG_CTL2 1 +#define MGA_TEXREG_FILTER 2 +#define MGA_TEXREG_BORDERCOL 3 +#define MGA_TEXREG_ORG 4 /* validated */ +#define MGA_TEXREG_ORG1 5 +#define MGA_TEXREG_ORG2 6 +#define MGA_TEXREG_ORG3 7 +#define MGA_TEXREG_ORG4 8 +#define MGA_TEXREG_WIDTH 9 +#define MGA_TEXREG_HEIGHT 10 +#define MGA_TEX_SETUP_SIZE 11 + +/* What needs to be changed for the current vertex dma buffer? + */ +#define MGA_UPLOAD_CTX 0x1 +#define MGA_UPLOAD_TEX0 0x2 +#define MGA_UPLOAD_TEX1 0x4 +#define MGA_UPLOAD_PIPE 0x8 +#define MGA_UPLOAD_TEX0IMAGE 0x10 /* handled client-side */ +#define MGA_UPLOAD_TEX1IMAGE 0x20 /* handled client-side */ +#define MGA_UPLOAD_2D 0x40 +#define MGA_WAIT_AGE 0x80 /* handled client-side */ +#define MGA_UPLOAD_CLIPRECTS 0x100 /* handled client-side */ +#define MGA_DMA_FLUSH 0x200 /* set when someone gets the lock + quiescent */ + +/* 32 buffers of 64k each, total 2 meg. + */ +#define MGA_DMA_BUF_ORDER 16 +#define MGA_DMA_BUF_SZ (1< + * Jeff Hartmann + * + * + */ + +#include +#include "drmP.h" +#include "mga_drv.h" + +#include + +static void __attribute__((unused)) unused(void) +{ + agp_enable(0); +} + +#define MGA_NAME "mga" +#define MGA_DESC "Matrox G200/G400" +#define MGA_DATE "20000910" +#define MGA_MAJOR 2 +#define MGA_MINOR 0 +#define MGA_PATCHLEVEL 0 + +static drm_device_t mga_device; +drm_ctx_t mga_res_ctx; + +static struct file_operations mga_fops = { +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ + owner: THIS_MODULE, +#endif + open: mga_open, + flush: drm_flush, + release: mga_release, + ioctl: mga_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +static struct miscdevice mga_misc = { + minor: MISC_DYNAMIC_MINOR, + name: MGA_NAME, + fops: &mga_fops, +}; + +static drm_ioctl_desc_t mga_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { mga_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_CONTROL)] = { mga_control, 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_BUFS)] = { mga_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { mga_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { mga_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { mga_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { mga_freebufs, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { mga_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { mga_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { mga_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { mga_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { mga_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { mga_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { mga_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_DMA)] = { mga_dma, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { mga_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { mga_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)] = { mga_dma_init, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)] = { mga_swap_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)] = { mga_clear_bufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_iload, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_vertex, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)] = { mga_flush_ioctl, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices, 1, 0 }, +}; + +#define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) + +#ifdef MODULE +static char *mga = NULL; +#endif + +MODULE_AUTHOR("VA Linux Systems, Inc."); +MODULE_DESCRIPTION("Matrox g200/g400"); +MODULE_PARM(mga, "s"); + +#ifndef MODULE +/* mga_options 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. + */ + +static int __init mga_options(char *str) +{ + drm_parse_options(str); + return 1; +} + +__setup("mga=", mga_options); +#endif + +static int mga_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); + + drm_dma_setup(dev); + + 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_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); + + 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 mga_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"); + + if (dev->dev_private) mga_dma_cleanup(dev); + if (dev->irq) mga_irq_uninstall(dev); + + 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 AGP information */ + if (dev->agp) { + drm_agp_mem_t *entry; + drm_agp_mem_t *nexte; + + /* Remove AGP resources, but leave dev->agp + intact until cleanup is called. */ + for (entry = dev->agp->memory; entry; entry = nexte) { + nexte = entry->next; + if (entry->bound) drm_unbind_agp(entry->memory); + drm_free_agp(entry->memory, entry->pages); + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + } + dev->agp->memory = NULL; + + if (dev->agp->acquired && drm_agp.release) + (*drm_agp.release)(); + + dev->agp->acquired = 0; + dev->agp->enabled = 0; + } + /* 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; + case _DRM_AGP: + 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->queuelist) { + for (i = 0; i < dev->queue_count; i++) { + drm_waitlist_destroy(&dev->queuelist[i]->waitlist); + if (dev->queuelist[i]) { + drm_free(dev->queuelist[i], + sizeof(*dev->queuelist[0]), + DRM_MEM_QUEUES); + dev->queuelist[i] = NULL; + } + } + drm_free(dev->queuelist, + dev->queue_slots * sizeof(*dev->queuelist), + DRM_MEM_QUEUES); + dev->queuelist = NULL; + } + + drm_dma_takedown(dev); + + dev->queue_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; +} + +/* mga_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +static int mga_init(void) +{ + int retcode; + drm_device_t *dev = &mga_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(mga); +#endif + DRM_DEBUG("doing misc_register\n"); + if ((retcode = misc_register(&mga_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", MGA_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, mga_misc.minor); + dev->name = MGA_NAME; + + DRM_DEBUG("doing mem init\n"); + drm_mem_init(); + DRM_DEBUG("doing proc init\n"); + drm_proc_init(dev); + DRM_DEBUG("doing agp init\n"); + dev->agp = drm_agp_init(); + if(dev->agp == NULL) { + DRM_INFO("The mga drm module requires the agpgart module" + " to function correctly\nPlease load the agpgart" + " module before you load the mga module\n"); + drm_proc_cleanup(); + misc_deregister(&mga_misc); + mga_takedown(dev); + return -ENOMEM; + } +#ifdef CONFIG_MTRR + dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024 * 1024, + MTRR_TYPE_WRCOMB, + 1); +#endif + DRM_DEBUG("doing ctxbitmap init\n"); + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&mga_misc); + mga_takedown(dev); + return retcode; + } + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + MGA_NAME, + MGA_MAJOR, + MGA_MINOR, + MGA_PATCHLEVEL, + MGA_DATE, + mga_misc.minor); + + return 0; +} + +/* mga_cleanup is called via cleanup_module at module unload time. */ + +static void mga_cleanup(void) +{ + drm_device_t *dev = &mga_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&mga_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + drm_ctxbitmap_cleanup(dev); +#ifdef CONFIG_MTRR + if(dev->agp && dev->agp->agp_mtrr) { + int retval; + retval = mtrr_del(dev->agp->agp_mtrr, + dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * 1024*1024); + DRM_DEBUG("mtrr_del = %d\n", retval); + } +#endif + + mga_takedown(dev); + if (dev->agp) { + drm_agp_uninit(); + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +} + +module_init(mga_init); +module_exit(mga_cleanup); + + +int mga_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 = MGA_MAJOR; + version.version_minor = MGA_MINOR; + version.version_patchlevel = MGA_PATCHLEVEL; + + DRM_COPY(version.name, MGA_NAME); + DRM_COPY(version.date, MGA_DATE); + DRM_COPY(version.desc, MGA_DESC); + + copy_to_user_ret((drm_version_t *)arg, + &version, + sizeof(version), + -EFAULT); + return 0; +} + +int mga_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &mga_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return mga_setup(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +int mga_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + int retcode = 0; + + lock_kernel(); + dev = priv->dev; + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + mga_reclaim_buffers(dev, priv->pid); + DRM_INFO("Process %d dead (ctx %d, d_s = 0x%02x)\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock), + dev->dev_private ? + ((drm_mga_private_t *)dev->dev_private) + ->dispatch_status + : 0); + + if (dev->dev_private) + ((drm_mga_private_t *)dev->dev_private) + ->dispatch_status &= MGA_IN_DISPATCH; + + drm_lock_free(dev, + &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + } else if (dev->lock.hw_lock) { + /* The lock is required to reclaim buffers */ + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + retcode = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.pid = priv->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + /* Contention */ + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + retcode = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + if(!retcode) { + mga_reclaim_buffers(dev, priv->pid); + if (dev->dev_private) + ((drm_mga_private_t *)dev->dev_private) + ->dispatch_status &= MGA_IN_DISPATCH; + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + } + } + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->remove_auth_on_close == 1) { + drm_file_t *temp = dev->file_first; + while(temp) { + temp->authenticated = 0; + temp = temp->next; + } + } + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + 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); + unlock_kernel(); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return mga_takedown(dev); + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return retcode; +} + + +/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int mga_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 >= MGA_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &mga_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function: pid = %d, cmd = 0x%02x," + " nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, + priv->authenticated); + 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 mga_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); + mga_dma_schedule(dev, 1); + + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/mga_drv.h linux/drivers/char/drm/mga_drv.h --- v2.2.17/drivers/char/drm/mga_drv.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/mga_drv.h Tue Nov 28 17:33:24 2000 @@ -0,0 +1,519 @@ +/* mga_drv.h -- Private header for the Matrox g200/g400 driver -*- linux-c -*- + * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#ifndef _MGA_DRV_H_ +#define _MGA_DRV_H_ + +#define MGA_BUF_IN_USE 0 +#define MGA_BUF_SWAP_PENDING 1 +#define MGA_BUF_FORCE_FIRE 2 +#define MGA_BUF_NEEDS_OVERFLOW 3 + +typedef struct { + u32 buffer_status; + int num_dwords; + int max_dwords; + u32 *current_dma_ptr; + u32 *head; + u32 phys_head; + unsigned int prim_age; + int sec_used; + int idx; +} drm_mga_prim_buf_t; + +typedef struct _drm_mga_freelist { + __volatile__ unsigned int age; + drm_buf_t *buf; + struct _drm_mga_freelist *next; + struct _drm_mga_freelist *prev; +} drm_mga_freelist_t; + +#define MGA_IN_DISPATCH 0 +#define MGA_IN_FLUSH 1 +#define MGA_IN_WAIT 2 +#define MGA_IN_GETBUF 3 + +typedef struct _drm_mga_private { + u32 dispatch_status; + unsigned int next_prim_age; + __volatile__ unsigned int last_prim_age; + int reserved_map_idx; + int buffer_map_idx; + drm_mga_sarea_t *sarea_priv; + int primary_size; + int warp_ucode_size; + int chipset; + unsigned int frontOffset; + unsigned int backOffset; + unsigned int depthOffset; + unsigned int textureOffset; + unsigned int textureSize; + int cpp; + unsigned int stride; + int sgram; + int use_agp; + drm_mga_warp_index_t WarpIndex[MGA_MAX_G400_PIPES]; + unsigned int WarpPipe; + unsigned int vertexsize; + atomic_t pending_bufs; + void *status_page; + unsigned long real_status_page; + u8 *ioremap; + drm_mga_prim_buf_t **prim_bufs; + drm_mga_prim_buf_t *next_prim; + drm_mga_prim_buf_t *last_prim; + drm_mga_prim_buf_t *current_prim; + int current_prim_idx; + drm_mga_freelist_t *head; + drm_mga_freelist_t *tail; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ + wait_queue_head_t wait_queue; /* Processes waiting until interrupt */ + wait_queue_head_t buf_queue; /* Processes waiting for a free buf */ + /* Some validated register values: + */ + u32 mAccess; +} drm_mga_private_t; + + /* mga_drv.c */ +extern int mga_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_open(struct inode *inode, struct file *filp); +extern int mga_release(struct inode *inode, struct file *filp); +extern int mga_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* mga_dma.c */ +extern int mga_dma_schedule(drm_device_t *dev, int locked); +extern int mga_dma(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_irq_install(drm_device_t *dev, int irq); +extern int mga_irq_uninstall(drm_device_t *dev); +extern int mga_control(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +/* mga_dma_init does init and release */ +extern int mga_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_dma_cleanup(drm_device_t *dev); +extern int mga_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern unsigned int mga_create_sync_tag(drm_device_t *dev); +extern drm_buf_t *mga_freelist_get(drm_device_t *dev); +extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf); +extern int mga_advance_primary(drm_device_t *dev); +extern void mga_reclaim_buffers(drm_device_t *dev, pid_t pid); + + + /* mga_bufs.c */ +extern int mga_addbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_infobufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_markbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_freebufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_mapbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_addmap(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + /* mga_state.c */ +extern int mga_clear_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_swap_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_iload(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_indices(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + /* mga_context.c */ +extern int mga_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int mga_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int mga_context_switch(drm_device_t *dev, int old, int new); +extern int mga_context_switch_complete(drm_device_t *dev, int new); + +#define mga_flush_write_combine() mb() + +typedef enum { + TT_GENERAL, + TT_BLIT, + TT_VECTOR, + TT_VERTEX +} transferType_t; + +typedef struct { + drm_mga_freelist_t *my_freelist; + int discard; + int dispatched; +} drm_mga_buf_priv_t; + +#define DWGREG0 0x1c00 +#define DWGREG0_END 0x1dff +#define DWGREG1 0x2c00 +#define DWGREG1_END 0x2dff + +#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END) +#define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2) +#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) +#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) + +#define MGA_VERBOSE 0 +#define MGA_NUM_PRIM_BUFS 8 + +#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ + int outcount, num_dwords + +#define PRIM_OVERFLOW(dev, dev_priv, length) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if( test_bit(MGA_BUF_NEEDS_OVERFLOW, &tmp_buf->buffer_status)) { \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + tmp_buf = dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length || \ + tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ + set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + tmp_buf = dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + } \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMGETPTR in %s\n", __FUNCTION__); \ + dma_ptr = tmp_buf->current_dma_ptr; \ + num_dwords = tmp_buf->num_dwords; \ + phys_head = tmp_buf->phys_head; \ + outcount = 0; \ +} while(0) + +#define PRIMGETPTR(dev_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMGETPTR in %s\n", __FUNCTION__); \ + dma_ptr = tmp_buf->current_dma_ptr; \ + num_dwords = tmp_buf->num_dwords; \ + phys_head = tmp_buf->phys_head; \ + outcount = 0; \ +} while(0) + +#define PRIMPTR(prim_buf) do { \ + if(MGA_VERBOSE) \ + DRM_DEBUG("PRIMPTR in %s\n", __FUNCTION__); \ + dma_ptr = prim_buf->current_dma_ptr; \ + num_dwords = prim_buf->num_dwords; \ + phys_head = prim_buf->phys_head; \ + outcount = 0; \ +} while(0) + +#define PRIMFINISH(prim_buf) do { \ + if (MGA_VERBOSE) { \ + DRM_DEBUG( "PRIMFINISH in %s\n", __FUNCTION__); \ + if (outcount & 3) \ + DRM_DEBUG(" --- truncation\n"); \ + } \ + prim_buf->num_dwords = num_dwords; \ + prim_buf->current_dma_ptr = dma_ptr; \ +} while(0) + +#define PRIMADVANCE(dev_priv) do { \ +drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if (MGA_VERBOSE) { \ + DRM_DEBUG("PRIMADVANCE in %s\n", __FUNCTION__); \ + if (outcount & 3) \ + DRM_DEBUG(" --- truncation\n"); \ + } \ + tmp_buf->num_dwords = num_dwords; \ + tmp_buf->current_dma_ptr = dma_ptr; \ +} while (0) + +#define PRIMUPDATE(dev_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + tmp_buf->sec_used++; \ +} while (0) + +#define AGEBUF(dev_priv, buf_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + buf_priv->my_freelist->age = tmp_buf->prim_age; \ +} while (0) + + +#define PRIMOUTREG(reg, val) do { \ + tempIndex[outcount]=ADRINDEX(reg); \ + dma_ptr[1+outcount] = val; \ + if (MGA_VERBOSE) \ + DRM_DEBUG(" PRIMOUT %d: 0x%x -- 0x%x\n", \ + num_dwords + 1 + outcount, ADRINDEX(reg), val); \ + if( ++outcount == 4) { \ + outcount = 0; \ + dma_ptr[0] = *(unsigned long *)tempIndex; \ + dma_ptr+=5; \ + num_dwords += 5; \ + } \ +}while (0) + +/* A reduced set of the mga registers. + */ + +#define MGAREG_MGA_EXEC 0x0100 +#define MGAREG_ALPHACTRL 0x2c7c +#define MGAREG_AR0 0x1c60 +#define MGAREG_AR1 0x1c64 +#define MGAREG_AR2 0x1c68 +#define MGAREG_AR3 0x1c6c +#define MGAREG_AR4 0x1c70 +#define MGAREG_AR5 0x1c74 +#define MGAREG_AR6 0x1c78 +#define MGAREG_CXBNDRY 0x1c80 +#define MGAREG_CXLEFT 0x1ca0 +#define MGAREG_CXRIGHT 0x1ca4 +#define MGAREG_DMAPAD 0x1c54 +#define MGAREG_DSTORG 0x2cb8 +#define MGAREG_DWGCTL 0x1c00 +#define MGAREG_DWGSYNC 0x2c4c +#define MGAREG_FCOL 0x1c24 +#define MGAREG_FIFOSTATUS 0x1e10 +#define MGAREG_FOGCOL 0x1cf4 +#define MGAREG_FXBNDRY 0x1c84 +#define MGAREG_FXLEFT 0x1ca8 +#define MGAREG_FXRIGHT 0x1cac +#define MGAREG_ICLEAR 0x1e18 +#define MGAREG_IEN 0x1e1c +#define MGAREG_LEN 0x1c5c +#define MGAREG_MACCESS 0x1c04 +#define MGAREG_PITCH 0x1c8c +#define MGAREG_PLNWT 0x1c1c +#define MGAREG_PRIMADDRESS 0x1e58 +#define MGAREG_PRIMEND 0x1e5c +#define MGAREG_PRIMPTR 0x1e50 +#define MGAREG_SECADDRESS 0x2c40 +#define MGAREG_SECEND 0x2c44 +#define MGAREG_SETUPADDRESS 0x2cd0 +#define MGAREG_SETUPEND 0x2cd4 +#define MGAREG_SOFTRAP 0x2c48 +#define MGAREG_SRCORG 0x2cb4 +#define MGAREG_STATUS 0x1e14 +#define MGAREG_STENCIL 0x2cc8 +#define MGAREG_STENCILCTL 0x2ccc +#define MGAREG_TDUALSTAGE0 0x2cf8 +#define MGAREG_TDUALSTAGE1 0x2cfc +#define MGAREG_TEXBORDERCOL 0x2c5c +#define MGAREG_TEXCTL 0x2c30 +#define MGAREG_TEXCTL2 0x2c3c +#define MGAREG_TEXFILTER 0x2c58 +#define MGAREG_TEXHEIGHT 0x2c2c +#define MGAREG_TEXORG 0x2c24 +#define MGAREG_TEXORG1 0x2ca4 +#define MGAREG_TEXORG2 0x2ca8 +#define MGAREG_TEXORG3 0x2cac +#define MGAREG_TEXORG4 0x2cb0 +#define MGAREG_TEXTRANS 0x2c34 +#define MGAREG_TEXTRANSHIGH 0x2c38 +#define MGAREG_TEXWIDTH 0x2c28 +#define MGAREG_WACCEPTSEQ 0x1dd4 +#define MGAREG_WCODEADDR 0x1e6c +#define MGAREG_WFLAG 0x1dc4 +#define MGAREG_WFLAG1 0x1de0 +#define MGAREG_WFLAGNB 0x1e64 +#define MGAREG_WFLAGNB1 0x1e08 +#define MGAREG_WGETMSB 0x1dc8 +#define MGAREG_WIADDR 0x1dc0 +#define MGAREG_WIADDR2 0x1dd8 +#define MGAREG_WMISC 0x1e70 +#define MGAREG_WVRTXSZ 0x1dcc +#define MGAREG_YBOT 0x1c9c +#define MGAREG_YDST 0x1c90 +#define MGAREG_YDSTLEN 0x1c88 +#define MGAREG_YDSTORG 0x1c94 +#define MGAREG_YTOP 0x1c98 +#define MGAREG_ZORG 0x1c0c + +/* Warp registers */ +#define MGAREG_WR0 0x2d00 +#define MGAREG_WR1 0x2d04 +#define MGAREG_WR2 0x2d08 +#define MGAREG_WR3 0x2d0c +#define MGAREG_WR4 0x2d10 +#define MGAREG_WR5 0x2d14 +#define MGAREG_WR6 0x2d18 +#define MGAREG_WR7 0x2d1c +#define MGAREG_WR8 0x2d20 +#define MGAREG_WR9 0x2d24 +#define MGAREG_WR10 0x2d28 +#define MGAREG_WR11 0x2d2c +#define MGAREG_WR12 0x2d30 +#define MGAREG_WR13 0x2d34 +#define MGAREG_WR14 0x2d38 +#define MGAREG_WR15 0x2d3c +#define MGAREG_WR16 0x2d40 +#define MGAREG_WR17 0x2d44 +#define MGAREG_WR18 0x2d48 +#define MGAREG_WR19 0x2d4c +#define MGAREG_WR20 0x2d50 +#define MGAREG_WR21 0x2d54 +#define MGAREG_WR22 0x2d58 +#define MGAREG_WR23 0x2d5c +#define MGAREG_WR24 0x2d60 +#define MGAREG_WR25 0x2d64 +#define MGAREG_WR26 0x2d68 +#define MGAREG_WR27 0x2d6c +#define MGAREG_WR28 0x2d70 +#define MGAREG_WR29 0x2d74 +#define MGAREG_WR30 0x2d78 +#define MGAREG_WR31 0x2d7c +#define MGAREG_WR32 0x2d80 +#define MGAREG_WR33 0x2d84 +#define MGAREG_WR34 0x2d88 +#define MGAREG_WR35 0x2d8c +#define MGAREG_WR36 0x2d90 +#define MGAREG_WR37 0x2d94 +#define MGAREG_WR38 0x2d98 +#define MGAREG_WR39 0x2d9c +#define MGAREG_WR40 0x2da0 +#define MGAREG_WR41 0x2da4 +#define MGAREG_WR42 0x2da8 +#define MGAREG_WR43 0x2dac +#define MGAREG_WR44 0x2db0 +#define MGAREG_WR45 0x2db4 +#define MGAREG_WR46 0x2db8 +#define MGAREG_WR47 0x2dbc +#define MGAREG_WR48 0x2dc0 +#define MGAREG_WR49 0x2dc4 +#define MGAREG_WR50 0x2dc8 +#define MGAREG_WR51 0x2dcc +#define MGAREG_WR52 0x2dd0 +#define MGAREG_WR53 0x2dd4 +#define MGAREG_WR54 0x2dd8 +#define MGAREG_WR55 0x2ddc +#define MGAREG_WR56 0x2de0 +#define MGAREG_WR57 0x2de4 +#define MGAREG_WR58 0x2de8 +#define MGAREG_WR59 0x2dec +#define MGAREG_WR60 0x2df0 +#define MGAREG_WR61 0x2df4 +#define MGAREG_WR62 0x2df8 +#define MGAREG_WR63 0x2dfc + +#define PDEA_pagpxfer_enable 0x2 + +#define WIA_wmode_suspend 0x0 +#define WIA_wmode_start 0x3 +#define WIA_wagp_agp 0x4 + +#define DC_opcod_line_open 0x0 +#define DC_opcod_autoline_open 0x1 +#define DC_opcod_line_close 0x2 +#define DC_opcod_autoline_close 0x3 +#define DC_opcod_trap 0x4 +#define DC_opcod_texture_trap 0x6 +#define DC_opcod_bitblt 0x8 +#define DC_opcod_iload 0x9 +#define DC_atype_rpl 0x0 +#define DC_atype_rstr 0x10 +#define DC_atype_zi 0x30 +#define DC_atype_blk 0x40 +#define DC_atype_i 0x70 +#define DC_linear_xy 0x0 +#define DC_linear_linear 0x80 +#define DC_zmode_nozcmp 0x0 +#define DC_zmode_ze 0x200 +#define DC_zmode_zne 0x300 +#define DC_zmode_zlt 0x400 +#define DC_zmode_zlte 0x500 +#define DC_zmode_zgt 0x600 +#define DC_zmode_zgte 0x700 +#define DC_solid_disable 0x0 +#define DC_solid_enable 0x800 +#define DC_arzero_disable 0x0 +#define DC_arzero_enable 0x1000 +#define DC_sgnzero_disable 0x0 +#define DC_sgnzero_enable 0x2000 +#define DC_shftzero_disable 0x0 +#define DC_shftzero_enable 0x4000 +#define DC_bop_SHIFT 16 +#define DC_trans_SHIFT 20 +#define DC_bltmod_bmonolef 0x0 +#define DC_bltmod_bmonowf 0x8000000 +#define DC_bltmod_bplan 0x2000000 +#define DC_bltmod_bfcol 0x4000000 +#define DC_bltmod_bu32bgr 0x6000000 +#define DC_bltmod_bu32rgb 0xe000000 +#define DC_bltmod_bu24bgr 0x16000000 +#define DC_bltmod_bu24rgb 0x1e000000 +#define DC_pattern_disable 0x0 +#define DC_pattern_enable 0x20000000 +#define DC_transc_disable 0x0 +#define DC_transc_enable 0x40000000 +#define DC_clipdis_disable 0x0 +#define DC_clipdis_enable 0x80000000 + +#define SETADD_mode_vertlist 0x0 + + +#define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ + DC_solid_enable | DC_transc_enable) + + +#define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy | \ + DC_solid_disable | DC_arzero_disable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_bltmod_bfcol | \ + DC_pattern_disable | DC_transc_disable | \ + DC_clipdis_enable) \ + +#define MGA_FLUSH_CMD (DC_opcod_texture_trap | (0xF << DC_trans_SHIFT) |\ + DC_arzero_enable | DC_sgnzero_enable | \ + DC_atype_i) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/mga_state.c linux/drivers/char/drm/mga_state.c --- v2.2.17/drivers/char/drm/mga_state.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/mga_state.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,1039 @@ +/* mga_state.c -- State support for mga g200/g400 -*- linux-c -*- + * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Jeff Hartmann + * Keith Whitwell + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "mga_drv.h" +#include "drm.h" + +/* If you change the functions to set state, PLEASE + * change these values + */ + +#define MGAEMITCLIP_SIZE 10 +#define MGAEMITCTX_SIZE 20 +#define MGAG200EMITTEX_SIZE 20 +#define MGAG400EMITTEX0_SIZE 30 +#define MGAG400EMITTEX1_SIZE 25 +#define MGAG400EMITPIPE_SIZE 50 +#define MGAG200EMITPIPE_SIZE 15 + +#define MAX_STATE_SIZE ((MGAEMITCLIP_SIZE * MGA_NR_SAREA_CLIPRECTS) + \ + MGAEMITCTX_SIZE + MGAG400EMITTEX0_SIZE + \ + MGAG400EMITTEX1_SIZE + MGAG400EMITPIPE_SIZE) + +static void mgaEmitClipRect(drm_mga_private_t * dev_priv, + drm_clip_rect_t * box) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + PRIMLOCALS; + + /* This takes 10 dwords */ + PRIMGETPTR(dev_priv); + + /* Force reset of dwgctl on G400 (eliminates clip disable bit) */ + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { +#if 0 + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); +#else + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000); +#endif + } + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_CXBNDRY, ((box->x2) << 16) | (box->x1)); + PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / dev_priv->cpp); + PRIMOUTREG(MGAREG_YBOT, box->y2 * dev_priv->stride / dev_priv->cpp); + + PRIMADVANCE(dev_priv); +} + +static void mgaEmitContext(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + PRIMLOCALS; + + /* This takes a max of 20 dwords */ + PRIMGETPTR(dev_priv); + + PRIMOUTREG(MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG]); + PRIMOUTREG(MGAREG_MACCESS, regs[MGA_CTXREG_MACCESS]); + PRIMOUTREG(MGAREG_PLNWT, regs[MGA_CTXREG_PLNWT]); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + + PRIMOUTREG(MGAREG_ALPHACTRL, regs[MGA_CTXREG_ALPHACTRL]); + PRIMOUTREG(MGAREG_FOGCOL, regs[MGA_CTXREG_FOGCOLOR]); + PRIMOUTREG(MGAREG_WFLAG, regs[MGA_CTXREG_WFLAG]); + PRIMOUTREG(MGAREG_ZORG, dev_priv->depthOffset); /* invarient */ + + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + PRIMOUTREG(MGAREG_WFLAG1, regs[MGA_CTXREG_WFLAG]); + PRIMOUTREG(MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0]); + PRIMOUTREG(MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1]); + PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]); + + PRIMOUTREG(MGAREG_STENCIL, regs[MGA_CTXREG_STENCIL]); + PRIMOUTREG(MGAREG_STENCILCTL, regs[MGA_CTXREG_STENCILCTL]); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + } else { + PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + } + + PRIMADVANCE(dev_priv); +} + +static void mgaG200EmitTex(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + PRIMGETPTR(dev_priv); + + /* This takes 20 dwords */ + + PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2]); + PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]); + PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]); + PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]); + + PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]); + PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]); + PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]); + PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]); + + PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]); + PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]); + PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]); + PRIMOUTREG(MGAREG_WR24, regs[MGA_TEXREG_WIDTH]); + + PRIMOUTREG(MGAREG_WR34, regs[MGA_TEXREG_HEIGHT]); + PRIMOUTREG(MGAREG_TEXTRANS, 0xffff); + PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff); + PRIMOUTREG(MGAREG_DMAPAD, 0); + + PRIMADVANCE(dev_priv); +} + +#define TMC_dualtex_enable 0x80 + +static void mgaG400EmitTex0(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[0]; + PRIMLOCALS; + + PRIMGETPTR(dev_priv); + + /* This takes 30 dwords */ + + PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000); + PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]); + PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]); + PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]); + + PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]); + PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]); + PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]); + PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]); + + PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]); + PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]); + PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]); + PRIMOUTREG(MGAREG_WR49, 0); + + PRIMOUTREG(MGAREG_WR57, 0); + PRIMOUTREG(MGAREG_WR53, 0); + PRIMOUTREG(MGAREG_WR61, 0); + PRIMOUTREG(MGAREG_WR52, 0x40); + + PRIMOUTREG(MGAREG_WR60, 0x40); + PRIMOUTREG(MGAREG_WR54, regs[MGA_TEXREG_WIDTH] | 0x40); + PRIMOUTREG(MGAREG_WR62, regs[MGA_TEXREG_HEIGHT] | 0x40); + PRIMOUTREG(MGAREG_DMAPAD, 0); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_TEXTRANS, 0xffff); + PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff); + + PRIMADVANCE(dev_priv); +} + +#define TMC_map1_enable 0x80000000 + +static void mgaG400EmitTex1(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->TexState[1]; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + PRIMGETPTR(dev_priv); + + /* This takes 25 dwords */ + + PRIMOUTREG(MGAREG_TEXCTL2, + regs[MGA_TEXREG_CTL2] | TMC_map1_enable | 0x00008000); + PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]); + PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]); + PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]); + + PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]); + PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]); + PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]); + PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]); + + PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]); + PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]); + PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]); + PRIMOUTREG(MGAREG_WR49, 0); + + PRIMOUTREG(MGAREG_WR57, 0); + PRIMOUTREG(MGAREG_WR53, 0); + PRIMOUTREG(MGAREG_WR61, 0); + PRIMOUTREG(MGAREG_WR52, regs[MGA_TEXREG_WIDTH] | 0x40); + + PRIMOUTREG(MGAREG_WR60, regs[MGA_TEXREG_HEIGHT] | 0x40); + PRIMOUTREG(MGAREG_TEXTRANS, 0xffff); + PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff); + PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000); + + PRIMADVANCE(dev_priv); +} + +#define MAGIC_FPARAM_HEX_VALUE 0x46480000 +/* This is the hex value of 12800.0f which is a magic value we must + * set in wr56. + */ + +static void mgaG400EmitPipe(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int pipe = sarea_priv->WarpPipe; + PRIMLOCALS; + + PRIMGETPTR(dev_priv); + + /* This takes 50 dwords */ + + /* Establish vertex size. + */ + PRIMOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + + if (pipe & MGA_T2) { + PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001e09); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0); + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0); + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0); + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x1e000000); + } else { + if (dev_priv->WarpPipe & MGA_T2) { + /* Flush the WARP pipe */ + PRIMOUTREG(MGAREG_YDST, 0); + PRIMOUTREG(MGAREG_FXLEFT, 0); + PRIMOUTREG(MGAREG_FXRIGHT, 1); + PRIMOUTREG(MGAREG_DWGCTL, MGA_FLUSH_CMD); + + PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 1); + PRIMOUTREG(MGAREG_DWGSYNC, 0x7000); + PRIMOUTREG(MGAREG_TEXCTL2, 0x00008000); + PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0); + + PRIMOUTREG(MGAREG_TEXCTL2, 0x80 | 0x00008000); + PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + } + + PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001807); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0); + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0); + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0); + PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x18000000); + } + + PRIMOUTREG(MGAREG_WFLAG, 0); + PRIMOUTREG(MGAREG_WFLAG1, 0); + PRIMOUTREG(MGAREG_WR56, MAGIC_FPARAM_HEX_VALUE); + PRIMOUTREG(MGAREG_DMAPAD, 0); + + PRIMOUTREG(MGAREG_WR49, 0); /* Tex stage 0 */ + PRIMOUTREG(MGAREG_WR57, 0); /* Tex stage 0 */ + PRIMOUTREG(MGAREG_WR53, 0); /* Tex stage 1 */ + PRIMOUTREG(MGAREG_WR61, 0); /* Tex stage 1 */ + + PRIMOUTREG(MGAREG_WR54, 0x40); /* Tex stage 0 : w */ + PRIMOUTREG(MGAREG_WR62, 0x40); /* Tex stage 0 : h */ + PRIMOUTREG(MGAREG_WR52, 0x40); /* Tex stage 1 : w */ + PRIMOUTREG(MGAREG_WR60, 0x40); /* Tex stage 1 : h */ + + /* Dma pading required due to hw bug */ + PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); + PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); + PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); + PRIMOUTREG(MGAREG_WIADDR2, + (u32) (dev_priv->WarpIndex[pipe]. + phys_addr | WIA_wmode_start | WIA_wagp_agp)); + PRIMADVANCE(dev_priv); +} + +static void mgaG200EmitPipe(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int pipe = sarea_priv->WarpPipe; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + PRIMGETPTR(dev_priv); + + /* This takes 15 dwords */ + + PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend); + PRIMOUTREG(MGAREG_WVRTXSZ, 7); + PRIMOUTREG(MGAREG_WFLAG, 0); + PRIMOUTREG(MGAREG_WR24, 0); /* tex w/h */ + + PRIMOUTREG(MGAREG_WR25, 0x100); + PRIMOUTREG(MGAREG_WR34, 0); /* tex w/h */ + PRIMOUTREG(MGAREG_WR42, 0xFFFF); + PRIMOUTREG(MGAREG_WR60, 0xFFFF); + + /* Dma pading required due to hw bug */ + PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); + PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); + PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); + PRIMOUTREG(MGAREG_WIADDR, + (u32) (dev_priv->WarpIndex[pipe]. + phys_addr | WIA_wmode_start | WIA_wagp_agp)); + + PRIMADVANCE( dev_priv ); +} + +static void mgaEmitState(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + DRM_DEBUG("%s\n", __FUNCTION__); + + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + int multitex = sarea_priv->WarpPipe & MGA_T2; + + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + mgaG400EmitPipe(dev_priv); + dev_priv->WarpPipe = sarea_priv->WarpPipe; + } + + if (dirty & MGA_UPLOAD_CTX) { + mgaEmitContext(dev_priv); + sarea_priv->dirty &= ~MGA_UPLOAD_CTX; + } + + if (dirty & MGA_UPLOAD_TEX0) { + mgaG400EmitTex0(dev_priv); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; + } + + if ((dirty & MGA_UPLOAD_TEX1) && multitex) { + mgaG400EmitTex1(dev_priv); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX1; + } + } else { + if (sarea_priv->WarpPipe != dev_priv->WarpPipe) { + mgaG200EmitPipe(dev_priv); + dev_priv->WarpPipe = sarea_priv->WarpPipe; + } + + if (dirty & MGA_UPLOAD_CTX) { + mgaEmitContext(dev_priv); + sarea_priv->dirty &= ~MGA_UPLOAD_CTX; + } + + if (dirty & MGA_UPLOAD_TEX0) { + mgaG200EmitTex(dev_priv); + sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; + } + } +} + + +/* Disallow all write destinations except the front and backbuffer. + */ +static int mgaVerifyContext(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset && + regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) { + DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n", + regs[MGA_CTXREG_DSTORG], dev_priv->frontOffset, + dev_priv->backOffset); + regs[MGA_CTXREG_DSTORG] = 0; + return -1; + } + + return 0; +} + +/* Disallow texture reads from PCI space. + */ +static int mgaVerifyTex(drm_mga_private_t * dev_priv, int unit) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) { + DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n", + sarea_priv->TexState[unit][MGA_TEXREG_ORG], + unit); + sarea_priv->TexState[unit][MGA_TEXREG_ORG] = 0; + return -1; + } + + return 0; +} + +static int mgaVerifyState(drm_mga_private_t * dev_priv) +{ + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + int rv = 0; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + if (dirty & MGA_UPLOAD_CTX) + rv |= mgaVerifyContext(dev_priv); + + if (dirty & MGA_UPLOAD_TEX0) + rv |= mgaVerifyTex(dev_priv, 0); + + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + if (dirty & MGA_UPLOAD_TEX1) + rv |= mgaVerifyTex(dev_priv, 1); + + if (dirty & MGA_UPLOAD_PIPE) + rv |= (sarea_priv->WarpPipe > MGA_MAX_G400_PIPES); + } else { + if (dirty & MGA_UPLOAD_PIPE) + rv |= (sarea_priv->WarpPipe > MGA_MAX_G200_PIPES); + } + + return rv == 0; +} + +static int mgaVerifyIload(drm_mga_private_t * dev_priv, + unsigned long bus_address, + unsigned int dstOrg, int length) +{ + DRM_DEBUG("%s\n", __FUNCTION__); + + if (dstOrg < dev_priv->textureOffset || + dstOrg + length > + (dev_priv->textureOffset + dev_priv->textureSize)) { + return -EINVAL; + } + if (length % 64) { + return -EINVAL; + } + return 0; +} + +/* This copies a 64 byte aligned agp region to the frambuffer + * with a standard blit, the ioctl needs to do checking */ + +static void mga_dma_dispatch_tex_blit(drm_device_t * dev, + unsigned long bus_address, + int length, unsigned int destOrg) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + int use_agp = PDEA_pagpxfer_enable | 0x00000001; + u16 y2; + PRIMLOCALS; + + y2 = length / 64; + + PRIM_OVERFLOW(dev, dev_priv, 30); + + PRIMOUTREG(MGAREG_DSTORG, destOrg); + PRIMOUTREG(MGAREG_MACCESS, 0x00000000); + PRIMOUTREG(MGAREG_SRCORG, (u32) bus_address | use_agp); + PRIMOUTREG(MGAREG_AR5, 64); + + PRIMOUTREG(MGAREG_PITCH, 64); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD); + + PRIMOUTREG(MGAREG_AR0, 63); + PRIMOUTREG(MGAREG_AR3, 0); + PRIMOUTREG(MGAREG_FXBNDRY, (63 << 16)); + PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC, y2); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_SRCORG, 0); + PRIMOUTREG(MGAREG_PITCH, dev_priv->stride / dev_priv->cpp); + PRIMOUTREG(MGAREG_DWGSYNC, 0x7000); + PRIMADVANCE(dev_priv); +} + +static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned long address = (unsigned long) buf->bus_address; + int length = buf->used; + int use_agp = PDEA_pagpxfer_enable; + int i = 0; + PRIMLOCALS; + + if (buf->used) { + /* WARNING: if you change any of the state functions verify + * these numbers (Overestimating this doesn't hurt). + */ + buf_priv->dispatched = 1; + PRIM_OVERFLOW(dev, dev_priv, + (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS))); + mgaEmitState(dev_priv); + +#if 0 + length = dev_priv->vertexsize * 3 * 4; +#endif + + do { + if (i < sarea_priv->nbox) { + mgaEmitClipRect(dev_priv, + &sarea_priv->boxes[i]); + } + + PRIMGETPTR(dev_priv); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_SECADDRESS, + ((u32) address) | TT_VERTEX); + PRIMOUTREG(MGAREG_SECEND, + (((u32) (address + length)) | use_agp)); + PRIMADVANCE(dev_priv); + } while (++i < sarea_priv->nbox); + } + if (buf_priv->discard) { + if (buf_priv->dispatched == 1) + AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + + +} + + +static void mga_dma_dispatch_indices(drm_device_t * dev, + drm_buf_t * buf, + unsigned int start, unsigned int end) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int address = (unsigned int) buf->bus_address; + int use_agp = PDEA_pagpxfer_enable; + int i = 0; + PRIMLOCALS; + + if (start != end) { + /* WARNING: if you change any of the state functions verify + * these numbers (Overestimating this doesn't hurt). + */ + buf_priv->dispatched = 1; + PRIM_OVERFLOW(dev, dev_priv, + (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS))); + mgaEmitState(dev_priv); + + do { + if (i < sarea_priv->nbox) { + mgaEmitClipRect(dev_priv, + &sarea_priv->boxes[i]); + } + + PRIMGETPTR(dev_priv); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_SETUPADDRESS, + ((address + start) | + SETADD_mode_vertlist)); + PRIMOUTREG(MGAREG_SETUPEND, + ((address + end) | use_agp)); + PRIMADVANCE(dev_priv); + } while (++i < sarea_priv->nbox); + } + if (buf_priv->discard) { + if (buf_priv->dispatched == 1) + AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } +} + + +static void mga_dma_dispatch_clear(drm_device_t * dev, int flags, + unsigned int clear_color, + unsigned int clear_zval, + unsigned int clear_colormask, + unsigned int clear_depthmask) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + unsigned int cmd; + int i; + PRIMLOCALS; + + if (dev_priv->sgram) + cmd = MGA_CLEAR_CMD | DC_atype_blk; + else + cmd = MGA_CLEAR_CMD | DC_atype_rstr; + + PRIM_OVERFLOW(dev, dev_priv, 35 * MGA_NR_SAREA_CLIPRECTS); + + for (i = 0; i < nbox; i++) { + unsigned int height = pbox[i].y2 - pbox[i].y1; + + if (flags & MGA_FRONT) { + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_PLNWT, clear_colormask); + PRIMOUTREG(MGAREG_YDSTLEN, + (pbox[i].y1 << 16) | height); + PRIMOUTREG(MGAREG_FXBNDRY, + (pbox[i].x2 << 16) | pbox[i].x1); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_color); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); + PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd); + } + + if (flags & MGA_BACK) { + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_PLNWT, clear_colormask); + PRIMOUTREG(MGAREG_YDSTLEN, + (pbox[i].y1 << 16) | height); + PRIMOUTREG(MGAREG_FXBNDRY, + (pbox[i].x2 << 16) | pbox[i].x1); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_color); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->backOffset); + PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd); + } + + if (flags & MGA_DEPTH) { + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_PLNWT, clear_depthmask); + PRIMOUTREG(MGAREG_YDSTLEN, + (pbox[i].y1 << 16) | height); + PRIMOUTREG(MGAREG_FXBNDRY, + (pbox[i].x2 << 16) | pbox[i].x1); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_FCOL, clear_zval); + PRIMOUTREG(MGAREG_DSTORG, dev_priv->depthOffset); + PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd); + } + } + + /* Force reset of DWGCTL */ + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + PRIMADVANCE(dev_priv); +} + +static void mga_dma_dispatch_swap(drm_device_t * dev) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int i; + int pixel_stride = dev_priv->stride / dev_priv->cpp; + + PRIMLOCALS; + + PRIM_OVERFLOW(dev, dev_priv, (MGA_NR_SAREA_CLIPRECTS * 5) + 20); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0x7100); + PRIMOUTREG(MGAREG_DWGSYNC, 0x7000); + + PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); + PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); + PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset); + PRIMOUTREG(MGAREG_AR5, pixel_stride); + + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD); + + for (i = 0; i < nbox; i++) { + unsigned int h = pbox[i].y2 - pbox[i].y1; + unsigned int start = pbox[i].y1 * pixel_stride; + + PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1); + PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1); + PRIMOUTREG(MGAREG_FXBNDRY, + pbox[i].x1 | ((pbox[i].x2 - 1) << 16)); + PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC, + (pbox[i].y1 << 16) | h); + } + + /* Force reset of DWGCTL */ + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_SRCORG, 0); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + + PRIMADVANCE(dev_priv); +} + +int mga_clear_bufs(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_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_clear_t clear; + + copy_from_user_ret(&clear, (drm_mga_clear_t *) arg, sizeof(clear), + -EFAULT); + DRM_DEBUG("%s\n", __FUNCTION__); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_clear_bufs called without lock held\n"); + return -EINVAL; + } + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_clear(dev, clear.flags, + clear.clear_color, + clear.clear_depth, + clear.clear_color_mask, + clear.clear_depth_mask); + PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + +int mga_swap_bufs(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_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + DRM_DEBUG("%s\n", __FUNCTION__); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_swap_bufs called without lock held\n"); + return -EINVAL; + } + + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) + sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; + + /* Make sure we restore the 3D state next time. + */ + dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; + mga_dma_dispatch_swap(dev); + PRIMUPDATE(dev_priv); + set_bit(MGA_BUF_SWAP_PENDING, + &dev_priv->current_prim->buffer_status); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + +int mga_iload(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_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_iload_t iload; + unsigned long bus_address; + DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("Starting Iload\n"); + copy_from_user_ret(&iload, (drm_mga_iload_t *) arg, sizeof(iload), + -EFAULT); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_iload called without lock held\n"); + return -EINVAL; + } + + buf = dma->buflist[iload.idx]; + buf_priv = buf->dev_private; + bus_address = buf->bus_address; + DRM_DEBUG("bus_address %lx, length %d, destorg : %x\n", + bus_address, iload.length, iload.destOrg); + + if (mgaVerifyIload(dev_priv, + bus_address, iload.destOrg, iload.length)) { + mga_freelist_put(dev, buf); + return -EINVAL; + } + + sarea_priv->dirty |= MGA_UPLOAD_CTX; + + mga_dma_dispatch_tex_blit(dev, bus_address, iload.length, + iload.destOrg); + AGEBUF(dev_priv, buf_priv); + buf_priv->discard = 1; + mga_freelist_put(dev, buf); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + +int mga_vertex(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_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_vertex_t vertex; + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&vertex, (drm_mga_vertex_t *) arg, + sizeof(vertex), -EFAULT); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("mga_vertex\n"); + + buf = dma->buflist[vertex.idx]; + buf_priv = buf->dev_private; + + buf->used = vertex.used; + buf_priv->discard = vertex.discard; + + if (!mgaVerifyState(dev_priv)) { + if (vertex.discard) { + if (buf_priv->dispatched == 1) + AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + DRM_DEBUG("bad state\n"); + return -EINVAL; + } + + mga_dma_dispatch_vertex(dev, buf); + + PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + + +int mga_indices(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_mga_private_t *dev_priv = + (drm_mga_private_t *) dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_indices_t indices; + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&indices, (drm_mga_indices_t *) arg, + sizeof(indices), -EFAULT); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_indices called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("mga_indices\n"); + + buf = dma->buflist[indices.idx]; + buf_priv = buf->dev_private; + + buf_priv->discard = indices.discard; + + if (!mgaVerifyState(dev_priv)) { + if (indices.discard) { + if (buf_priv->dispatched == 1) + AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + return -EINVAL; + } + + mga_dma_dispatch_indices(dev, buf, indices.start, indices.end); + + PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + + + +static int mga_dma_get_buffers(drm_device_t * dev, drm_dma_t * d) +{ + int i; + drm_buf_t *buf; + DRM_DEBUG("%s\n", __FUNCTION__); + + for (i = d->granted_count; i < d->request_count; i++) { + buf = mga_freelist_get(dev); + if (!buf) + break; + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, sizeof(buf->idx), -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, sizeof(buf->total), -EFAULT); + ++d->granted_count; + } + return 0; +} + +int mga_dma(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_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_dma_t d; + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&d, (drm_dma_t *) arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_dma called without lock held\n"); + return -EINVAL; + } + + /* Please don't send us buffers. + */ + if (d.send_count != 0) { + DRM_ERROR + ("Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count); + return -EINVAL; + } + + /* We'll send you buffers. + */ + if (d.request_count < 0 || d.request_count > dma->buf_count) { + DRM_ERROR + ("Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count); + return -EINVAL; + } + + d.granted_count = 0; + + if (d.request_count) { + retcode = mga_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, d.granted_count); + copy_to_user_ret((drm_dma_t *) arg, &d, sizeof(d), -EFAULT); + return retcode; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/proc.c linux/drivers/char/drm/proc.c --- v2.2.17/drivers/char/drm/proc.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/proc.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,577 @@ +/* proc.c -- /proc support for DRM -*- linux-c -*- + * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static struct proc_dir_entry *drm_root = NULL; +static struct proc_dir_entry *drm_dev_root = NULL; +static char drm_slot_name[64]; + +static int drm_name_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_vm_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_clients_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_queues_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_bufs_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +#if DRM_DEBUG_CODE +static int drm_vma_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +#endif +#if DRM_DMA_HISTOGRAM +static int drm_histo_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +#endif + +struct drm_proc_list { + const char *name; + int (*f)(char *, char **, off_t, int, int *, void *); +} drm_proc_list[] = { + { "name", drm_name_info }, + { "mem", drm_mem_info }, + { "vm", drm_vm_info }, + { "clients", drm_clients_info }, + { "queues", drm_queues_info }, + { "bufs", drm_bufs_info }, +#if DRM_DEBUG_CODE + { "vma", drm_vma_info }, +#endif +#if DRM_DMA_HISTOGRAM + { "histo", drm_histo_info }, +#endif +}; +#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0])) + +int drm_proc_init(drm_device_t *dev) +{ + struct proc_dir_entry *ent; + int i, j; + + drm_root = create_proc_entry("dri", S_IFDIR, NULL); + if (!drm_root) { + DRM_ERROR("Cannot create /proc/dri\n"); + return -1; + } + + /* Instead of doing this search, we should + add some global support for /proc/dri. */ + for (i = 0; i < 8; i++) { + sprintf(drm_slot_name, "dri/%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("dri", NULL); + } + if (drm_dev_root->nlink == 2) break; + drm_dev_root = NULL; + } + if (!drm_dev_root) { + DRM_ERROR("Cannot find slot in /proc/dri\n"); + return -1; + } + + for (i = 0; i < DRM_PROC_ENTRIES; i++) { + ent = create_proc_entry(drm_proc_list[i].name, + S_IFREG|S_IRUGO, drm_dev_root); + if (!ent) { + DRM_ERROR("Cannot create /proc/%s/%s\n", + drm_slot_name, drm_proc_list[i].name); + for (j = 0; j < i; j++) + remove_proc_entry(drm_proc_list[i].name, + drm_dev_root); + remove_proc_entry(drm_slot_name, NULL); + remove_proc_entry("dri", NULL); + return -1; + } + ent->read_proc = drm_proc_list[i].f; + ent->data = dev; + } + + return 0; +} + + +int drm_proc_cleanup(void) +{ + int i; + + if (drm_root) { + if (drm_dev_root) { + for (i = 0; i < DRM_PROC_ENTRIES; i++) { + remove_proc_entry(drm_proc_list[i].name, + drm_dev_root); + } + remove_proc_entry(drm_slot_name, NULL); + } + remove_proc_entry("dri", NULL); + remove_proc_entry(DRM_NAME, NULL); + } + drm_root = drm_dev_root = NULL; + return 0; +} + +static int drm_name_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + if (dev->unique) { + DRM_PROC_PRINT("%s 0x%x %s\n", + dev->name, dev->device, dev->unique); + } else { + DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device); + } + return len; +} + +static int _drm_vm_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_map_t *map; + /* Hardcoded from _DRM_FRAME_BUFFER, + _DRM_REGISTERS, _DRM_SHM, and + _DRM_AGP. */ + const char *types[] = { "FB", "REG", "SHM", "AGP" }; + const char *type; + int i; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT("slot offset size type flags " + "address mtrr\n\n"); + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (map->type < 0 || map->type > 3) type = "??"; + else type = types[map->type]; + DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", + i, + map->offset, + map->size, + type, + map->flags, + (unsigned long)map->handle); + if (map->mtrr < 0) { + DRM_PROC_PRINT("none\n"); + } else { + DRM_PROC_PRINT("%4d\n", map->mtrr); + } + } + + return len; +} + +static int drm_vm_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_vm_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + + +static int _drm_queues_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int i; + drm_queue_t *q; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT(" ctx/flags use fin" + " blk/rw/rwf wait flushed queued" + " locks\n\n"); + for (i = 0; i < dev->queue_count; i++) { + q = dev->queuelist[i]; + atomic_inc(&q->use_count); + DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), + "%5d/0x%03x %5d %5d" + " %5d/%c%c/%c%c%c %5Zd %10d %10d %10d\n", + i, + q->flags, + atomic_read(&q->use_count), + atomic_read(&q->finalization), + atomic_read(&q->block_count), + atomic_read(&q->block_read) ? 'r' : '-', + atomic_read(&q->block_write) ? 'w' : '-', + waitqueue_active(&q->read_queue) ? 'r':'-', + waitqueue_active(&q->write_queue) ? 'w':'-', + waitqueue_active(&q->flush_queue) ? 'f':'-', + DRM_BUFCOUNT(&q->waitlist), + atomic_read(&q->total_flushed), + atomic_read(&q->total_queued), + atomic_read(&q->total_locks)); + atomic_dec(&q->use_count); + } + + return len; +} + +static int drm_queues_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_queues_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + +/* drm_bufs_info is called whenever a process reads + /dev/drm//bufs. */ + +static int _drm_bufs_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return 0; + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); + for (i = 0; i <= DRM_MAX_ORDER; i++) { + if (dma->bufs[i].buf_count) + DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", + i, + dma->bufs[i].buf_size, + dma->bufs[i].buf_count, + atomic_read(&dma->bufs[i] + .freelist.count), + dma->bufs[i].seg_count, + dma->bufs[i].seg_count + *(1 << dma->bufs[i].page_order), + (dma->bufs[i].seg_count + * (1 << dma->bufs[i].page_order)) + * PAGE_SIZE / 1024); + } + DRM_PROC_PRINT("\n"); + for (i = 0; i < dma->buf_count; i++) { + if (i && !(i%32)) DRM_PROC_PRINT("\n"); + DRM_PROC_PRINT(" %d", dma->buflist[i]->list); + } + DRM_PROC_PRINT("\n"); + + return len; +} + +static int drm_bufs_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_bufs_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + + +static int _drm_clients_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_file_t *priv; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); + for (priv = dev->file_first; priv; priv = priv->next) { + DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", + priv->authenticated ? 'y' : 'n', + priv->minor, + priv->pid, + priv->uid, + priv->magic, + priv->ioctl_count); + } + + return len; +} + +static int drm_clients_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_clients_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + +#if DRM_DEBUG_CODE + +#define DRM_VMA_VERBOSE 0 + +static int _drm_vma_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_vma_entry_t *pt; + struct vm_area_struct *vma; +#if DRM_VMA_VERBOSE + unsigned long i; + unsigned long address; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; +#endif +#if defined(__i386__) + unsigned int pgprot; +#endif + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", + atomic_read(&dev->vma_count), + high_memory, virt_to_phys(high_memory)); + for (pt = dev->vmalist; pt; pt = pt->next) { + if (!(vma = pt->vma)) continue; + DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", + pt->pid, + vma->vm_start, + vma->vm_end, + vma->vm_flags & VM_READ ? 'r' : '-', + vma->vm_flags & VM_WRITE ? 'w' : '-', + vma->vm_flags & VM_EXEC ? 'x' : '-', + vma->vm_flags & VM_MAYSHARE ? 's' : 'p', + vma->vm_flags & VM_LOCKED ? 'l' : '-', + vma->vm_flags & VM_IO ? 'i' : '-', + 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", + pgprot & _PAGE_PRESENT ? 'p' : '-', + pgprot & _PAGE_RW ? 'w' : 'r', + pgprot & _PAGE_USER ? 'u' : 's', + pgprot & _PAGE_PWT ? 't' : 'b', + pgprot & _PAGE_PCD ? 'u' : 'c', + pgprot & _PAGE_ACCESSED ? 'a' : '-', + pgprot & _PAGE_DIRTY ? 'd' : '-', + pgprot & _PAGE_PSE ? 'm' : 'k', + pgprot & _PAGE_GLOBAL ? 'g' : 'l' ); +#endif + DRM_PROC_PRINT("\n"); +#if 0 + for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) { + pgd = pgd_offset(vma->vm_mm, i); + pmd = pmd_offset(pgd, i); + pte = pte_offset(pmd, i); + if (pte_present(*pte)) { + address = __pa(pte_page(*pte)) + + (i & (PAGE_SIZE-1)); + DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx" + " %c%c%c%c%c\n", + i, + address, + pte_read(*pte) ? 'r' : '-', + pte_write(*pte) ? 'w' : '-', + pte_exec(*pte) ? 'x' : '-', + pte_dirty(*pte) ? 'd' : '-', + pte_young(*pte) ? 'a' : '-' ); + } else { + DRM_PROC_PRINT(" 0x%08lx\n", i); + } + } +#endif + } + + return len; +} + +static int drm_vma_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_vma_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} +#endif + + +#if DRM_DMA_HISTOGRAM +static int _drm_histo_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_device_dma_t *dma = dev->dma; + int i; + unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL; + unsigned long prev_value = 0; + drm_buf_t *buffer; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + DRM_PROC_PRINT("general statistics:\n"); + DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total)); + DRM_PROC_PRINT("open %10u\n", atomic_read(&dev->total_open)); + DRM_PROC_PRINT("close %10u\n", atomic_read(&dev->total_close)); + DRM_PROC_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl)); + DRM_PROC_PRINT("irq %10u\n", atomic_read(&dev->total_irq)); + DRM_PROC_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx)); + + DRM_PROC_PRINT("\nlock statistics:\n"); + DRM_PROC_PRINT("locks %10u\n", atomic_read(&dev->total_locks)); + DRM_PROC_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks)); + DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends)); + DRM_PROC_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps)); + + + if (dma) { + DRM_PROC_PRINT("\ndma statistics:\n"); + DRM_PROC_PRINT("prio %10u\n", + atomic_read(&dma->total_prio)); + DRM_PROC_PRINT("bytes %10u\n", + atomic_read(&dma->total_bytes)); + DRM_PROC_PRINT("dmas %10u\n", + atomic_read(&dma->total_dmas)); + DRM_PROC_PRINT("missed:\n"); + DRM_PROC_PRINT(" dma %10u\n", + atomic_read(&dma->total_missed_dma)); + DRM_PROC_PRINT(" lock %10u\n", + atomic_read(&dma->total_missed_lock)); + DRM_PROC_PRINT(" free %10u\n", + atomic_read(&dma->total_missed_free)); + DRM_PROC_PRINT(" sched %10u\n", + atomic_read(&dma->total_missed_sched)); + DRM_PROC_PRINT("tried %10u\n", + atomic_read(&dma->total_tried)); + DRM_PROC_PRINT("hit %10u\n", + atomic_read(&dma->total_hit)); + DRM_PROC_PRINT("lost %10u\n", + atomic_read(&dma->total_lost)); + + buffer = dma->next_buffer; + if (buffer) { + DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx); + } else { + DRM_PROC_PRINT("next_buffer none\n"); + } + buffer = dma->this_buffer; + if (buffer) { + DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx); + } else { + DRM_PROC_PRINT("this_buffer none\n"); + } + } + + + DRM_PROC_PRINT("\nvalues:\n"); + if (dev->lock.hw_lock) { + DRM_PROC_PRINT("lock 0x%08x\n", + dev->lock.hw_lock->lock); + } else { + DRM_PROC_PRINT("lock none\n"); + } + DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag); + DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag); + DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag); + + DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count); + DRM_PROC_PRINT("last_context %10d\n", dev->last_context); + DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch); + DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked); + + + DRM_PROC_PRINT("\n q2d d2c c2f" + " q2c q2f dma sch" + " ctx lacq lhld\n\n"); + for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) { + DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u" + " %10u %10u %10u %10u %10u\n", + i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ", + i == DRM_DMA_HISTOGRAM_SLOTS - 1 + ? prev_value : slot_value , + + atomic_read(&dev->histo + .queued_to_dispatched[i]), + atomic_read(&dev->histo + .dispatched_to_completed[i]), + atomic_read(&dev->histo + .completed_to_freed[i]), + + atomic_read(&dev->histo + .queued_to_completed[i]), + atomic_read(&dev->histo + .queued_to_freed[i]), + atomic_read(&dev->histo.dma[i]), + atomic_read(&dev->histo.schedule[i]), + atomic_read(&dev->histo.ctx[i]), + atomic_read(&dev->histo.lacq[i]), + atomic_read(&dev->histo.lhld[i])); + prev_value = slot_value; + slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value); + } + return len; +} + +static int drm_histo_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_histo_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/r128_bufs.c linux/drivers/char/drm/r128_bufs.c --- v2.2.17/drivers/char/drm/r128_bufs.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/r128_bufs.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,309 @@ +/* r128_bufs.c -- IOCTLs to manage buffers -*- linux-c -*- + * Created: Wed Apr 12 16:19:08 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Kevin E. Martin + * Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#define __NO_VERSION__ +#include +#include "drmP.h" +#include "r128_drv.h" +#include "linux/un.h" + + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +int r128_addbufs_agp(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_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = dev->agp->base + request.agp_start; + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %ld\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + offset = 0; + + for (offset = 0; + entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + offset); + buf->address = (void *)(agp_offset + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; + + buf->dev_priv_size = sizeof(drm_r128_buf_priv_t); + buf->dev_private = drm_alloc(sizeof(drm_r128_buf_priv_t), + DRM_MEM_BUFS); + memset(buf->dev_private, 0, buf->dev_priv_size); + +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + + byte_count += PAGE_SIZE << page_order; + + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + + DRM_DEBUG("byte_count: %d\n", byte_count); + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); + + dma->flags = _DRM_DMA_USE_AGP; + + atomic_dec(&dev->buf_alloc); + return 0; +} +#endif + +int r128_addbufs(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_r128_private_t *dev_priv = dev->dev_private; + drm_buf_desc_t request; + + if (!dev_priv || dev_priv->is_pci) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + if (request.flags & _DRM_AGP_BUFFER) + return r128_addbufs_agp(inode, filp, cmd, arg); + else +#endif + return -EINVAL; +} + +int r128_mapbufs(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_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + const int zero = 0; + unsigned long virtual; + unsigned long address; + drm_buf_map_t request; + int i; + + if (!dma || !dev_priv || dev_priv->is_pci) return -EINVAL; + + DRM_DEBUG("\n"); + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_map_t *)arg, + sizeof(request), + -EFAULT); + + if (request.count >= dma->buf_count) { + if (dma->flags & _DRM_DMA_USE_AGP) { + drm_map_t *map; + + map = dev_priv->agp_vertbufs; + if (!map) { + retcode = -EINVAL; + goto done; + } + + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, map->size, + PROT_READ|PROT_WRITE, + MAP_SHARED, + (unsigned long)map->offset); + up(¤t->mm->mmap_sem); + } else { + down(¤t->mm->mmap_sem); + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); + } + if (virtual > -1024UL) { + /* Real error */ + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void *)virtual; + + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].used, + &zero, + sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; + if (copy_to_user(&request.list[i].address, + &address, + sizeof(address))) { + retcode = -EFAULT; + goto done; + } + } + } + done: + request.count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); + + copy_to_user_ret((drm_buf_map_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return retcode; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/r128_context.c linux/drivers/char/drm/r128_context.c --- v2.2.17/drivers/char/drm/r128_context.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/r128_context.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,207 @@ +/* r128_context.c -- IOCTLs for r128 contexts -*- linux-c -*- + * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Author: Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" + +extern drm_ctx_t r128_res_ctx; + +static int r128_alloc_queue(drm_device_t *dev) +{ + return drm_ctxbitmap_next(dev); +} + +int r128_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) { + r128_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + return 0; +} + +int r128_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 r128_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 r128_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 = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Skip kernel's context and get a new one. */ + ctx.handle = r128_alloc_queue(dev); + } + DRM_DEBUG("%d\n", ctx.handle); + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int r128_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) + r128_res_ctx.handle=ctx.handle; + return 0; +} + +int r128_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 r128_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 r128_context_switch(dev, dev->last_context, ctx.handle); +} + +int r128_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); + r128_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int r128_rmctx(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); + drm_ctxbitmap_free(dev, ctx.handle); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/r128_dma.c linux/drivers/char/drm/r128_dma.c --- v2.2.17/drivers/char/drm/r128_dma.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/r128_dma.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,906 @@ +/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- + * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Kevin E. Martin + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" + +#include /* For task queue support */ +#include + + + +#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) + +#define DO_REMAPFREE(_m) \ + do { \ + if ((_m)->handle && (_m)->size) \ + drm_ioremapfree((_m)->handle, (_m)->size); \ + } while (0) + +#define DO_FIND_MAP(_m, _o) \ + do { \ + int _i; \ + for (_i = 0; _i < dev->map_count; _i++) { \ + if (dev->maplist[_i]->offset == _o) { \ + _m = dev->maplist[_i]; \ + break; \ + } \ + } \ + } while (0) + + +#define R128_MAX_VBUF_AGE 0x10000000 +#define R128_VB_AGE_REG R128_GUI_SCRATCH_REG0 + +int R128_READ_PLL(drm_device_t *dev, int addr) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + + R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); + return R128_READ(R128_CLOCK_CNTL_DATA); +} + +#define r128_flush_write_combine() mb() + + +static void r128_status(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + + printk("GUI_STAT = 0x%08x\n", + (unsigned int)R128_READ(R128_GUI_STAT)); + printk("PM4_STAT = 0x%08x\n", + (unsigned int)R128_READ(R128_PM4_STAT)); + printk("PM4_BUFFER_DL_WPTR = 0x%08x\n", + (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR)); + printk("PM4_BUFFER_DL_RPTR = 0x%08x\n", + (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR)); +} + +static int r128_do_cleanup_cce(drm_device_t *dev) +{ + if (dev->dev_private) { + drm_r128_private_t *dev_priv = dev->dev_private; + + if (!dev_priv->is_pci) { + DO_REMAPFREE(dev_priv->agp_ring); + DO_REMAPFREE(dev_priv->agp_read_ptr); + DO_REMAPFREE(dev_priv->agp_vertbufs); + DO_REMAPFREE(dev_priv->agp_indbufs); + DO_REMAPFREE(dev_priv->agp_textures); + } + + drm_free(dev->dev_private, sizeof(drm_r128_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; + } + + return 0; +} + +static int r128_do_init_cce(drm_device_t *dev, drm_r128_init_t *init) +{ + drm_r128_private_t *dev_priv; + int i; + + dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) return -ENOMEM; + dev->dev_private = (void *)dev_priv; + + memset(dev_priv, 0, sizeof(drm_r128_private_t)); + + dev_priv->is_pci = init->is_pci; + + dev_priv->usec_timeout = init->usec_timeout; + if (dev_priv->usec_timeout < 1 || + dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) { + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + return -EINVAL; + } + + dev_priv->cce_mode = init->cce_mode; + dev_priv->cce_fifo_size = init->cce_fifo_size; + dev_priv->cce_is_bm_mode = + ((init->cce_mode == R128_PM4_192BM) || + (init->cce_mode == R128_PM4_128BM_64INDBM) || + (init->cce_mode == R128_PM4_64BM_128INDBM) || + (init->cce_mode == R128_PM4_64BM_64VCBM_64INDBM)); + dev_priv->cce_secure = init->cce_secure; + + if (dev_priv->cce_is_bm_mode && dev_priv->is_pci) { + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + return -EINVAL; + } + + for (i = 0; i < dev->map_count; i++) { + if (dev->maplist[i]->type == _DRM_SHM) { + dev_priv->sarea = dev->maplist[i]; + break; + } + } + + DO_FIND_MAP(dev_priv->fb, init->fb_offset); + if (!dev_priv->is_pci) { + DO_FIND_MAP(dev_priv->agp_ring, init->agp_ring_offset); + DO_FIND_MAP(dev_priv->agp_read_ptr, init->agp_read_ptr_offset); + DO_FIND_MAP(dev_priv->agp_vertbufs, init->agp_vertbufs_offset); + DO_FIND_MAP(dev_priv->agp_indbufs, init->agp_indbufs_offset); + DO_FIND_MAP(dev_priv->agp_textures, init->agp_textures_offset); + } + DO_FIND_MAP(dev_priv->mmio, init->mmio_offset); + + dev_priv->sarea_priv = + (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + + init->sarea_priv_offset); + + if (!dev_priv->is_pci) { + DO_REMAP(dev_priv->agp_ring); + DO_REMAP(dev_priv->agp_read_ptr); + DO_REMAP(dev_priv->agp_vertbufs); +#if 0 + DO_REMAP(dev_priv->agp_indirectbufs); + DO_REMAP(dev_priv->agp_textures); +#endif + + dev_priv->ring_size = init->ring_size; + dev_priv->ring_sizel2qw = drm_order(init->ring_size/8); + dev_priv->ring_entries = init->ring_size/sizeof(u32); + dev_priv->ring_read_ptr = ((__volatile__ u32 *) + dev_priv->agp_read_ptr->handle); + dev_priv->ring_start = (u32 *)dev_priv->agp_ring->handle; + dev_priv->ring_end = ((u32 *)dev_priv->agp_ring->handle + + dev_priv->ring_entries); + } + + dev_priv->submit_age = 0; + R128_WRITE(R128_VB_AGE_REG, dev_priv->submit_age); + + return 0; +} + +int r128_init_cce(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_r128_init_t init; + + copy_from_user_ret(&init, (drm_r128_init_t *)arg, sizeof(init), + -EFAULT); + + switch (init.func) { + case R128_INIT_CCE: + return r128_do_init_cce(dev, &init); + case R128_CLEANUP_CCE: + return r128_do_cleanup_cce(dev); + } + + return -EINVAL; +} + +static void r128_mark_vertbufs_done(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[i]; + drm_r128_buf_priv_t *buf_priv = buf->dev_private; + buf_priv->age = 0; + } +} + +static int r128_do_pixcache_flush(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 tmp; + int i; + + tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL; + R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp); + + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) + return 0; + udelay(1); + } + + return -EBUSY; +} + +static int r128_do_wait_for_fifo(drm_device_t *dev, int entries) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK; + if (slots >= entries) return 0; + udelay(1); + } + return -EBUSY; +} + +static int r128_do_wait_for_idle(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i, ret; + + if (!(ret = r128_do_wait_for_fifo(dev, 64))) return ret; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) { + (void)r128_do_pixcache_flush(dev); + return 0; + } + udelay(1); + } + return -EBUSY; +} + +int r128_do_engine_reset(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; + + (void)r128_do_pixcache_flush(dev); + + clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX); + mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL); + + R128_WRITE_PLL(R128_MCLK_CNTL, + mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP); + + gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL); + + R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI); + (void)R128_READ(R128_GEN_RESET_CNTL); + R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI); + (void)R128_READ(R128_GEN_RESET_CNTL); + + R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl); + R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index); + R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl); + + /* For CCE ring buffer only */ + if (dev_priv->cce_is_bm_mode) { + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0); + R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0); + *dev_priv->ring_read_ptr = 0; + dev_priv->sarea_priv->ring_write = 0; + } + + /* Reset the CCE mode */ + (void)r128_do_wait_for_idle(dev); + R128_WRITE(R128_PM4_BUFFER_CNTL, + dev_priv->cce_mode | dev_priv->ring_sizel2qw); + (void)R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */ + R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN); + + r128_mark_vertbufs_done(dev); + return 0; +} + +int r128_eng_reset(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; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_eng_reset called without holding the lock\n"); + return -EINVAL; + } + + return r128_do_engine_reset(dev); +} + +static int r128_do_engine_flush(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 tmp; + + tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR); + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp | R128_PM4_BUFFER_DL_DONE); + + return 0; +} + +int r128_eng_flush(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; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_eng_flush called without holding the lock\n"); + return -EINVAL; + } + + return r128_do_engine_flush(dev); +} + +static int r128_do_cce_wait_for_fifo(drm_device_t *dev, int entries) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int slots = R128_READ(R128_PM4_STAT) & R128_PM4_FIFOCNT_MASK; + if (slots >= entries) return 0; + udelay(1); + } + return -EBUSY; +} + +int r128_do_cce_wait_for_idle(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int i; + + if (dev_priv->cce_is_bm_mode) { + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (*dev_priv->ring_read_ptr == dev_priv->sarea_priv->ring_write) { + int pm4stat = R128_READ(R128_PM4_STAT); + if ((pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size && + !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { + return r128_do_pixcache_flush(dev); + } + } + udelay(1); + } + return -EBUSY; + } else { + int ret = r128_do_cce_wait_for_fifo(dev, dev_priv->cce_fifo_size); + if (ret < 0) return ret; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int pm4stat = R128_READ(R128_PM4_STAT); + if (!(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { + return r128_do_pixcache_flush(dev); + } + udelay(1); + } + return -EBUSY; + } +} + +int r128_cce_idle(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; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_wait_idle called without holding the lock\n"); + return -EINVAL; + } + + return r128_do_cce_wait_for_idle(dev); +} + +static int r128_submit_packets_ring_secure(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int write = dev_priv->sarea_priv->ring_write; + int *write_ptr = dev_priv->ring_start + write; + int c = *count; + u32 tmp = 0; + int psize = 0; + int writing = 1; + int timeout; + + while (c > 0) { + tmp = *commands++; + if (!psize) { + writing = 1; + + if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= + (0x1004 << 9)) { + if ((tmp & R128_CCE_PACKET1_REG1_MASK) != + (R128_PM4_VC_FPU_SETUP << 9)) { + writing = 0; + } + } + psize = 3; + } else { + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } + } + psize--; + + if (writing) { + write++; + *write_ptr++ = tmp; + } + if (write >= dev_priv->ring_entries) { + write = 0; + write_ptr = dev_priv->ring_start; + } + timeout = 0; + while (write == *dev_priv->ring_read_ptr) { + (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); + if (timeout++ >= dev_priv->usec_timeout) + return -EBUSY; + udelay(1); + } + c--; + } + + if (write < 32) + memcpy(dev_priv->ring_end, + dev_priv->ring_start, + write * sizeof(u32)); + + /* Make sure WC cache has been flushed */ + r128_flush_write_combine(); + + dev_priv->sarea_priv->ring_write = write; + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); + + *count = 0; + + return 0; +} + +static int r128_submit_packets_pio_secure(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 tmp = 0; + int psize = 0; + int writing = 1; + int addr = R128_PM4_FIFO_DATA_EVEN; + int ret; + + while (*count > 0) { + tmp = *commands++; + if (!psize) { + writing = 1; + + if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET0_REG_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { + if ((tmp & R128_CCE_PACKET1_REG0_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2)) { + writing = 0; + } + } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= + (0x1004 << 9)) { + if ((tmp & R128_CCE_PACKET1_REG1_MASK) != + (R128_PM4_VC_FPU_SETUP << 9)) { + writing = 0; + } + } + psize = 3; + } else { + psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + } + } + psize--; + + if (writing) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) + return ret; + R128_WRITE(addr, tmp); + addr ^= 0x0004; + } + + *count -= 1; + } + + if (addr == R128_PM4_FIFO_DATA_ODD) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) return ret; + R128_WRITE(addr, R128_CCE_PACKET2); + } + + return 0; +} + +static int r128_submit_packets_ring(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int write = dev_priv->sarea_priv->ring_write; + int *write_ptr = dev_priv->ring_start + write; + int c = *count; + int timeout; + + while (c > 0) { + write++; + *write_ptr++ = *commands++; + if (write >= dev_priv->ring_entries) { + write = 0; + write_ptr = dev_priv->ring_start; + } + timeout = 0; + while (write == *dev_priv->ring_read_ptr) { + (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); + if (timeout++ >= dev_priv->usec_timeout) + return -EBUSY; + udelay(1); + } + c--; + } + + if (write < 32) + memcpy(dev_priv->ring_end, + dev_priv->ring_start, + write * sizeof(u32)); + + /* Make sure WC cache has been flushed */ + r128_flush_write_combine(); + + dev_priv->sarea_priv->ring_write = write; + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); + + *count = 0; + + return 0; +} + +static int r128_submit_packets_pio(drm_device_t *dev, + u32 *commands, int *count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int ret; + + while (*count > 1) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; + R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); + R128_WRITE(R128_PM4_FIFO_DATA_ODD, *commands++); + *count -= 2; + } + + if (*count) { + if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; + R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); + R128_WRITE(R128_PM4_FIFO_DATA_ODD, R128_CCE_PACKET2); + *count = 0; + } + + return 0; +} + +static int r128_do_submit_packets(drm_device_t *dev, u32 *buffer, int count) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + int c = count; + int ret; + + if (dev_priv->cce_is_bm_mode) { + int left = 0; + + if (c >= dev_priv->ring_entries) { + c = dev_priv->ring_entries-1; + left = count - c; + } + + /* Since this is only used by the kernel we can use the + insecure ring buffer submit packet routine */ + ret = r128_submit_packets_ring(dev, buffer, &c); + + c += left; + } else { + /* Since this is only used by the kernel we can use the + insecure PIO submit packet routine */ + ret = r128_submit_packets_pio(dev, buffer, &c); + } + + if (ret < 0) return ret; + else return c; +} + +int r128_submit_pkt(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_r128_private_t *dev_priv = dev->dev_private; + drm_r128_packet_t packet; + u32 *buffer; + int c; + int size; + int ret = 0; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_submit_pkt called without holding the lock\n"); + return -EINVAL; + } + + copy_from_user_ret(&packet, (drm_r128_packet_t *)arg, sizeof(packet), + -EFAULT); + + c = packet.count; + size = c * sizeof(*buffer); + + if (dev_priv->cce_is_bm_mode) { + int left = 0; + + if (c >= dev_priv->ring_entries) { + c = dev_priv->ring_entries-1; + size = c * sizeof(*buffer); + left = packet.count - c; + } + + if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; + copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); + + if (dev_priv->cce_secure) + ret = r128_submit_packets_ring_secure(dev, buffer, &c); + else + ret = r128_submit_packets_ring(dev, buffer, &c); + + c += left; + } else { + if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; + copy_from_user_ret(buffer, packet.buffer, size, -EFAULT); + + if (dev_priv->cce_secure) + ret = r128_submit_packets_pio_secure(dev, buffer, &c); + else + ret = r128_submit_packets_pio(dev, buffer, &c); + } + + kfree(buffer); + + packet.count = c; + copy_to_user_ret((drm_r128_packet_t *)arg, &packet, sizeof(packet), + -EFAULT); + + if (ret) return ret; + else if (c > 0) return -EAGAIN; + + return 0; +} + +static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) +{ + drm_device_dma_t *dma = dev->dma; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv; + drm_buf_t *buf; + int i, ret; + u32 cce[2]; + + /* Make sure we have valid data */ + for (i = 0; i < v->send_count; i++) { + int idx = v->send_indices[i]; + + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + idx, dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[idx]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d using buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + if (buf->pending) { + DRM_ERROR("Sending pending buffer:" + " buffer %d, offset %d\n", + v->send_indices[i], i); + return -EINVAL; + } + } + + /* Wait for idle, if we've wrapped to make sure that all pending + buffers have been processed */ + if (dev_priv->submit_age == R128_MAX_VBUF_AGE) { + if ((ret = r128_do_cce_wait_for_idle(dev)) < 0) return ret; + dev_priv->submit_age = 0; + r128_mark_vertbufs_done(dev); + } + + /* Make sure WC cache has been flushed (if in PIO mode) */ + if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine(); + + /* FIXME: Add support for sending vertex buffer to the CCE here + instead of in client code. The v->prim holds the primitive + type that should be drawn. Loop over the list buffers in + send_indices[] and submit a packet for each VB. + + This will require us to loop over the clip rects here as + well, which implies that we extend the kernel driver to allow + cliprects to be stored here. Note that the cliprects could + possibly come from the X server instead of the client, but + this will require additional changes to the DRI to allow for + this optimization. */ + + /* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */ + cce[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0); + cce[1] = dev_priv->submit_age; + if ((ret = r128_do_submit_packets(dev, cce, 2)) < 0) { + /* Until we add support for sending VBs to the CCE in + this routine, we can recover from this error. After + we add that support, we won't be able to easily + recover, so we will probably have to implement + another mechanism for handling timeouts from packets + submitted directly by the kernel. */ + return ret; + } + + /* Now that the submit packet request has succeeded, we can mark + the buffers as pending */ + for (i = 0; i < v->send_count; i++) { + buf = dma->buflist[v->send_indices[i]]; + buf->pending = 1; + + buf_priv = buf->dev_private; + buf_priv->age = dev_priv->submit_age; + } + + dev_priv->submit_age++; + + return 0; +} + +static drm_buf_t *r128_freelist_get(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv; + drm_buf_t *buf; + int i, t; + + /* FIXME: Optimize -- use freelist code */ + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if (buf->pid == 0) return buf; + } + + for (t = 0; t < dev_priv->usec_timeout; t++) { + u32 done_age = R128_READ(R128_VB_AGE_REG); + + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if (buf->pending && buf_priv->age <= done_age) { + /* The buffer has been processed, so it + can now be used */ + buf->pending = 0; + return buf; + } + } + udelay(1); + } + + r128_status(dev); + return NULL; +} + + +static int r128_get_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) +{ + drm_buf_t *buf; + int i; + + for (i = v->granted_count; i < v->request_count; i++) { + buf = r128_freelist_get(dev); + if (!buf) break; + buf->pid = current->pid; + copy_to_user_ret(&v->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&v->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++v->granted_count; + } + return 0; +} + +int r128_vertex_buf(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_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_r128_vertex_t v; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || + dev->lock.pid != current->pid) { + DRM_ERROR("r128_vertex_buf called without holding the lock\n"); + return -EINVAL; + } + + if (!dev_priv || dev_priv->is_pci) { + DRM_ERROR("r128_vertex_buf called with a PCI card\n"); + return -EINVAL; + } + + copy_from_user_ret(&v, (drm_r128_vertex_t *)arg, sizeof(v), -EFAULT); + DRM_DEBUG("%d: %d send, %d req\n", + current->pid, v.send_count, v.request_count); + + if (v.send_count < 0 || v.send_count > dma->buf_count) { + DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", + current->pid, v.send_count, dma->buf_count); + return -EINVAL; + } + if (v.request_count < 0 || v.request_count > dma->buf_count) { + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + current->pid, v.request_count, dma->buf_count); + return -EINVAL; + } + + if (v.send_count) { + retcode = r128_send_vertbufs(dev, &v); + } + + v.granted_count = 0; + + if (!retcode && v.request_count) { + retcode = r128_get_vertbufs(dev, &v); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, v.granted_count); + copy_to_user_ret((drm_r128_vertex_t *)arg, &v, sizeof(v), -EFAULT); + + return retcode; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/r128_drm.h linux/drivers/char/drm/r128_drm.h --- v2.2.17/drivers/char/drm/r128_drm.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/r128_drm.h Fri Sep 1 14:12:33 2000 @@ -0,0 +1,111 @@ +/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*- + * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Kevin E. Martin + * + */ + +#ifndef _R128_DRM_H_ +#define _R128_DRM_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmR128.h) + */ +typedef struct drm_r128_init { + enum { + R128_INIT_CCE = 0x01, + R128_CLEANUP_CCE = 0x02 + } func; + int sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_fifo_size; + int cce_secure; + int ring_size; + int usec_timeout; + + int fb_offset; + int agp_ring_offset; + int agp_read_ptr_offset; + int agp_vertbufs_offset; + int agp_indbufs_offset; + int agp_textures_offset; + int mmio_offset; +} drm_r128_init_t; + +typedef struct drm_r128_packet { + unsigned long *buffer; + int count; + int flags; +} drm_r128_packet_t; + +typedef enum drm_r128_prim { + _DRM_R128_PRIM_NONE = 0x0001, + _DRM_R128_PRIM_POINT = 0x0002, + _DRM_R128_PRIM_LINE = 0x0004, + _DRM_R128_PRIM_POLY_LINE = 0x0008, + _DRM_R128_PRIM_TRI_LIST = 0x0010, + _DRM_R128_PRIM_TRI_FAN = 0x0020, + _DRM_R128_PRIM_TRI_STRIP = 0x0040, + _DRM_R128_PRIM_TRI_TYPE2 = 0x0080 +} drm_r128_prim_t; + +typedef struct drm_r128_vertex { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int send_count; /* Number of buffers to send */ + int *send_indices; /* List of handles to buffers */ + int *send_sizes; /* Lengths of data to send */ + drm_r128_prim_t prim; /* Primitive type */ + int request_count; /* Number of buffers requested */ + int *request_indices; /* Buffer information */ + int *request_sizes; + int granted_count; /* Number of buffers granted */ +} drm_r128_vertex_t; + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (r128_sarea.h) + */ +#define R128_LOCAL_TEX_HEAP 0 +#define R128_AGP_TEX_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 64 +#define R128_LOG_TEX_GRANULARITY 16 + +typedef struct drm_tex_region { + unsigned char next, prev; + unsigned char in_use; + int age; +} drm_tex_region_t; + +typedef struct drm_r128_sarea { + drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + int tex_age[R128_NR_TEX_HEAPS]; + int ctx_owner; + int ring_write; +} drm_r128_sarea_t; + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/r128_drv.c linux/drivers/char/drm/r128_drv.c --- v2.2.17/drivers/char/drm/r128_drv.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/r128_drv.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,730 @@ +/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- + * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Kevin E. Martin + * + */ + +#include +#include "drmP.h" +#include "r128_drv.h" + +#include + +static void __attribute__((unused)) unused(void) +{ + agp_enable(0); +} + +#define R128_NAME "r128" +#define R128_DESC "ATI Rage 128" +#define R128_DATE "20000719" +#define R128_MAJOR 1 +#define R128_MINOR 0 +#define R128_PATCHLEVEL 0 + +static drm_device_t r128_device; +drm_ctx_t r128_res_ctx; + +static struct file_operations r128_fops = { +#if LINUX_VERSION_CODE >= 0x020400 + /* This started being used during 2.4.0-test */ + owner: THIS_MODULE, +#endif + open: r128_open, + flush: drm_flush, + release: r128_release, + ioctl: r128_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +static struct miscdevice r128_misc = { + minor: MISC_DYNAMIC_MINOR, + name: R128_NAME, + fops: &r128_fops, +}; + +static drm_ioctl_desc_t r128_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { r128_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_BUFS)] = { r128_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { r128_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { r128_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { r128_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { r128_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { r128_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { r128_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { r128_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { r128_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)] = { r128_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { r128_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_agp_enable, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_agp_info, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_agp_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_agp_free, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_agp_bind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_agp_unbind, 1, 1 }, +#endif + + [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_init_cce, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_eng_reset, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_FLUSH)] = { r128_eng_flush, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_IDLE)] = { r128_cce_idle, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 }, +}; +#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) + +#ifdef MODULE +static char *r128 = NULL; +#endif + +MODULE_AUTHOR("VA Linux Systems, Inc."); +MODULE_DESCRIPTION("r128"); +MODULE_PARM(r128, "s"); + +#ifndef MODULE +/* r128_options 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. + */ + +static int __init r128_options(char *str) +{ + drm_parse_options(str); + return 1; +} + +__setup("r128=", r128_options); +#endif + +static int r128_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); + + drm_dma_setup(dev); + + 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_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); + + r128_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 r128_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; + } + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + /* Clear AGP information */ + if (dev->agp) { + drm_agp_mem_t *entry; + drm_agp_mem_t *nexte; + + /* Remove AGP resources, but leave dev->agp + intact until r128_cleanup is called. */ + for (entry = dev->agp->memory; entry; entry = nexte) { + nexte = entry->next; + if (entry->bound) drm_unbind_agp(entry->memory); + drm_free_agp(entry->memory, entry->pages); + drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + } + dev->agp->memory = NULL; + + if (dev->agp->acquired && drm_agp.release) + (*drm_agp.release)(); + + dev->agp->acquired = 0; + dev->agp->enabled = 0; + } +#endif + + /* 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; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + 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; + } + + drm_dma_takedown(dev); + + dev->queue_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; +} + +/* r128_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +static int r128_init(void) +{ + int retcode; + drm_device_t *dev = &r128_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(r128); +#endif + + if ((retcode = misc_register(&r128_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", R128_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, r128_misc.minor); + dev->name = R128_NAME; + + drm_mem_init(); + drm_proc_init(dev); + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + dev->agp = drm_agp_init(); + if (dev->agp == NULL) { + DRM_ERROR("Cannot initialize agpgart module.\n"); + drm_proc_cleanup(); + misc_deregister(&r128_misc); + r128_takedown(dev); + return -ENOMEM; + } + +#ifdef CONFIG_MTRR + dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size*1024*1024, + MTRR_TYPE_WRCOMB, + 1); +#endif +#endif + + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&r128_misc); + r128_takedown(dev); + return retcode; + } + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + R128_NAME, + R128_MAJOR, + R128_MINOR, + R128_PATCHLEVEL, + R128_DATE, + r128_misc.minor); + + return 0; +} + +/* r128_cleanup is called via cleanup_module at module unload time. */ + +static void r128_cleanup(void) +{ + drm_device_t *dev = &r128_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&r128_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + drm_ctxbitmap_cleanup(dev); + r128_takedown(dev); +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + if (dev->agp) { + drm_agp_uninit(); + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +#endif +} + +module_init(r128_init); +module_exit(r128_cleanup); + + +int r128_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 = R128_MAJOR; + version.version_minor = R128_MINOR; + version.version_patchlevel = R128_PATCHLEVEL; + + DRM_COPY(version.name, R128_NAME); + DRM_COPY(version.date, R128_DATE); + DRM_COPY(version.desc, R128_DESC); + + copy_to_user_ret((drm_version_t *)arg, + &version, + sizeof(version), + -EFAULT); + return 0; +} + +int r128_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &r128_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return r128_setup(dev); + } + spin_unlock(&dev->count_lock); + } + + return retcode; +} + +int r128_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + int retcode = 0; + + lock_kernel(); + dev = priv->dev; + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_release(inode, filp))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + 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); + unlock_kernel(); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return r128_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + + unlock_kernel(); + return retcode; +} + +/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int r128_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 >= R128_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &r128_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 r128_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 + r128. 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 == r128_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 (;;) { + current->state = TASK_INTERRUPTIBLE; + 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); +#if 1 + current->policy |= SCHED_YIELD; +#endif + 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 != r128_res_ctx.handle && + dev->last_context != r128_res_ctx.handle) { + add_wait_queue(&dev->context_wait, &entry); + current->state = TASK_INTERRUPTIBLE; + /* PRE: dev->last_context != lock.context */ + r128_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 + r128_quiescent(dev); +#endif + } + } + +#if LINUX_VERSION_CODE < 0x020400 + if (lock.context != r128_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY/4; + } +#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 r128_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"); + } + } + +#if LINUX_VERSION_CODE < 0x020400 + if (lock.context != r128_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY; + } +#endif + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/r128_drv.h linux/drivers/char/drm/r128_drv.h --- v2.2.17/drivers/char/drm/r128_drv.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/r128_drv.h Fri Sep 1 14:12:33 2000 @@ -0,0 +1,224 @@ +/* r128_drv.h -- Private header for r128 driver -*- linux-c -*- + * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: Rickard E. (Rik) Faith + * Kevin E. Martin + * + */ + +#ifndef _R128_DRV_H_ +#define _R128_DRV_H_ + +typedef struct drm_r128_private { + int is_pci; + + int cce_mode; + int cce_fifo_size; + int cce_is_bm_mode; + int cce_secure; + + drm_r128_sarea_t *sarea_priv; + + __volatile__ u32 *ring_read_ptr; + + u32 *ring_start; + u32 *ring_end; + int ring_size; + int ring_sizel2qw; + int ring_entries; + + int submit_age; + + int usec_timeout; + + drm_map_t *sarea; + drm_map_t *fb; + drm_map_t *agp_ring; + drm_map_t *agp_read_ptr; + drm_map_t *agp_vertbufs; + drm_map_t *agp_indbufs; + drm_map_t *agp_textures; + drm_map_t *mmio; +} drm_r128_private_t; + +typedef struct drm_r128_buf_priv { + u32 age; +} drm_r128_buf_priv_t; + + /* r128_drv.c */ +extern int r128_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_open(struct inode *inode, struct file *filp); +extern int r128_release(struct inode *inode, struct file *filp); +extern int r128_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* r128_dma.c */ +extern int r128_init_cce(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_eng_reset(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_eng_flush(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_submit_pkt(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_cce_idle(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_vertex_buf(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* r128_bufs.c */ +extern int r128_addbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_mapbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* r128_context.c */ +extern int r128_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int r128_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int r128_context_switch(drm_device_t *dev, int old, int new); +extern int r128_context_switch_complete(drm_device_t *dev, int new); + + +/* Register definitions, register access macros and drmAddMap constants + * for Rage 128 kernel driver. + */ + +#define R128_PC_NGUI_CTLSTAT 0x0184 +# define R128_PC_FLUSH_ALL 0x00ff +# define R128_PC_BUSY (1 << 31) + +#define R128_CLOCK_CNTL_INDEX 0x0008 +#define R128_CLOCK_CNTL_DATA 0x000c +# define R128_PLL_WR_EN (1 << 7) + +#define R128_MCLK_CNTL 0x000f +# define R128_FORCE_GCP (1 << 16) +# define R128_FORCE_PIPE3D_CP (1 << 17) +# define R128_FORCE_RCP (1 << 18) + +#define R128_GEN_RESET_CNTL 0x00f0 +# define R128_SOFT_RESET_GUI (1 << 0) + +#define R128_PM4_BUFFER_CNTL 0x0704 +# define R128_PM4_NONPM4 (0 << 28) +# define R128_PM4_192PIO (1 << 28) +# define R128_PM4_192BM (2 << 28) +# define R128_PM4_128PIO_64INDBM (3 << 28) +# define R128_PM4_128BM_64INDBM (4 << 28) +# define R128_PM4_64PIO_128INDBM (5 << 28) +# define R128_PM4_64BM_128INDBM (6 << 28) +# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) +# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) +# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) + + +#define R128_PM4_BUFFER_DL_RPTR 0x0710 +#define R128_PM4_BUFFER_DL_WPTR 0x0714 +# define R128_PM4_BUFFER_DL_DONE (1 << 31) + +#define R128_PM4_VC_FPU_SETUP 0x071c + +#define R128_PM4_STAT 0x07b8 +# define R128_PM4_FIFOCNT_MASK 0x0fff +# define R128_PM4_BUSY (1 << 16) +# define R128_PM4_GUI_ACTIVE (1 << 31) + +#define R128_PM4_BUFFER_ADDR 0x07f0 +#define R128_PM4_MICRO_CNTL 0x07fc +# define R128_PM4_MICRO_FREERUN (1 << 30) + +#define R128_PM4_FIFO_DATA_EVEN 0x1000 +#define R128_PM4_FIFO_DATA_ODD 0x1004 + +#define R128_GUI_SCRATCH_REG0 0x15e0 +#define R128_GUI_SCRATCH_REG1 0x15e4 +#define R128_GUI_SCRATCH_REG2 0x15e8 +#define R128_GUI_SCRATCH_REG3 0x15ec +#define R128_GUI_SCRATCH_REG4 0x15f0 +#define R128_GUI_SCRATCH_REG5 0x15f4 + +#define R128_GUI_STAT 0x1740 +# define R128_GUI_FIFOCNT_MASK 0x0fff +# define R128_GUI_ACTIVE (1 << 31) + + +/* CCE command packets */ +#define R128_CCE_PACKET0 0x00000000 +#define R128_CCE_PACKET1 0x40000000 +#define R128_CCE_PACKET2 0x80000000 +# define R128_CCE_PACKET_MASK 0xC0000000 +# define R128_CCE_PACKET_COUNT_MASK 0x3fff0000 +# define R128_CCE_PACKET0_REG_MASK 0x000007ff +# define R128_CCE_PACKET1_REG0_MASK 0x000007ff +# define R128_CCE_PACKET1_REG1_MASK 0x003ff800 + + +#define R128_MAX_USEC_TIMEOUT 100000 /* 100 ms */ + + +#define R128_BASE(reg) ((u32)(dev_priv->mmio->handle)) +#define R128_ADDR(reg) (R128_BASE(reg) + reg) + +#define R128_DEREF(reg) *(__volatile__ int *)R128_ADDR(reg) +#define R128_READ(reg) R128_DEREF(reg) +#define R128_WRITE(reg,val) do { R128_DEREF(reg) = val; } while (0) + +#define R128_DEREF8(reg) *(__volatile__ char *)R128_ADDR(reg) +#define R128_READ8(reg) R128_DEREF8(reg) +#define R128_WRITE8(reg,val) do { R128_DEREF8(reg) = val; } while (0) + +#define R128_WRITE_PLL(addr,val) \ +do { \ + R128_WRITE8(R128_CLOCK_CNTL_INDEX, ((addr) & 0x1f) | R128_PLL_WR_EN); \ + R128_WRITE(R128_CLOCK_CNTL_DATA, (val)); \ +} while (0) + +extern int R128_READ_PLL(drm_device_t *dev, int addr); + +#define R128CCE0(p,r,n) ((p) | ((n) << 16) | ((r) >> 2)) +#define R128CCE1(p,r1,r2) ((p) | (((r2) >> 2) << 11) | ((r1) >> 2)) +#define R128CCE2(p) ((p)) +#define R128CCE3(p,n) ((p) | ((n) << 16)) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/tdfx_context.c linux/drivers/char/drm/tdfx_context.c --- v2.2.17/drivers/char/drm/tdfx_context.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/tdfx_context.c Fri Sep 1 14:12:33 2000 @@ -0,0 +1,209 @@ +/* tdfx_context.c -- IOCTLs for tdfx contexts -*- linux-c -*- + * Created: Thu Oct 7 10:50:22 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * Daryll Strauss + * + */ + +#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) +{ + return drm_ctxbitmap_next(dev); +} + +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); + if (ctx.handle == -1) { + DRM_DEBUG("Not enough free contexts.\n"); + /* Should this return -EBUSY instead? */ + return -ENOMEM; + } + + 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_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); + drm_ctxbitmap_free(dev, ctx.handle); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/tdfx_drv.c linux/drivers/char/drm/tdfx_drv.c --- v2.2.17/drivers/char/drm/tdfx_drv.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/tdfx_drv.c Tue Nov 28 20:14:54 2000 @@ -0,0 +1,693 @@ +/* tdfx.c -- tdfx driver -*- linux-c -*- + * Created: Thu Oct 7 10:38:32 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * Daryll Strauss + * + */ + +#include +#include "drmP.h" +#include "tdfx_drv.h" + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +#include +#endif + +static void __attribute__((unused)) unused(void) +{ +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + agp_enable(0); +#endif +} + +#define TDFX_NAME "tdfx" +#define TDFX_DESC "3dfx Banshee/Voodoo3+" +#define TDFX_DATE "20000719" +#define TDFX_MAJOR 1 +#define TDFX_MINOR 0 +#define TDFX_PATCHLEVEL 0 + +static drm_device_t tdfx_device; +drm_ctx_t tdfx_res_ctx; + +static struct file_operations tdfx_fops = { +#if LINUX_VERSION_CODE >= 0x020322 + /* This started being used approx. 2.3.34 */ + owner: THIS_MODULE, +#endif + open: tdfx_open, + flush: drm_flush, + release: tdfx_release, + ioctl: tdfx_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +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 }, +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_unbind, 1, 1}, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_bind, 1, 1}, +#endif +}; +#define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls) + +#ifdef MODULE +static char *tdfx = NULL; +#endif + +MODULE_AUTHOR("VA Linux Systems, Inc."); +MODULE_DESCRIPTION("tdfx"); +MODULE_PARM(tdfx, "s"); + +#ifndef MODULE +/* tdfx_options 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. + */ + +static int __init tdfx_options(char *str) +{ + drm_parse_options(str); + return 1; +} + +__setup("tdfx=", tdfx_options); +#endif + +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; + } +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + /* Clear AGP information */ + if (dev->agp) { + drm_agp_mem_t *temp; + drm_agp_mem_t *temp_next; + + temp = dev->agp->memory; + while(temp != NULL) { + temp_next = temp->next; + drm_free_agp(temp->memory, temp->pages); + drm_free(temp, sizeof(*temp), DRM_MEM_AGPLISTS); + temp = temp_next; + } + if (dev->agp->acquired) (*drm_agp.release)(); + } +#endif + /* 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; + case _DRM_AGP: + /* Do nothing here, because this is all + handled in the AGP/GART driver. */ + 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). */ + +static 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); +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + dev->agp = drm_agp_init(); +#endif + if((retcode = drm_ctxbitmap_init(dev))) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + drm_proc_cleanup(); + misc_deregister(&tdfx_misc); + tdfx_takedown(dev); + return retcode; + } + + 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. */ + +static 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"); + } + drm_ctxbitmap_cleanup(dev); + tdfx_takedown(dev); +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + if (dev->agp) { + drm_agp_uninit(); + drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + dev->agp = NULL; + } +#endif +} + +module_init(tdfx_init); +module_exit(tdfx_cleanup); + + +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))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + 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; + int retcode = 0; + + lock_kernel(); + dev = priv->dev; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_release(inode, filp))) { +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + 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); + unlock_kernel(); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + unlock_kernel(); + return tdfx_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + + unlock_kernel(); + 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 (;;) { + current->state = TASK_INTERRUPTIBLE; + 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); +#if 1 + current->policy |= SCHED_YIELD; +#endif + 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 + } + } + +#if LINUX_VERSION_CODE < 0x020400 + if (lock.context != tdfx_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY/4; + } +#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"); + } + } + +#if LINUX_VERSION_CODE < 0x020400 + if (lock.context != tdfx_res_ctx.handle) { + current->counter = 5; + current->priority = DEF_PRIORITY; + } +#endif + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/tdfx_drv.h linux/drivers/char/drm/tdfx_drv.h --- v2.2.17/drivers/char/drm/tdfx_drv.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/tdfx_drv.h Fri Sep 1 14:12:33 2000 @@ -0,0 +1,67 @@ +/* tdfx_drv.h -- Private header for tdfx driver -*- linux-c -*- + * Created: Thu Oct 7 10:40:04 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * Daryll Strauss + * + */ + +#ifndef _TDFX_DRV_H_ +#define _TDFX_DRV_H_ + + /* tdfx_drv.c */ +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 -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/drm/vm.c linux/drivers/char/drm/vm.c --- v2.2.17/drivers/char/drm/vm.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/drm/vm.c Tue Nov 28 17:33:24 2000 @@ -0,0 +1,372 @@ +/* vm.c -- Memory mapping for DRM -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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. + * + * Authors: + * Rickard E. (Rik) Faith + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +struct vm_operations_struct drm_vm_ops = { + nopage: drm_vm_nopage, + open: drm_vm_open, + close: drm_vm_close, +}; + +struct vm_operations_struct drm_vm_shm_ops = { + nopage: drm_vm_shm_nopage, + open: drm_vm_open, + close: drm_vm_close, +}; + +struct vm_operations_struct drm_vm_shm_lock_ops = { + nopage: drm_vm_shm_nopage_lock, + open: drm_vm_open, + close: drm_vm_close, +}; + +struct vm_operations_struct drm_vm_dma_ops = { + nopage: drm_vm_dma_nopage, + open: drm_vm_open, + 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 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 +{ +#if LINUX_VERSION_CODE >= 0x020300 + drm_map_t *map = (drm_map_t *)vma->vm_private_data; +#else + drm_map_t *map = (drm_map_t *)vma->vm_pte; +#endif + unsigned long physical; + unsigned long offset; + + if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!map) return NOPAGE_OOM; /* Nothing allocated */ + + offset = address - vma->vm_start; + physical = (unsigned long)map->handle + offset; + atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ + + DRM_DEBUG("0x%08lx => 0x%08lx\n", address, physical); +#if LINUX_VERSION_CODE < 0x020317 + return physical; +#else + return virt_to_page(physical); +#endif +} + +#if LINUX_VERSION_CODE < 0x020317 +unsigned long drm_vm_shm_nopage_lock(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_lock(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; + unsigned long physical; + unsigned long offset; + unsigned long page; + + 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; + physical = (unsigned long)dev->lock.hw_lock + offset; + atomic_inc(&virt_to_page(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 virt_to_page(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; + drm_device_dma_t *dma = dev->dma; + unsigned long physical; + unsigned long offset; + unsigned long page; + + 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_[pg]off[set] should be 0 */ + page = offset >> PAGE_SHIFT; + physical = dma->pagelist[page] + (offset & (~PAGE_MASK)); + atomic_inc(&virt_to_page(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 virt_to_page(physical); +#endif +} + +void drm_vm_open(struct vm_area_struct *vma) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; +#if DRM_DEBUG_CODE + drm_vma_entry_t *vma_entry; +#endif + + DRM_DEBUG("0x%08lx,0x%08lx\n", + vma->vm_start, vma->vm_end - vma->vm_start); + atomic_inc(&dev->vma_count); +#if LINUX_VERSION_CODE < 0x020333 + /* The map can exist after the fd is closed. */ + MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + + +#if DRM_DEBUG_CODE + vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); + if (vma_entry) { + down(&dev->struct_sem); + vma_entry->vma = vma; + vma_entry->next = dev->vmalist; + vma_entry->pid = current->pid; + dev->vmalist = vma_entry; + up(&dev->struct_sem); + } +#endif +} + +void drm_vm_close(struct vm_area_struct *vma) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; +#if DRM_DEBUG_CODE + drm_vma_entry_t *pt, *prev; +#endif + + DRM_DEBUG("0x%08lx,0x%08lx\n", + vma->vm_start, vma->vm_end - vma->vm_start); +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_dec(&dev->vma_count); + +#if DRM_DEBUG_CODE + down(&dev->struct_sem); + for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { + if (pt->vma == vma) { + if (prev) { + prev->next = pt->next; + } else { + dev->vmalist = pt->next; + } + drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + break; + } + } + up(&dev->struct_sem); +#endif +} + +int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + drm_device_dma_t *dma; + unsigned long length = vma->vm_end - vma->vm_start; + + lock_kernel(); + dev = priv->dev; + dma = dev->dma; + 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 (!dma || (length >> PAGE_SHIFT) != dma->page_count) { + unlock_kernel(); + return -EINVAL; + } + unlock_kernel(); + + vma->vm_ops = &drm_vm_dma_ops; + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + +#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ + /* In Linux 2.2.3 and above, this is + handled in do_mmap() in mm/mmap.c. */ + ++filp->f_count; +#endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ + drm_vm_open(vma); + return 0; +} + +int drm_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + int i; + + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + + if (!VM_OFFSET(vma)) return drm_mmap_dma(filp, vma); + + /* 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 + DRI client only has to do this mapping + once, so it doesn't have to be optimized + for performance, even if the list was a + bit longer. */ + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (map->offset == VM_OFFSET(vma)) break; + } + + if (i >= dev->map_count) return -EINVAL; + if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) + return -EPERM; + + /* Check for valid size. */ + if (map->size != vma->vm_end - vma->vm_start) return -EINVAL; + + if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { + vma->vm_flags &= VM_MAYWRITE; +#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 + } + + switch (map->type) { + case _DRM_FRAME_BUFFER: + case _DRM_REGISTERS: + case _DRM_AGP: + if (VM_OFFSET(vma) >= __pa(high_memory)) { +#if defined(__i386__) + if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; + pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; + } +#elif defined(__ia64__) + if (map->type != _DRM_AGP) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#endif + vma->vm_flags |= VM_IO; /* not in core dump */ + } + if (remap_page_range(vma->vm_start, + VM_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," + " offset = 0x%lx\n", + map->type, + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + vma->vm_ops = &drm_vm_ops; + break; + case _DRM_SHM: + if (map->flags & _DRM_CONTAINS_LOCK) + vma->vm_ops = &drm_vm_shm_lock_ops; + else { + vma->vm_ops = &drm_vm_shm_ops; +#if LINUX_VERSION_CODE >= 0x020300 + vma->vm_private_data = (void *)map; +#else + vma->vm_pte = (unsigned long)map; +#endif + } + + /* Don't let this area swap. Change when + DRM_KERNEL advisory is supported. */ + vma->vm_flags |= VM_LOCKED; + break; + default: + return -EINVAL; /* This should never happen. */ + } + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + +#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ + /* In Linux 2.2.3 and above, this is + handled in do_mmap() in mm/mmap.c. */ + ++filp->f_count; +#endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ + drm_vm_open(vma); + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/dtlk.c linux/drivers/char/dtlk.c --- v2.2.17/drivers/char/dtlk.c Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/dtlk.c Mon Oct 2 10:14:40 2000 @@ -61,7 +61,7 @@ #include /* for verify_area */ #include /* for -EBUSY */ #include /* for check_region, request_region */ -#include /* for loops_per_sec */ +#include /* for loops_per_jiffy */ #include /* for put_user_byte */ #include /* for inb_p, outb_p, inb, outb, etc. */ #include /* for get_user, etc. */ @@ -154,7 +154,7 @@ if (minor != DTLK_MINOR || !dtlk_has_indexing) return -EINVAL; - for (retries = 0; retries < loops_per_sec / 10; retries++) { + for (retries = 0; retries < 10000000; retries++) { while (i < count && dtlk_readable()) { ch = dtlk_read_lpc(); /* printk("dtlk_read() reads 0x%02x\n", ch); */ @@ -168,7 +168,7 @@ break; dtlk_delay(10); } - if (retries == loops_per_sec) + if (retries == 10000000) printk(KERN_ERR "dtlk_read times out\n"); TRACE_RET; return -EAGAIN; @@ -222,7 +222,7 @@ up to 250 usec for the RDY bit to go nonzero. */ for (retries = 0; - retries < loops_per_sec / 4000; + retries < 25000; retries++) if (inb_p(dtlk_port_tts) & TTS_WRITABLE) @@ -479,7 +479,7 @@ for (i = 0; i < 10; i++) \ { \ buffer[b++] = inb_p(dtlk_port_lpc); \ - __delay(loops_per_sec/1000000); \ + udelay(1); \ } char buffer[1000]; int b = 0, i, j; @@ -490,7 +490,7 @@ LOOK dtlk_write_bytes("\0012I\r", 4); buffer[b++] = 0; - __delay(50 * loops_per_sec / 1000); + mdelay(50); outb_p(0xff, dtlk_port_lpc); buffer[b++] = 0; LOOK @@ -509,12 +509,12 @@ for (i = 0; i < 10; i++) \ { \ buffer[b++] = inb_p(dtlk_port_tts); \ - __delay(loops_per_sec/1000000); /* 1 us */ \ + udelay(1); \ } char buffer[1000]; int b = 0, i, j; - __delay(loops_per_sec / 100); /* 10 ms */ + mdelay(10); LOOK outb_p(0x03, dtlk_port_tts); buffer[b++] = 0; @@ -646,7 +646,7 @@ /* acknowledging a read takes 3-4 usec. Here, we wait up to 20 usec for the acknowledgement */ - retries = (loops_per_sec * 20) / 1000000; + retries = 2000; while (inb_p(dtlk_port_lpc) != 0x7f && --retries > 0); if (retries == 0) printk(KERN_ERR "dtlk_read_lpc() timeout\n"); @@ -704,7 +704,7 @@ /* the RDY bit goes zero 2-3 usec after writing, and goes 1 again 180-190 usec later. Here, we wait up to 10 usec for the RDY bit to go zero. */ - for (retries = 0; retries < loops_per_sec / 100000; retries++) + for (retries = 0; retries < 1000; retries++) if ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0) break; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/epca.c linux/drivers/char/epca.c --- v2.2.17/drivers/char/epca.c Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/epca.c Mon Oct 2 10:14:40 2000 @@ -1681,7 +1681,7 @@ memory. ------------------------------------------------------------------*/ - ulong flags, save_loops_per_sec; + ulong flags; int crd; struct board_info *bd; unsigned char board_id = 0; @@ -1825,9 +1825,10 @@ /* --------------------------------------------------------------------- loops_per_sec hasn't been set at this point :-(, so fake it out... I set it, so that I can use the __delay() function. + + We don't use __delay(), so we don't need to fake it. + ------------------------------------------------------------------------ */ - save_loops_per_sec = loops_per_sec; - loops_per_sec = 13L * 500000L; save_flags(flags); cli(); @@ -1960,7 +1961,6 @@ if (tty_register_driver(&pc_info)) panic("Couldn't register Digi PC/ info "); - loops_per_sec = save_loops_per_sec; /* reset it to what it should be */ /* ------------------------------------------------------------------- Start up the poller to check for events on all enabled boards diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c --- v2.2.17/drivers/char/generic_serial.c Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/generic_serial.c Thu Dec 7 14:45:41 2000 @@ -29,7 +29,7 @@ #include #include -#define DEBUG +#define DEBUG 1 static char * tmp_buf; static DECLARE_MUTEX(tmp_buf_sem); @@ -367,7 +367,7 @@ struct gs_port *port = ptr; long end_jiffies; int jiffies_to_transmit, charsleft = 0, rv = 0; - int to, rcib; + int rcib; func_enter(); @@ -391,6 +391,7 @@ return rv; } /* stop trying: now + twice the time it would normally take + seconds */ + if (timeout == 0) timeout = MAX_SCHEDULE_TIMEOUT; end_jiffies = jiffies; if (timeout != MAX_SCHEDULE_TIMEOUT) end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0; @@ -399,11 +400,9 @@ gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", jiffies, end_jiffies, end_jiffies-jiffies); - to = 100; /* the expression is actually jiffies < end_jiffies, but that won't work around the wraparound. Tricky eh? */ - while (to-- && - (charsleft = gs_real_chars_in_buffer (port->tty)) && + while ((charsleft = gs_real_chars_in_buffer (port->tty)) && time_after (end_jiffies, jiffies)) { /* Units check: chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies! @@ -576,7 +575,7 @@ port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE); port->tty = NULL; port->count = 0; - + port->event = 0; wake_up_interruptible(&port->open_wait); func_exit (); } @@ -751,9 +750,13 @@ if (!port) return; if (!port->tty) { + port->rd->hungup (port); + return; +#if 0 /* This seems to happen when this is called from vhangup. */ gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->tty is NULL\n"); port->tty = tty; +#endif } save_flags(flags); cli(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c --- v2.2.17/drivers/char/i810_rng.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/i810_rng.c Tue Nov 28 22:22:24 2000 @@ -0,0 +1,489 @@ +/* + + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000 Jeff Garzik + + Driver Web site: http://gtf.org/garzik/drivers/i810_rng/ + + + + Based on: + Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet + May 1999 Order Number: 290658-002 R + + Intel 82802 Firmware Hub: Random Number Generator + Programmer's Reference Manual + December 1999 Order Number: 298029-001 R + + Intel 82802 Firmware HUB Random Number Generator Driver + Copyright (c) 2000 Matt Sottek + + Special thanks to Matt Sottek. I did the "guts", he + did the "brains" and all the testing. (Anybody wanna send + me an i810 or i820?) + + ---------------------------------------------------------- + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + ---------------------------------------------------------- + + From the firmware hub datasheet: + + The Firmware Hub integrates a Random Number Generator (RNG) + using thermal noise generated from inherently random quantum + mechanical properties of silicon. When not generating new random + bits the RNG circuitry will enter a low power state. Intel will + provide a binary software driver to give third party software + access to our RNG for use as a security feature. At this time, + the RNG is only to be used with a system in an OS-present state. + + ---------------------------------------------------------- + + Theory of operation: + + Character driver. Using the standard open() + and read() system calls, you can read random data from + the i810 RNG device. This data is NOT CHECKED by any + fitness tests, and could potentially be bogus (if the + hardware is faulty or has been tampered with). + + /dev/intel_rng is char device major 10, minor 183. + + + ---------------------------------------------------------- + + Driver notes: + + * In order to unload the i810_rng module, you must first + make sure all users of the character device have closed + + * FIXME: Currently only one open() of the character device is allowed. + If another user tries to open() the device, they will get an + -EBUSY error. Instead, this really should either support + multiple simultaneous users of the character device (not hard), + or simply block open() until the current user of the chrdev + calls close(). + + * FIXME: support poll() + + * FIXME: should we be crazy and support mmap()? + + ---------------------------------------------------------- + + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * core module and version information + */ +#define RNG_VERSION "0.6.2-2.2.x" +#define RNG_MODULE_NAME "i810_rng" +#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION +#define PFX RNG_MODULE_NAME ": " + + +/* + * debugging macros + */ +#undef RNG_DEBUG /* define to 1 to enable copious debugging info */ + +#ifdef RNG_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ +#if RNG_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + + +/* + * misc helper macros + */ +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + + +/* + * RNG registers (offsets from rng_mem) + */ +#define RNG_HW_STATUS 0 +#define RNG_PRESENT 0x40 +#define RNG_ENABLED 0x01 +#define RNG_STATUS 1 +#define RNG_DATA_PRESENT 0x01 +#define RNG_DATA 2 + +#define RNG_ADDR 0xFFBC015F +#define RNG_ADDR_LEN 3 + +#define RNG_MISCDEV_MINOR 183 /* official */ + + +/* + * various RNG status variables. they are globals + * as we only support a single RNG device + */ +static int rng_allocated; /* is someone using the RNG region? */ +static int rng_hw_enabled; /* is the RNG h/w enabled? */ +static int rng_use_count; /* number of times RNG has been enabled */ +static void *rng_mem; /* token to our ioremap'd RNG register area */ +static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */ +static int rng_open; /* boolean, 0 (false) if chrdev is closed, 1 (true) if open */ + +/* + * inlined helper functions for accessing RNG registers + */ +static inline u8 rng_hwstatus (void) +{ + assert (rng_mem != NULL); + return readb (rng_mem + RNG_HW_STATUS); +} + + +static inline void rng_hwstatus_set (u8 hw_status) +{ + assert (rng_mem != NULL); + writeb (hw_status, rng_mem + RNG_HW_STATUS); +} + + +static inline int rng_data_present (void) +{ + assert (rng_mem != NULL); + assert (rng_hw_enabled == 1); + + return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0; +} + + +static inline int rng_data_read (void) +{ + assert (rng_mem != NULL); + assert (rng_hw_enabled == 1); + + return readb (rng_mem + RNG_DATA); +} + + +/* + * rng_enable - enable or disable the RNG hardware + */ +static int rng_enable (int enable) +{ + int rc = 0; + u8 hw_status; + + DPRINTK ("ENTER\n"); + + spin_lock (&rng_lock); + + hw_status = rng_hwstatus (); + + if (enable) { + rng_hw_enabled = 1; + rng_use_count++; + MOD_INC_USE_COUNT; + } else { + rng_use_count--; + if (rng_use_count == 0) + rng_hw_enabled = 0; + MOD_DEC_USE_COUNT; + } + + if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) { + rng_hwstatus_set (hw_status | RNG_ENABLED); + printk (KERN_INFO PFX "RNG h/w enabled\n"); + } + + else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) { + rng_hwstatus_set (hw_status & ~RNG_ENABLED); + printk (KERN_INFO PFX "RNG h/w disabled\n"); + } + + spin_unlock (&rng_lock); + + if ((!!enable) != (!!(rng_hwstatus () & RNG_ENABLED))) { + printk (KERN_ERR PFX "Unable to %sable the RNG\n", + enable ? "en" : "dis"); + rc = -EIO; + } + + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + + +static int rng_dev_open (struct inode *inode, struct file *filp) +{ + int rc = -EINVAL; + + MOD_INC_USE_COUNT; + + if ((filp->f_mode & FMODE_READ) == 0) + goto err_out; + if (filp->f_mode & FMODE_WRITE) + goto err_out; + + spin_lock (&rng_lock); + + /* only allow one open of this device, exit with -EBUSY if already open */ + /* FIXME: we should sleep on a semaphore here, unless O_NONBLOCK */ + if (rng_open) { + spin_unlock (&rng_lock); + rc = -EBUSY; + goto err_out; + } + + rng_open = 1; + + spin_unlock (&rng_lock); + + if (rng_enable(1) != 0) { + spin_lock (&rng_lock); + rng_open = 0; + spin_unlock (&rng_lock); + rc = -EIO; + goto err_out; + } + + return 0; + +err_out: + MOD_DEC_USE_COUNT; + return rc; +} + + +static int rng_dev_release (struct inode *inode, struct file *filp) +{ + + if (rng_enable(0) != 0) + return -EIO; + + spin_lock (&rng_lock); + rng_open = 0; + spin_unlock (&rng_lock); + + MOD_DEC_USE_COUNT; + return 0; +} + + +static ssize_t rng_dev_read (struct file *filp, char * buf, size_t size, + loff_t *offp) +{ + int have_data, copied = 0; + u8 data=0; + u8 *page; + + if (size < 1) + return 0; + + page = (unsigned char *) get_free_page (GFP_KERNEL); + if (!page) + return -ENOMEM; + +read_loop: + /* using the fact that read() can return >0 but + * less than the requested amount, we simply + * read up to PAGE_SIZE or buffer size, whichever + * is smaller, and return that data. + */ + if ((copied == size) || (copied == PAGE_SIZE)) { + size_t tmpsize = (copied == size) ? size : PAGE_SIZE; + int rc = copy_to_user (buf, page, tmpsize); + free_page ((long)page); + if (rc) return rc; + return tmpsize; + } + + spin_lock (&rng_lock); + + have_data = 0; + if (rng_data_present ()) { + data = rng_data_read (); + have_data = 1; + } + + spin_unlock (&rng_lock); + + if (have_data) { + page[copied] = data; + copied++; + } else { + if (filp->f_flags & O_NONBLOCK) { + free_page ((long)page); + return -EAGAIN; + } + } + + if (current->need_resched) + schedule (); + + if (signal_pending (current)) { + free_page ((long)page); + return -ERESTARTSYS; + } + + goto read_loop; +} + + +/* + * rng_init_one - look for and attempt to init a single RNG + */ +static int __init rng_init_one (struct pci_dev *dev) +{ + int rc; + u8 hw_status; + + DPRINTK ("ENTER\n"); + + if (rng_allocated) { + printk (KERN_ERR PFX "this driver only supports one RNG\n"); + DPRINTK ("EXIT, returning -EBUSY\n"); + return -EBUSY; + } + + rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN); + if (rng_mem == NULL) { + printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); + DPRINTK ("EXIT, returning -EBUSY\n"); + rc = -EBUSY; + goto err_out; + } + + /* Check for Intel 82802 */ + hw_status = rng_hwstatus (); + if ((hw_status & RNG_PRESENT) == 0) { + printk (KERN_ERR PFX "RNG not detected\n"); + DPRINTK ("EXIT, returning -ENODEV\n"); + rc = -ENODEV; + goto err_out; + } + + rng_allocated = 1; + + rc = rng_enable (0); + if (rc) { + printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); + goto err_out; + } + + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out: + if (rng_mem) + iounmap (rng_mem); + return rc; +} + + +/* + * Data for PCI driver interface + */ + +MODULE_AUTHOR("Jeff Garzik, Matt Sottek"); +MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver"); + + +static struct file_operations rng_chrdev_ops = { + open: rng_dev_open, + release: rng_dev_release, + read: rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + + +/* + * rng_init - initialize RNG module + */ +int __init rng_init (void) +{ + int rc; + struct pci_dev *pdev; + + pdev = pci_find_device (0x8086, 0x2418, NULL); + if (!pdev) + pdev = pci_find_device (0x8086, 0x2428, NULL); + if (!pdev) + pdev = pci_find_device (0x8086, 0x1130, NULL); + if (!pdev) + return -ENODEV; + + DPRINTK ("ENTER\n"); + + rc = rng_init_one(pdev); + if (rc) { + DPRINTK ("EXIT, returning -ENODEV\n"); + return rc; + } + + rc = misc_register (&rng_miscdev); + if (rc) { + if (rng_mem) + iounmap (rng_mem); + DPRINTK ("EXIT, returning %d\n", rc); + return rc; + } + + printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + +#ifdef MODULE + +int init_module (void) { return rng_init (); } + +/* + * rng_init - shutdown RNG module + */ +void cleanup_module (void) +{ + DPRINTK ("ENTER\n"); + + iounmap (rng_mem); + + rng_hwstatus_set (rng_hwstatus() & ~RNG_ENABLED); + + misc_deregister (&rng_miscdev); + + DPRINTK ("EXIT\n"); +} + +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.2.17/drivers/char/isicom.c Fri Apr 21 12:46:03 2000 +++ linux/drivers/char/isicom.c Sat Sep 23 13:34:38 2000 @@ -16,6 +16,31 @@ * * 10/6/99 sameer Merged the ISA and PCI drivers to * a new unified driver. + * + * 3/9/99 sameer Added support for ISI4616 cards. + * + * 16/9/99 sameer We do not force RTS low anymore. + * This is to prevent the firmware + * from getting confused. + * + * 26/10/99 sameer Cosmetic changes:The driver now + * dumps the Port Count information + * along with I/O address and IRQ. + * + * 13/12/99 sameer Fixed the problem with IRQ sharing. + * + * 10/5/00 sameer Fixed isicom_shutdown_board() + * to not lower DTR on all the ports + * when the last port on the card is + * closed. + * + * 10/5/00 sameer Signal mask setup command added + * to isicom_setup_port and + * isicom_shutdown_port. + * + * 24/5/00 sameer The driver is now SMP aware. + * + * * *********************************************************** * * To use this driver you also need the support package. You @@ -51,6 +76,7 @@ #include #include #include +#include #include @@ -67,9 +93,11 @@ 0x2058 }; +#define DEVID_COUNT (sizeof(device_id) / sizeof(device_id[0])) + static int isicom_refcount = 0; static int prev_card = 3; /* start servicing isi_card[0] */ -static struct isi_board * irq_to_board[16] = { NULL, }; +/*static struct isi_board * irq_to_board[16] = { NULL, };*/ static struct tty_driver isicom_normal, isicom_callout; static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, }; static struct termios * isicom_termios[PORT_COUNT] = { NULL, }; @@ -84,6 +112,7 @@ static char re_schedule = 1; #ifdef ISICOM_DEBUG static unsigned long tx_count = 0; +static unsigned long intr_count = 0; #endif static int ISILoad_open(struct inode *inode, struct file *filp); @@ -140,6 +169,70 @@ return 1; } + +extern inline unsigned char valid_irq(int irq) +{ + if ((irq != 2) && + (irq != 3) && + (irq != 4) && + (irq != 5) && + (irq != 7) && + (irq != 10) && + (irq != 11) && + (irq != 12) && + (irq != 15)) + return 0; + else + return 1; +} + +static unsigned short reset_card(int base_addr, unsigned char read_portcount) +{ + unsigned int i; + unsigned short sig, portcount; + + inw(base_addr + 0x8); + + for(i = jiffies+HZ/100; time_before(jiffies, i);); + + outw(0, base_addr + 0x8); /* Reset */ + + for(i = jiffies+HZ; time_before(jiffies, i);); + + sig = (inw(base_addr + 0x4)) & 0xff; + + if ((sig!= 0xa5) && + (sig != 0xbb) && + (sig != 0xcc) && + (sig != 0xdd)) + return 0; + + if (read_portcount) { + + for(i = jiffies+HZ/100; time_before(jiffies, i);); + + portcount = inw(base_addr + 0x2); + if ((portcount != 0) && + (portcount != 4) && + (portcount != 8) && + (portcount != 16)) + return 0; + else + sig |= (portcount << 8); + } + + if (!(inw(base_addr + 0xe) & 0x1)) { +#ifdef ISICOM_DEBUG + printk("\nbase+0xe=0x%x", inw(base_addr + 0xe)); +#endif + printk("\nISILoad:ISA Card reset failure" + "(Possible bad I/O Port Address 0x%x).\n", + base_addr); + return 0; + } + return sig; +} + static int ISILoad_open(struct inode *inode, struct file *filp) { #ifdef ISICOM_DEBUG @@ -152,7 +245,7 @@ static int ISILoad_release(struct inode *inode, struct file *filp) { #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",); + printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n"); #endif MOD_DEC_USE_COUNT; return 0; @@ -161,7 +254,7 @@ static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - unsigned int card, i, j, signature, status, portcount = 0; + unsigned int card, i, signature, status; unsigned short word_count, base; bin_frame frame; /* exec_record exec_rec; */ @@ -182,46 +275,18 @@ if (!capable(CAP_SYS_ADMIN)) return -EPERM; printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base); - - inw(base+0x8); - - for(i=jiffies+HZ/100;time_before(jiffies, i);); - - outw(0,base+0x8); /* Reset */ - - for(j=1;j<=3;j++) { - for(i=jiffies+HZ;time_before(jiffies, i);); - printk("."); - } - signature=(inw(base+0x4)) & 0xff; - if (isi_card[card].isa) { - - if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) { -#ifdef ISICOM_DEBUG - printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); -#endif - printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); - return -EIO; - } - } - else { - portcount = inw(base+0x2); - if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) { -#ifdef ISICOM_DEBUG - printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); -#endif - printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); - return -EIO; - } - } - switch(signature) { + + signature = reset_card(base, + (isi_card[card].isa ? 0 : 1)); + + switch(signature & 0xff) { case 0xa5: case 0xbb: case 0xdd: if (isi_card[card].isa) isi_card[card].port_count = 8; else { - if (portcount == 4) + if ((signature & 0xff00) == 0x0400) isi_card[card].port_count = 4; else isi_card[card].port_count = 8; @@ -229,17 +294,20 @@ isi_card[card].shift_count = 12; break; - case 0xcc: isi_card[card].port_count = 16; + case 0xcc: /* ISI616EM */ + case 0xee: /* ISI4616 */ + isi_card[card].port_count = 16; isi_card[card].shift_count = 11; break; - default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); + default: printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); #ifdef ISICOM_DEBUG - printk("Sig=0x%x\n",signature); + printk("Sig=0x%x\n", signature); #endif return -EIO; } printk("-Done\n"); + signature &= 0xff; return put_user(signature,(unsigned int*)arg); case MIOCTL_LOAD_FIRMWARE: @@ -266,8 +334,14 @@ return -EIO; if ((status=inw(base+0x4))!=0) { - printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n", - card+1, frame.addr, frame.count, status); + printk(KERN_WARNING "ISILoad:" + "Card%d rejected load header:" + "\nAddress:0x%x \nCount:0x%x" + " \nStatus:0x%x \n", + card+1, + frame.addr, + frame.count, + status); return -EIO; } outsw(base, (void *) frame.bin_data, word_count); @@ -280,7 +354,10 @@ return -EIO; if ((status=inw(base+0x4))!=0) { - printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status); + printk(KERN_ERR "ISILoad:Card%d" + " got out of sync.Card Status:0x%x\n", + card+1, + status); return -EIO; } return 0; @@ -346,6 +423,9 @@ outw(0x0, base+0x4); /* for ISI4608 cards */ isi_card[card].status |= FIRMWARE_LOADED; + printk(KERN_INFO "ISICOM: Card%d with %d ports at 0x%x using irq %d.\n", + card+1,isi_card[card].port_count, + isi_card[card].base, isi_card[card].irq); return 0; default: @@ -363,8 +443,10 @@ * ISICOM Driver specific routines ... * */ - -static inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev, +#ifndef ISIOCM_DEBUG +static +#endif +inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev, const char * routine) { #ifdef ISICOM_DEBUG @@ -391,14 +473,15 @@ } /* Transmitter */ - -static void isicom_tx(unsigned long _data) +#ifndef ISICOM_DEBUG +static +#endif +void isicom_tx(unsigned long _data) { short count = (BOARD_COUNT-1), card, base; - short txcount, wait, wrd, residue, word_count, cnt; + short txcount, wrd, residue, word_count, cnt; struct isi_port * port; struct tty_struct * tty; - unsigned long flags; #ifdef ISICOM_DEBUG ++tx_count; @@ -416,54 +499,64 @@ prev_card = card; - count = isi_card[card].port_count; + port = isi_card[card].ports; base = isi_card[card].base; - for (;count > 0;count--, port++) { + for (count = isi_card[card].port_count; count > 0; count--, port++) { + + if (!lock_card_at_interrupt(&isi_card[card])) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_tx:" + "Card(0x%x) found busy.\n", + card); +#endif + continue; + } + /* port not active or tx disabled to force flow control */ - if (!(port->status & ISI_TXOK)) + if (!(port->flags & ASYNC_INITIALIZED) || + !(port->status & ISI_TXOK)) { + unlock_card(&isi_card[card]); continue; + } tty = port->tty; - save_flags(flags); cli(); + txcount = MIN(TX_SIZE, port->xmit_cnt); if ((txcount <= 0) || tty->stopped || tty->hw_stopped) { - restore_flags(flags); - continue; - } - wait = 200; - while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); - if (wait <= 0) { - restore_flags(flags); -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_tx:Card(0x%x) found busy.\n", - card); -#endif + unlock_card(&isi_card[card]); continue; } + if (!(inw(base + 0x02) & (1 << port->channel))) { - restore_flags(flags); + unlock_card(&isi_card[card]); #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_tx: cannot tx to 0x%x:%d.\n", - base, port->channel + 1); + printk(KERN_DEBUG "ISICOM: isicom_tx:" + "Card(0x%x) cannot accept data" + " for channel %d!\n", + base, + port->channel + 1); #endif continue; } #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: txing %d bytes, port%d.\n", - txcount, port->channel+1); + txcount, + port->channel+1); #endif - outw((port->channel << isi_card[card].shift_count) | txcount - , base); + outw((port->channel << isi_card[card].shift_count) | txcount, + base); residue = NO; - wrd = 0; + wrd = 0; while (1) { cnt = MIN(txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); if (residue == YES) { residue = NO; if (cnt > 0) { - wrd |= (port->xmit_buf[port->xmit_tail] << 8); - port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); + wrd |= (port->xmit_buf[port->xmit_tail] + << 8); + port->xmit_tail = (port->xmit_tail + 1) + & (SERIAL_XMIT_SIZE - 1); port->xmit_cnt--; txcount--; cnt--; @@ -477,14 +570,15 @@ if (cnt <= 0) break; word_count = cnt >> 1; outsw(base, port->xmit_buf+port->xmit_tail, word_count); - port->xmit_tail = (port->xmit_tail + (word_count << 1)) & - (SERIAL_XMIT_SIZE - 1); + port->xmit_tail = (port->xmit_tail + (word_count << 1)) + & (SERIAL_XMIT_SIZE - 1); txcount -= (word_count << 1); port->xmit_cnt -= (word_count << 1); if (cnt & 0x0001) { residue = YES; wrd = port->xmit_buf[port->xmit_tail]; - port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); + port->xmit_tail = (port->xmit_tail + 1) & + (SERIAL_XMIT_SIZE - 1); port->xmit_cnt--; txcount--; } @@ -495,7 +589,7 @@ port->status &= ~ISI_TXOK; if (port->xmit_cnt <= WAKEUP_CHARS) schedule_bh(port); - restore_flags(flags); + unlock_card(&isi_card[card]); } /* schedule another tx for hopefully in about 10ms */ @@ -532,11 +626,13 @@ tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); - wake_up_interruptible(&tty->poll_wait); } /* main interrupt handler routine */ -static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs) +#ifndef ISICOM_DEBUG +static +#endif +void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs) { struct isi_board * card; struct isi_port * port; @@ -545,26 +641,34 @@ unsigned char channel; short byte_count; - /* - * find the source of interrupt - */ - - for(count = 0; count < BOARD_COUNT; count++) { - card = &isi_card[count]; - if (card->base != 0) { - if (((card->isa == YES) && (card->irq == irq)) || - ((card->isa == NO) && (card->irq == irq) && (inw(card->base+0x0e) & 0x02))) - break; - } - card = NULL; - } +#ifdef ISICOM_DEBUG + ++intr_count; +#endif + + card = (struct isi_board *) dev_id; if (!card || !(card->status & FIRMWARE_LOADED)) { -/* printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);*/ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: interrupt:" + " not handling irq%d!.\n", + irq); +#endif return; } - + base = card->base; + + /* + * If this is a PCI card, did it really interrupt us ? + */ + if ((card->isa == NO) && (!inw(base+0x0e) & 0x02)) + return; + + spin_lock(&card->card_lock); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_interrupt: acquired card spinlock\n"); + +#endif if (card->isa == NO) { /* * disable any interrupts from the PCI card and lower the @@ -582,12 +686,14 @@ printk(KERN_DEBUG "ISICOM:Intr:(0x%x:%d).\n", base, channel+1); #endif if ((channel+1) > card->port_count) { - printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n", - base, channel+1); + printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x):" + " %d(channel) > port_count.\n", + base, channel+1); if (card->isa) ClearInterrupt(base); else outw(0x0000, base+0x04); /* enable interrupts */ + spin_unlock(&card->card_lock); return; } port = card->ports + channel; @@ -596,6 +702,7 @@ ClearInterrupt(base); else outw(0x0000, base+0x04); /* enable interrupts */ + spin_unlock(&card->card_lock); return; } @@ -606,6 +713,7 @@ switch(header & 0xff) { case 0: /* Change in EIA signals */ + if (port->flags & ASYNC_CHECK_CD) { if (port->status & ISI_DCD) { if (!(header & ISI_DCD)) { @@ -613,7 +721,6 @@ #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n"); #endif - port->status &= ~ISI_DCD; if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && (port->flags & ASYNC_CALLOUT_NOHUP))) queue_task(&port->hangup_tq, @@ -626,42 +733,39 @@ #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: interrupt: DCD->high.\n"); #endif - port->status |= ISI_DCD; wake_up_interruptible(&port->open_wait); } } } - else { - if (header & ISI_DCD) - port->status |= ISI_DCD; - else - port->status &= ~ISI_DCD; - } + if (header & ISI_DCD) + port->status |= ISI_DCD; + else + port->status &= ~ISI_DCD; + if (port->flags & ASYNC_CTS_FLOW) { if (port->tty->hw_stopped) { if (header & ISI_CTS) { port->tty->hw_stopped = 0; - /* start tx ing */ - port->status |= (ISI_TXOK | ISI_CTS); + /* start tx ing + port->status |= (ISI_TXOK | ISI_CTS);*/ schedule_bh(port); } } else { if (!(header & ISI_CTS)) { - port->tty->hw_stopped = 1; - /* stop tx ing */ - port->status &= ~(ISI_TXOK | ISI_CTS); + /* port->tty->hw_stopped = 1;*/ + /* stop tx ing + port->status &= ~(ISI_TXOK | ISI_CTS);*/ } } } - else { - if (header & ISI_CTS) - port->status |= ISI_CTS; - else - port->status &= ~ISI_CTS; - } + if (header & ISI_CTS) + port->status |= ISI_CTS; + else + port->status &= ~ISI_CTS; + if (header & ISI_DSR) port->status |= ISI_DSR; else @@ -687,7 +791,8 @@ break; case 2: /* Statistics */ - printk(KERN_DEBUG "ISICOM: isicom_interrupt: stats!!!.\n"); + printk(KERN_DEBUG "ISICOM: isicom_interrupt:" + " stats!!!.\n"); break; default: @@ -714,8 +819,9 @@ tty->flip.count += count; if (byte_count > 0) { - printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n", - base, channel+1); + printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d):" + " Flip buffer overflow! dropping bytes...\n", + base, channel+1); while(byte_count > 0) { /* drain out unread xtra data */ inw(base); byte_count -= 2; @@ -726,20 +832,25 @@ if (card->isa == YES) ClearInterrupt(base); else - outw(0x0000, base+0x04); /* enable interrupts */ + outw(0x0000, base+0x04); /* enable interrupts */ + spin_unlock(&card->card_lock); return; } - - /* called with interrupts disabled */ -static void isicom_config_port(struct isi_port * port) +#ifndef ISICOM_DEBUG +static +#endif +void isicom_config_port(struct isi_port * port) { struct isi_board * card = port->card; struct tty_struct * tty; unsigned long baud; - unsigned short channel_setup, wait, base = card->base; + unsigned short channel_setup, base = card->base; unsigned short channel = port->channel, shift_count = card->shift_count; unsigned char flow_ctrl; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM:isicom_config_port:start\n"); +#endif if (!(tty = port->tty) || !tty->termios) return; baud = C_BAUD(tty); @@ -776,40 +887,47 @@ else raise_dtr(port); - wait = 100; - while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); - if (!wait) { - printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at channel setup.\n"); - return; - } - outw(0x8000 | (channel << shift_count) |0x03, base); - outw(linuxb_to_isib[baud] << 8 | 0x03, base); - channel_setup = 0; - switch(C_CSIZE(tty)) { - case CS5: - channel_setup |= ISICOM_CS5; - break; - case CS6: - channel_setup |= ISICOM_CS6; - break; - case CS7: - channel_setup |= ISICOM_CS7; - break; - case CS8: - channel_setup |= ISICOM_CS8; - break; - } + if (lock_card(card)) { + outw(0x8000 | (channel << shift_count) |0x03, base); + outw(linuxb_to_isib[baud] << 8 | 0x03, base); + channel_setup = 0; + switch(C_CSIZE(tty)) { + case CS5: + channel_setup |= ISICOM_CS5; + break; + case CS6: + channel_setup |= ISICOM_CS6; + break; + case CS7: + channel_setup |= ISICOM_CS7; + break; + case CS8: + channel_setup |= ISICOM_CS8; + break; + } - if (C_CSTOPB(tty)) - channel_setup |= ISICOM_2SB; - - if (C_PARENB(tty)) - channel_setup |= ISICOM_EVPAR; - if (C_PARODD(tty)) - channel_setup |= ISICOM_ODPAR; - outw(channel_setup, base); - InterruptTheCard(base); + if (C_CSTOPB(tty)) + channel_setup |= ISICOM_2SB; + if (C_PARENB(tty)) { + if (C_PARODD(tty)) + channel_setup |= ISICOM_ODPAR; + else + channel_setup |= ISICOM_EVPAR; + } + outw(channel_setup, base); + InterruptTheCard(base); + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM:isicom_config_port:channel setup\n"); +#endif + unlock_card(card); + } + else + printk(KERN_WARNING "ISICOM:isicom_config_port:" + "Card (0x%x) busy for Channel Setup\n", + card->base); + if (C_CLOCAL(tty)) port->flags &= ~ASYNC_CHECK_CD; else @@ -827,23 +945,33 @@ if (I_IXOFF(tty)) flow_ctrl |= ISICOM_INITIATE_XONXOFF; - wait = 100; - while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); - if (!wait) { - printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at flow setup.\n"); - return; - } - outw(0x8000 | (channel << shift_count) |0x04, base); - outw(flow_ctrl << 8 | 0x05, base); - outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); - InterruptTheCard(base); + if (lock_card(card)) { + outw(0x8000 | (channel << shift_count) |0x04, base); + outw(flow_ctrl << 8 | 0x05, base); + outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); + InterruptTheCard(base); + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM:isicom_config_port:flow setup\n"); +#endif + + unlock_card(card); + } + else + printk(KERN_WARNING "ISICOM:isicom_config_port:" + "Card (0x%x) busy for Flow Ctrl Setup\n", + card->base); + /* rx enabled -> enable port for rx on the card */ if (C_CREAD(tty)) { card->port_status |= (1 << channel); outw(card->port_status, base + 0x02); } +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM:isicom_config_port:stop\n"); +#endif } /* open et all */ @@ -854,74 +982,106 @@ struct isi_port * port; unsigned long flags; - if (bp->status & BOARD_ACTIVE) - return; - port = bp->ports; #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts start, port_count %d...\n", bp->port_count); + printk(KERN_DEBUG "ISICOM: setup_board:start\n"); +#endif + + spin_lock_irqsave(&bp->card_lock, flags); + if (bp->status & BOARD_ACTIVE) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_board:" + " already active\n"); +#endif + spin_unlock_irqrestore(&bp->card_lock, flags); + return; + } + port = bp->ports; + bp->status |= BOARD_ACTIVE; + MOD_INC_USE_COUNT; + spin_unlock_irqrestore(&bp->card_lock, flags); + + for(channel = 0; channel < bp->port_count; channel++, port++) + drop_dtr(port); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_board:stop\n"); #endif - for(channel = 0; channel < bp->port_count; channel++, port++) { - save_flags(flags); cli(); - drop_dtr_rts(port); - restore_flags(flags); - } -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts stop...\n"); -#endif - - bp->status |= BOARD_ACTIVE; - MOD_INC_USE_COUNT; return; } - -static int isicom_setup_port(struct isi_port * port) + +#ifndef ISICOM_DEBUG +static +#endif +int isicom_setup_port(struct isi_port * port) { struct isi_board * card = port->card; unsigned long flags; - if (port->flags & ASYNC_INITIALIZED) - return 0; - if (!port->xmit_buf) { - unsigned long page; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_port:start\n"); +#endif + spin_lock_irqsave(&card->card_lock, flags); + if (port->flags & ASYNC_INITIALIZED) { + spin_unlock_irqrestore(&card->card_lock, flags); + return 0; + } + + if (!port->xmit_buf) { + unsigned long page; - if (!(page = get_free_page(GFP_KERNEL))) - return -ENOMEM; + if (!(page = get_free_page(GFP_KERNEL))) { + spin_unlock_irqrestore(&card->card_lock, flags); + return -ENOMEM; + } - if (port->xmit_buf) { - free_page(page); - return -ERESTARTSYS; + if (port->xmit_buf) { + free_page(page); + spin_unlock_irqrestore(&card->card_lock, flags); + return -ERESTARTSYS; + } + port->xmit_buf = (unsigned char *) page; } - port->xmit_buf = (unsigned char *) page; - } - save_flags(flags); cli(); - if (port->tty) - clear_bit(TTY_IO_ERROR, &port->tty->flags); - if (port->count == 1) - card->count++; + + if (port->tty) + clear_bit(TTY_IO_ERROR, &port->tty->flags); + if (port->count == 1) + card->count++; - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + port->flags |= ASYNC_INITIALIZED; + spin_unlock_irqrestore(&card->card_lock, flags); /* discard any residual data */ kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_port: isicom_config_port...\n"); +#endif isicom_config_port(port); - port->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + set_signal_mask(port, 0xff); /* enable EIA status interrupt reporting */ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_port:stop\n"); +#endif return 0; -} - -static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port) +} +#ifndef ISICOM_DEBUG +static +#endif +int block_til_ready(struct tty_struct * tty, struct file * filp, + struct isi_port * port) { int do_clocal = 0, retval; struct wait_queue wait = { current, NULL }; + struct isi_board *card = port->card; /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: close in progress.\n"); + printk(KERN_DEBUG "ISICOM: block_til_ready:" + " close in progress.\n"); #endif interruptible_sleep_on(&port->close_wait); if (port->flags & ASYNC_HUP_NOTIFY) @@ -948,15 +1108,14 @@ (port->pgrp != current->pgrp)) return -EBUSY; port->flags |= ASYNC_CALLOUT_ACTIVE; - cli(); raise_dtr_rts(port); - sti(); return 0; } /* if non-blocking mode is set ... */ - if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n"); #endif @@ -982,20 +1141,20 @@ callout dev is busy */ retval = 0; add_wait_queue(&port->open_wait, &wait); - cli(); + + spin_lock_irqsave(&card->card_lock, card->flags); if (!tty_hung_up_p(filp)) port->count--; - sti(); + spin_unlock_irqrestore(&card->card_lock, card->flags); + port->blocked_open++; #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: block_til_ready: waiting for DCD...\n"); #endif while (1) { - cli(); if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) raise_dtr_rts(port); - sti(); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) @@ -1003,7 +1162,8 @@ else retval = -ERESTARTSYS; #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: tty_hung_up_p || not init.\n"); + printk(KERN_DEBUG "ISICOM: block_til_ready:" + " tty_hung_up_p || not init.\n"); #endif break; } @@ -1011,13 +1171,15 @@ !(port->flags & ASYNC_CLOSING) && (do_clocal || (port->status & ISI_DCD))) { #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n"); + printk(KERN_DEBUG "ISICOM: block_til_ready:" + " do_clocal || DCD.\n"); #endif break; } if (signal_pending(current)) { #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: block_til_ready: sig blocked.\n"); + printk(KERN_DEBUG "ISICOM: block_til_ready:" + " sig blocked.\n"); #endif retval = -ERESTARTSYS; break; @@ -1034,13 +1196,15 @@ port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - -static int isicom_open(struct tty_struct * tty, struct file * filp) + +#ifndef ISICOM_DEBUG +static +#endif +int isicom_open(struct tty_struct * tty, struct file * filp) { struct isi_port * port; struct isi_board * card; unsigned int line, board; - unsigned long flags; int error; #ifdef ISICOM_DEBUG @@ -1063,14 +1227,16 @@ card = &isi_card[board]; if (!(card->status & FIRMWARE_LOADED)) { #ifdef ISICOM_DEBUG - printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board); + printk(KERN_DEBUG"ISICOM: Firmware not loaded" + " to card%d.\n", board); #endif return -ENODEV; } /* open on a port greater than the port count for the card !!! */ if (line > ((board * 16) + card->port_count - 1)) { - printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n"); + printk(KERN_ERR "ISICOM: Open on a port which exceeds" + " the port_count of the card!\n"); return -ENODEV; } port = &isi_ports[line]; @@ -1080,16 +1246,18 @@ #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n"); #endif - isicom_setup_board(card); + isicom_setup_board(card); port->count++; tty->driver_data = port; port->tty = tty; + #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n"); #endif if ((error = isicom_setup_port(port))!=0) return error; + #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: block_til_ready ...\n"); #endif @@ -1101,9 +1269,7 @@ *tty->termios = port->normal_termios; else *tty->termios = port->callout_termios; - save_flags(flags); cli(); isicom_config_port(port); - restore_flags(flags); } port->session = current->session; @@ -1118,30 +1284,40 @@ extern inline void isicom_shutdown_board(struct isi_board * bp) { - int channel; - struct isi_port * port; - - if (!(bp->status & BOARD_ACTIVE)) - return; - bp->status &= ~BOARD_ACTIVE; - port = bp->ports; - for(channel = 0; channel < bp->port_count; channel++, port++) { - drop_dtr_rts(port); - } - MOD_DEC_USE_COUNT; + unsigned long flags; + + spin_lock_irqsave(&bp->card_lock, flags); + if (!(bp->status & BOARD_ACTIVE)) { + spin_unlock_irqrestore(&bp->card_lock, flags); + return; + } + bp->status &= ~BOARD_ACTIVE; + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore(&bp->card_lock, flags); } -static void isicom_shutdown_port(struct isi_port * port) +#ifndef ISICOM_DEBUG +static +#endif +void isicom_shutdown_port(struct isi_port * port) { struct isi_board * card = port->card; - struct tty_struct * tty; - - if (!(port->flags & ASYNC_INITIALIZED)) - return; - if (port->xmit_buf) { - free_page((unsigned long) port->xmit_buf); - port->xmit_buf = NULL; - } + struct tty_struct * tty; + unsigned long flags; + + spin_lock_irqsave(&card->card_lock, flags); + if (!(port->flags & ASYNC_INITIALIZED)){ + spin_unlock_irqrestore(&card->card_lock, flags); + return; + } + if (port->xmit_buf) { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = NULL; + } + port->flags &= ~ASYNC_INITIALIZED; + spin_unlock_irqrestore(&card->card_lock, flags); + + tty = port->tty; if (!(tty = port->tty) || C_HUPCL(tty)) /* drop dtr on this port */ drop_dtr(port); @@ -1150,37 +1326,44 @@ if (tty) set_bit(TTY_IO_ERROR, &tty->flags); - port->flags &= ~ASYNC_INITIALIZED; if (--card->count < 0) { - printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n", - card->base, card->count); + printk(KERN_DEBUG "ISICOM: isicom_shutdown_port:" + " bad board(0x%x) count %d.\n", + card->base, card->count); card->count = 0; } + set_signal_mask(port, 0x00); /*disable EIA status interrupt reporting */ + /* last port was closed , shutdown that boad too */ if (!card->count) isicom_shutdown_board(card); } -static void isicom_close(struct tty_struct * tty, struct file * filp) +#ifndef ISICOM_DEBUG +static +#endif +void isicom_close(struct tty_struct * tty, struct file * filp) { struct isi_port * port = (struct isi_port *) tty->driver_data; - struct isi_board * card = port->card; + struct isi_board * card; unsigned long flags; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Close start!!!.\n"); +#endif if (!port) return; + + card = port->card; + if (isicom_paranoia_check(port, tty->device, "isicom_close")) return; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: Close start!!!.\n"); -#endif - - save_flags(flags); cli(); + spin_lock_irqsave(&card->card_lock, flags); if (tty_hung_up_p(filp)) { - restore_flags(flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } @@ -1191,14 +1374,16 @@ port->count = 1; } if (--port->count < 0) { - printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for" - "channel%d = %d", card->base, port->channel, + printk(KERN_WARNING "ISICOM:(0x%x) isicom_close:" + " bad port count for channel%d = %d", + card->base, + port->channel, port->count); port->count = 0; } if (port->count) { - restore_flags(flags); + spin_unlock_irqrestore(&card->card_lock, flags); return; } port->flags |= ASYNC_CLOSING; @@ -1212,22 +1397,35 @@ port->callout_termios = *tty->termios; tty->closing = 1; + + spin_unlock_irqrestore(&card->card_lock, flags); if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, port->closing_wait); - /* indicate to the card that no more data can be received - on this port */ + spin_lock_irqsave(&card->card_lock, flags); + + /* + * indicate to the card that no more data can be received + * on this port + */ if (port->flags & ASYNC_INITIALIZED) { card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); - } + } + + spin_unlock_irqrestore(&card->card_lock, flags); + isicom_shutdown_port(port); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); + + spin_lock_irqsave(&card->card_lock, flags); + tty->closing = 0; port->tty = 0; if (port->blocked_open) { + spin_unlock_irqrestore(&card->card_lock, flags); if (port->close_delay) { current->state = TASK_INTERRUPTIBLE; #ifdef ISICOM_DEBUG @@ -1236,101 +1434,130 @@ schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); + spin_lock_irqsave(&card->card_lock, flags); } port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); + port->status &= ~ISI_TXOK; wake_up_interruptible(&port->close_wait); - restore_flags(flags); + + spin_unlock_irqrestore(&card->card_lock, flags); + #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Close end!!!.\n"); #endif } /* write et all */ -static int isicom_write(struct tty_struct * tty, int from_user, +#ifndef ISICOM_DEBUG +static +#endif +int isicom_write(struct tty_struct * tty, int from_user, const unsigned char * buf, int count) { struct isi_port * port = (struct isi_port *) tty->driver_data; - unsigned long flags; + struct isi_board * card = port->card; int cnt, total = 0; #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n", - port->channel+1, count); +/* printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n", + port->channel+1, count);*/ #endif if (isicom_paranoia_check(port, tty->device, "isicom_write")) return 0; + spin_lock_irqsave(&card->card_lock, card->flags); + if (!tty || !port->xmit_buf || !tmp_buf) return 0; if (from_user) down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */ - save_flags(flags); + while(1) { - cli(); + +/* spin_lock_irqsave(&card->card_lock, card->flags);*/ cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); - if (cnt <= 0) + if (cnt <= 0) { +/* spin_unlock_irqrestore(&card->card_lock, card->flags);*/ break; + } if (from_user) { - /* the following may block for paging... hence - enabling interrupts but tx routine may have - created more space in xmit_buf when the ctrl - gets back here */ - sti(); + /* + * the following may block for paging... hence + * enabling interrupts but tx routine may have + * created more space in xmit_buf when the ctrl + * gets back here + */ + + spin_unlock_irqrestore(&card->card_lock, card->flags); + copy_from_user(tmp_buf, buf, cnt); - cli(); - cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); + + spin_lock_irqsave(&card->card_lock, card->flags); + + cnt = MIN(cnt, + MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt); } else memcpy(port->xmit_buf + port->xmit_head, buf, cnt); - port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1); + port->xmit_head = (port->xmit_head + cnt) & + (SERIAL_XMIT_SIZE - 1); port->xmit_cnt += cnt; - restore_flags(flags); + +/* spin_unlock_irqrestore(&card->card_lock, card->flags);*/ + buf += cnt; count -= cnt; total += cnt; - } + } if (from_user) up(&tmp_buf_sem); + if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) port->status |= ISI_TXOK; - restore_flags(flags); + + spin_unlock_irqrestore(&card->card_lock, card->flags); + #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total); +/* printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total);*/ #endif - return total; + return total; } /* put_char et all */ -static void isicom_put_char(struct tty_struct * tty, unsigned char ch) +#ifndef ISICOM_DEBUG +static +#endif +void isicom_put_char(struct tty_struct * tty, unsigned char ch) { struct isi_port * port = (struct isi_port *) tty->driver_data; - unsigned long flags; + struct isi_board * card = port->card; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch); +#endif if (isicom_paranoia_check(port, tty->device, "isicom_put_char")) return; if (!tty || !port->xmit_buf) return; -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch); -#endif - - save_flags(flags); cli(); + + spin_lock_irqsave(&card->card_lock, card->flags); - if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) { - restore_flags(flags); - return; - } + if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) { + spin_unlock_irqrestore(&card->card_lock, card->flags); + return; + } - port->xmit_buf[port->xmit_head++] = ch; - port->xmit_head &= (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt++; - restore_flags(flags); + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt++; + + spin_unlock_irqrestore(&card->card_lock, card->flags); } /* flush_chars et all */ @@ -1377,21 +1604,20 @@ extern inline void isicom_send_break(struct isi_port * port, unsigned long length) { struct isi_board * card = port->card; - short wait = 10; unsigned short base = card->base; - unsigned long flags; - save_flags(flags); cli(); - while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); - if (!wait) { - printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n"); + if (!lock_card(card)) { + printk(KERN_DEBUG "ISICOM: Card found busy in" + " isicom_send_break.\n"); return; - } + } + outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); outw((length & 0xff) << 8 | 0x00, base); outw((length & 0xff00), base); InterruptTheCard(base); - restore_flags(flags); + + unlock_card(card); } static int isicom_get_modem_info(struct isi_port * port, unsigned int * value) @@ -1414,12 +1640,10 @@ unsigned int * value) { unsigned int arg; - unsigned long flags; if(get_user(arg, value)) return -EFAULT; - save_flags(flags); cli(); switch(cmd) { case TIOCMBIS: @@ -1449,10 +1673,8 @@ break; default: - restore_flags(flags); return -EINVAL; } - restore_flags(flags); return 0; } @@ -1460,7 +1682,6 @@ struct serial_struct * info) { struct serial_struct newinfo; - unsigned long flags; int reconfig_port; if(copy_from_user(&newinfo, info, sizeof(newinfo))) @@ -1485,9 +1706,7 @@ (newinfo.flags & ASYNC_FLAGS)); } if (reconfig_port) { - save_flags(flags); cli(); isicom_config_port(port); - restore_flags(flags); } return 0; } @@ -1576,7 +1795,6 @@ static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios) { struct isi_port * port = (struct isi_port *) tty->driver_data; - unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_set_termios")) return; @@ -1585,9 +1803,7 @@ tty->termios->c_iflag == old_termios->c_iflag) return; - save_flags(flags); cli(); isicom_config_port(port); - restore_flags(flags); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1601,16 +1817,13 @@ { struct isi_port * port = (struct isi_port *) tty->driver_data; struct isi_board * card = port->card; - unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_throttle")) return; /* tell the card that this port cannot handle any more data for now */ - save_flags(flags); cli(); card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); - restore_flags(flags); } /* unthrottle et all */ @@ -1618,16 +1831,13 @@ { struct isi_port * port = (struct isi_port *) tty->driver_data; struct isi_board * card = port->card; - unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_unthrottle")) return; /* tell the card that this port is ready to accept more data */ - save_flags(flags); cli(); card->port_status |= (1 << port->channel); outw(card->port_status, card->base + 0x02); - restore_flags(flags); } /* stop et all */ @@ -1688,16 +1898,20 @@ { struct isi_port * port = (struct isi_port *) tty->driver_data; unsigned long flags; +#ifdef __SMP__ + struct isi_board *card = port->card; +#endif if (isicom_paranoia_check(port, tty->device, "isicom_flush_buffer")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&card->card_lock, flags); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - restore_flags(flags); + + spin_unlock_irqrestore(&card->card_lock, flags); wake_up_interruptible(&tty->write_wait); - wake_up_interruptible(&tty->poll_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -1710,14 +1924,23 @@ for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { if (check_region(isi_card[count].base,16)) { - printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n", - isi_card[count].base,isi_card[count].base+15,count+1); + printk(KERN_DEBUG "ISICOM: I/O Region" + " 0x%x-0x%x is busy." + " Card%d will be disabled.\n", + isi_card[count].base, + isi_card[count].base+15, + count+1); isi_card[count].base=0; } else { - request_region(isi_card[count].base,16,ISICOM_NAME); + request_region(isi_card[count].base,16, + ISICOM_NAME); #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1); + printk(KERN_DEBUG "ISICOM: I/O Region" + " 0x%x-0x%x requested for Card%d.\n", + isi_card[count].base, + isi_card[count].base+15, + count+1); #endif done++; } @@ -1733,7 +1956,11 @@ if (isi_card[count].base) { release_region(isi_card[count].base,16); #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1); + printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x" + " released for Card%d.\n", + isi_card[count].base, + isi_card[count].base+15, + count+1); #endif } } @@ -1744,55 +1971,57 @@ /* tty driver structure initialization */ memset(&isicom_normal, 0, sizeof(struct tty_driver)); - isicom_normal.magic = TTY_DRIVER_MAGIC; - isicom_normal.name = "ttyM"; - isicom_normal.major = ISICOM_NMAJOR; + isicom_normal.magic = TTY_DRIVER_MAGIC; + isicom_normal.name = "ttyM"; + isicom_normal.major = ISICOM_NMAJOR; isicom_normal.minor_start = 0; - isicom_normal.num = PORT_COUNT; - isicom_normal.type = TTY_DRIVER_TYPE_SERIAL; - isicom_normal.subtype = SERIAL_TYPE_NORMAL; + isicom_normal.num = PORT_COUNT; + isicom_normal.type = TTY_DRIVER_TYPE_SERIAL; + isicom_normal.subtype = SERIAL_TYPE_NORMAL; isicom_normal.init_termios = tty_std_termios; isicom_normal.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |CLOCAL; - isicom_normal.flags = TTY_DRIVER_REAL_RAW; - isicom_normal.refcount = &isicom_refcount; + isicom_normal.flags = TTY_DRIVER_REAL_RAW; + isicom_normal.refcount = &isicom_refcount; - isicom_normal.table = isicom_table; - isicom_normal.termios = isicom_termios; + isicom_normal.table = isicom_table; + isicom_normal.termios = isicom_termios; isicom_normal.termios_locked = isicom_termios_locked; - isicom_normal.open = isicom_open; - isicom_normal.close = isicom_close; - isicom_normal.write = isicom_write; - isicom_normal.put_char = isicom_put_char; + isicom_normal.open = isicom_open; + isicom_normal.close = isicom_close; + isicom_normal.write = isicom_write; + isicom_normal.put_char = isicom_put_char; isicom_normal.flush_chars = isicom_flush_chars; isicom_normal.write_room = isicom_write_room; isicom_normal.chars_in_buffer = isicom_chars_in_buffer; - isicom_normal.ioctl = isicom_ioctl; + isicom_normal.ioctl = isicom_ioctl; isicom_normal.set_termios = isicom_set_termios; - isicom_normal.throttle = isicom_throttle; + isicom_normal.throttle = isicom_throttle; isicom_normal.unthrottle = isicom_unthrottle; - isicom_normal.stop = isicom_stop; - isicom_normal.start = isicom_start; - isicom_normal.hangup = isicom_hangup; + isicom_normal.stop = isicom_stop; + isicom_normal.start = isicom_start; + isicom_normal.hangup = isicom_hangup; isicom_normal.flush_buffer = isicom_flush_buffer; /* callout device */ - isicom_callout = isicom_normal; - isicom_callout.name = "cum"; - isicom_callout.major = ISICOM_CMAJOR; - isicom_callout.subtype = SERIAL_TYPE_CALLOUT; + isicom_callout = isicom_normal; + isicom_callout.name = "cum"; + isicom_callout.major = ISICOM_CMAJOR; + isicom_callout.subtype = SERIAL_TYPE_CALLOUT; if ((error=tty_register_driver(&isicom_normal))!=0) { - printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n", - error); + printk(KERN_DEBUG "ISICOM: Couldn't register the" + " dialin driver, error=%d\n", + error); return error; } if ((error=tty_register_driver(&isicom_callout))!=0) { tty_unregister_driver(&isicom_normal); - printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n", - error); + printk(KERN_DEBUG "ISICOM: Couldn't register the" + " callout driver, error=%d\n", + error); return error; } return 0; @@ -1802,15 +2031,17 @@ { int error; if ((error=tty_unregister_driver(&isicom_callout))!=0) - printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error); + printk(KERN_DEBUG "ISICOM: couldn't unregister" + " callout driver error=%d.\n",error); if (tty_unregister_driver(&isicom_normal)) - printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error); + printk(KERN_DEBUG "ISICOM: couldn't unregister" + " normal driver error=%d.\n",error); } +#if 0 static int register_isr(void) { int count, done=0, card; - int flag; unsigned char request; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { @@ -1820,9 +2051,11 @@ */ request = YES; for(card = 0; card < count; card++) - if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { + if ((isi_card[card].base) && + (isi_card[card].irq == isi_card[count].irq)) { request = NO; - if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO)) + if ((isi_card[count].isa == NO) + && (isi_card[card].isa == NO)) break; /* * ISA cards cannot share interrupts with other @@ -1832,22 +2065,24 @@ isi_card[count].base = 0; break; } - flag=0; - if(isi_card[count].isa == NO) - flag |= SA_SHIRQ; - if (request == YES) { - if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT|flag, ISICOM_NAME, NULL)) { - printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", + if (request_irq(isi_card[count].irq, + isicom_interrupt, + SA_INTERRUPT | SA_SHIRQ, + ISICOM_NAME, NULL)) { + + printk(KERN_WARNING "ISICOM: Could not" + " install handler at Irq %d." + " Card%d will be disabled.\n", isi_card[count].irq, count+1); + release_region(isi_card[count].base,16); isi_card[count].base=0; } else { - printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", - count+1, isi_card[count].base, isi_card[count].irq); - irq_to_board[isi_card[count].irq]=&isi_card[count]; +/* irq_to_board[isi_card[count].irq]= + &isi_card[count];*/ done++; } } @@ -1855,7 +2090,41 @@ } return done; } +#endif + +static int register_isr(void) +{ + int count, done = 0; + unsigned long irqflags; + + for (count=0; count < BOARD_COUNT; count++ ) { + if (isi_card[count].base) { + + irqflags = (isi_card[count].isa == YES) ? + SA_INTERRUPT : + (SA_INTERRUPT | SA_SHIRQ); + + if (request_irq(isi_card[count].irq, + isicom_interrupt, + irqflags, + ISICOM_NAME, &isi_card[count])) { + + printk(KERN_WARNING "ISICOM: Could not" + " install handler at Irq %d." + " Card%d will be disabled.\n", + isi_card[count].irq, count+1); + release_region(isi_card[count].base,16); + isi_card[count].base=0; + } + else + done++; + } + } + return done; +} + +#if 0 static void unregister_isr(void) { int count, card; @@ -1864,19 +2133,42 @@ if (isi_card[count].base) { freeirq = YES; for(card = 0; card < count; card++) - if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { + if ((isi_card[card].base) && + (isi_card[card].irq == + isi_card[count].irq)) { freeirq = NO; break; } if (freeirq == YES) { free_irq(isi_card[count].irq, NULL); #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); + printk(KERN_DEBUG "ISICOM: Irq %d released" + " for Card%d.\n", + isi_card[count].irq, + count+1); #endif } } } } +#endif + +static void unregister_isr(void) +{ + int count; + + for (count=0; count < BOARD_COUNT; count++ ) { + if (isi_card[count].base) { + free_irq(isi_card[count].irq, &isi_card[count]); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Irq %d released" + " for Card%d.\n", + isi_card[count].irq, + count+1); +#endif + } + } +} static int isicom_init(void) { @@ -1888,7 +2180,8 @@ page = get_free_page(GFP_KERNEL); if (!page) { #ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n"); + printk(KERN_DEBUG "ISICOM: Couldn't allocate page" + " for tmp_buf.\n"); #else printk(KERN_ERR "ISICOM: Not enough memory...\n"); #endif @@ -1909,6 +2202,7 @@ free_page((unsigned long)tmp_buf); return 0; } + if (!register_isr()) { unregister_drivers(); @@ -1916,7 +2210,7 @@ free_page((unsigned long)tmp_buf); return 0; } - + /* initialize bottom half */ init_bh(ISICOM_BH, do_isicom_bh); @@ -1925,6 +2219,9 @@ for (card = 0; card < BOARD_COUNT; card++) { port = &isi_ports[card * 16]; isi_card[card].ports = port; + /* 11/5/00 -sameer SMPCHG*/ + isi_card[card].card_lock = SPIN_LOCK_UNLOCKED; + base = isi_card[card].base; for (channel = 0; channel < 16; channel++, port++) { port->magic = ISICOM_MAGIC; @@ -1967,54 +2264,45 @@ int retval, card, idx, count; unsigned char pciirq; unsigned int ioaddr; - + + for (idx = 0; idx < BOARD_COUNT; idx++) { + isi_card[idx].base = 0; + isi_card[idx].irq = 0; + } + card = 0; for(idx=0; idx < BOARD_COUNT; idx++) { - if (io[idx]) { - isi_card[idx].base=io[idx]; - isi_card[idx].irq=irq[idx]; - isi_card[idx].isa=YES; + if (io[idx] && reset_card(io[idx], 0) && valid_irq(irq[idx])) { + isi_card[card].base=io[idx]; + isi_card[card].irq=irq[idx]; + isi_card[card].isa=YES; card++; } - else { - isi_card[idx].base = 0; - isi_card[idx].irq = 0; - } } - for (idx=0 ;idx < card; idx++) { - if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)|| - (isi_card[idx].irq==4)||(isi_card[idx].irq==5)|| - (isi_card[idx].irq==7)||(isi_card[idx].irq==10)|| - (isi_card[idx].irq==11)||(isi_card[idx].irq==12)|| - (isi_card[idx].irq==15))) { - - if (isi_card[idx].base) { - printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n", - isi_card[idx].irq, idx+1); - isi_card[idx].base=0; - card--; - } - } - } - if (pci_present() && (card < BOARD_COUNT)) { for (idx=0; idx < DEVID_COUNT; idx++) { dev = NULL; for (;;){ - if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev))) + if (!(dev = pci_find_device(VENDOR_ID, + device_id[idx], dev))) break; if (card >= BOARD_COUNT) break; /* found a PCI ISI card! */ - ioaddr = dev->base_address[3]; /* i.e at offset 0x1c in the - * PCI configuration register - * space. - */ + + /* + * 16 bytes address space base at + * offset 0x1c in the PCI configuration + * register space + */ + ioaddr = dev->base_address[3]; ioaddr &= PCI_BASE_ADDRESS_IO_MASK; pciirq = dev->irq; - printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]); + printk(KERN_INFO "ISI PCI " + "Card(Device ID 0x%x)\n", + device_id[idx]); /* * allot the first empty slot in the array */ @@ -2032,29 +2320,34 @@ } } - if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) { - printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); + if (!(isi_card[0].base || isi_card[1].base || + isi_card[2].base || isi_card[3].base)) { + + printk(KERN_ERR "ISICOM: No valid card configuration." + " Driver cannot be initialized...\n"); return -EIO; } retval=misc_register(&isiloader_device); if (retval<0) { - printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n"); + printk(KERN_ERR "ISICOM: Unable to register" + " firmware loader driver.\n"); return -EIO; } if (!isicom_init()) { if (misc_deregister(&isiloader_device)) - printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); + printk(KERN_ERR "ISICOM: Unable to unregister" + " Firmware Loader driver\n"); return -EIO; } - + init_timer(&tx); tx.expires = jiffies + 1; tx.data = 0; tx.function = isicom_tx; re_schedule = 1; add_timer(&tx); - + return 0; } @@ -2067,10 +2360,11 @@ #ifdef ISICOM_DEBUG printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count); + printk("ISICOM: isicom_interrupt intr_count = %ld.\n", intr_count); #endif #ifdef ISICOM_DEBUG - printk("ISICOM: uregistering isr ...\n"); + printk("ISICOM: unregistering isr ...\n"); #endif unregister_isr(); @@ -2093,5 +2387,6 @@ printk("ISICOM: unregistering firmware loader ...\n"); #endif if (misc_deregister(&isiloader_device)) - printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); + printk(KERN_ERR "ISICOM: Unable to unregister" + " Firmware Loader driver\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.2.17/drivers/char/keyboard.c Fri Apr 21 12:46:04 2000 +++ linux/drivers/char/keyboard.c Wed Nov 8 23:03:17 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); @@ -313,7 +315,7 @@ #if 1 /* how? two almost equivalent choices follow */ compute_shiftstate(); #else - keysym = U(plain_map[keycode]); + keysym = U(key_maps[0][keycode]); type = KTYP(keysym); if (type == KT_SHIFT) (*key_handler[type])(keysym & 0xff, up_flag); @@ -757,7 +759,7 @@ k = i*BITS_PER_LONG; for(j=0; j +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "multiface.h" + +static void lp_mfc_out(int,int); +static int lp_mfc_busy(int); +static int lp_mfc_pout(int); +static int lp_mfc_online(int); +static void lp_mfc_interrupt(int, void *, struct pt_regs *); + +static inline struct pia *pia(int); + +static volatile int dummy; /* for trigger reads */ +static int minor[MAX_LP] = { -1, -1, -1, -1, -1 }; +MODULE_PARM(minor,"1-" __MODULE_STRING(MAX_LP) "i"); +#ifdef MODULE +static unsigned int board_key[MAX_LP]; +#endif + +static void lp_mfc_out(int c, int dev) +{ +int wait = 0; + +while (wait != lp_table[dev]->wait) wait++; +dummy = pia(dev)->pprb; /* trigger read clears irq bit*/ +pia(dev)->pprb = c; /* strobe goes down by hardware */ +} + +static int lp_mfc_busy(int dev) +{ +return pia(dev)->ppra&1; +} + +static int lp_mfc_pout(int dev) +{ +return pia(dev)->ppra&2; +} + +static int lp_mfc_online(int dev) +{ +return pia(dev)->ppra&4; +} + +static void lp_mfc_interrupt(int irq,void *data,struct pt_regs *fp) +{ +int i; + +for( i=0; icrb&128) { /* has an irq? */ + dummy = pia(minor[i])->pprb; /* clear bit */ + lp_interrupt(minor[i]); + } +} + +static inline struct pia *pia(int dev) +{ +return lp_table[dev]->base; +} + +static int lp_mfc_open(int dev) +{ +MOD_INC_USE_COUNT; +return 0; +} + +static void lp_mfc_release(int dev) +{ +MOD_DEC_USE_COUNT; +} + +static struct lp_struct tab[MAX_LP] = {{0,},}; + +__initfunc(int lp_mfc_init(void)) +{ +int pias; +struct pia *pp; +unsigned int key = 0; +const struct ConfigDev *cd; + +if (!MACH_IS_AMIGA) + return -ENODEV; + +pias = 0; +while((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0 , key))) { + cd = zorro_get_board( key ); + pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE)); + if (pias < MAX_LP) { + pp->crb = 0; + pp->pddrb = 255; /* all pins output */ + pp->crb = PIA_DDR|32|8; + dummy = pp->pprb; + pp->crb |=(lp_irq!=0)?PIA_C1_ENABLE_IRQ:0; + pp->cra = 0; + pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */ + pp->cra = PIA_DDR; + pp->ppra = 0; /* reset printer */ + udelay(5); + pp->ppra |= 128; + tab[pias].name="Multiface III LP"; + tab[pias].lp_out=lp_mfc_out; + tab[pias].lp_is_busy=lp_mfc_busy; + tab[pias].lp_has_pout=lp_mfc_pout; + tab[pias].lp_is_online=lp_mfc_online; + tab[pias].lp_ioctl=NULL; + tab[pias].lp_open=lp_mfc_open; + tab[pias].lp_release=lp_mfc_release; + tab[pias].flags=LP_EXIST; + tab[pias].chars=LP_INIT_CHAR; + tab[pias].time=LP_INIT_TIME; + tab[pias].wait=LP_INIT_WAIT; + tab[pias].lp_wait_q=NULL; + tab[pias].base=pp; + tab[pias].type=LP_MFC; + if ((minor[pias] = register_parallel(tab + pias, minor[pias] )) >= 0) { + zorro_config_board( key, 0 ); +#ifdef MODULE + board_key[minor[pias]] = key; +#endif + pias++; + } + else + printk("mfc_init: cant get a minor for pia at 0x%08lx\n",(long)pp); + } +} +if ((pias != 0) && (lp_irq != 0)) + request_irq(IRQ_AMIGA_PORTS, lp_mfc_interrupt, 0, + "Multiface III printer", lp_mfc_interrupt); + +return (pias==0)?-ENODEV:0; +} + +#ifdef MODULE +int init_module(void) +{ +return lp_mfc_init(); +} + +void cleanup_module(void) +{ +int i; + +if (lp_irq) + free_irq(IRQ_AMIGA_PORTS, lp_mfc_interrupt); +for(i = 0; i < MAX_LP; i++) + if ((lp_table[i] != NULL) && (lp_table[i]->type == LP_MFC)) { + unregister_parallel(i); + zorro_unconfig_board(board_key[i], 0); + } +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/m68kserial.c linux/drivers/char/m68kserial.c --- v2.2.17/drivers/char/m68kserial.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/m68kserial.c Sat Oct 14 00:05:37 2000 @@ -0,0 +1,1861 @@ +/* + * linux/drivers/char/m68kserial.c + * + * + * Copyright 1994 Roman Hodek + * + * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now + * much more extensible to support other serial cards based on the + * 16450/16550A UART's. Added support for the AST FourPort and the + * Accent Async board. + * + * set_serial_info fixed to set the flags, custom divisor, and uart + * type fields. Fix suggested by Michael K. Johnson 12/12/92. + * + * This module exports the following rs232 io functions: + * + * long m68k_rs_init(void); + */ + +/* + * Notes and Design Goals: + * ----------------------- + * The PC serial drivers can rely on the fact that all the serial + * hardware is very similar to program for all ports. Unfortunately, + * this is not true for m68k machines, especially the Atari. Here it is + * nearly the other way 'round: All ports need different treatment for + * the low-level stuff. + * + * For this reason, I've split the serial driver code into a + * port-independent part (serial.c) and port-specific parts (atari_*.c, + * ...). The first manages all what can be done without accessing the + * hardware directly, i.e. interfacing with the high-level tty drivers, + * wait queues, managing existing ports and the like. The latter do the + * actual hardware programming and are accessed by the hardware + * independent part by a "switch" structure, that contains pointers to + * functions for specific tasks. See the comment before the definition + * of the SERIALSWITCH structure in for more details. + * + * The port-independent code should be usable by other machines than + * m68k ones, too, if there are similar circumstances with different + * serial port hardware. Feel free to use it, but please inform me if + * you have to do changes to it. I'll try to keep it really + * device-independent. + * + * Roman + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PROC_FS +#include +#endif +#ifdef CONFIG_SERIAL_CONSOLE +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATARI +#include "atari_SCC.h" +#include "atari_MFPser.h" +#include "atari_MIDI.h" +#endif + +#ifdef CONFIG_KMOD +#include +#endif + +#ifdef CONFIG_MAC_SCC +int mac_SCC_init(void); +#endif + +#ifdef CONFIG_AMIGA_BUILTIN_SERIAL +int amiga_serinit (void); +#endif + +#ifdef CONFIG_GVPIOEXT +int ioext_init (void); +#endif + +#ifdef CONFIG_MULTIFACE_III_TTY +int multiface_init(void); +#endif + +#ifdef CONFIG_MVME147_SCC +int m147_SCC_init(void); +#endif + +#ifdef CONFIG_MVME162_SCC +int mvme_SCC_init(void); +#endif + +#ifdef CONFIG_BVME6000_SCC +int bvme_SCC_init(void); +#endif + +#ifdef CONFIG_WHIPPET +int whippet_init (void); +#endif + +#ifdef CONFIG_HYPERCOM1 +int hypercom1_init(void); +#endif + +#ifdef CONFIG_HPDCA +int hpdca_init(void); +#endif + +DECLARE_TASK_QUEUE(tq_serial); + +struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +#define SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW + +#define _INLINE_ inline + +#define NR_PORTS 6 + +struct m68k_async_struct rs_table[NR_PORTS]; +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static char *serialtypes[] = { + "unknown", "8250", "16450", "16550", "16550A" +}; +#define PORT_MAX (sizeof(serialtypes)/sizeof(*serialtypes)) +#if defined(__mc68000__) || defined(CONFIG_APUS) +static char *serialtypes68k[] = { + "SCC w/o DMA", "SCC w/ DMA", + "MFP", "MFP w/o ctrl lines", + "MIDI", + "Amiga builtin", "GVP IO-Extender (16c552)", "BSC MultiFaceCard III", + "Hisoft Whippet", + "SCC on MVME", + "8350 ESCC w/o DMA", + "HP DCA", + "SCC on BVME", "A1200 HyperCOM1" +}; +#define M68K_PORT_MAX (sizeof(serialtypes68k)/sizeof(*serialtypes68k)) +#endif + +#ifdef CONFIG_PROC_FS +static int rs_read_proc (char *buffer, char **start, off_t offset, int size, + int *eof, void *data) +{ + int len, i; + off_t begin = 0; + char *name; + + len = sprintf (buffer, "Serial ports:\n"); + for (i = 0; i < NR_PORTS; ++i) { + struct m68k_async_struct *info = &rs_table[i]; + + if (!info->port) continue; + if (info->type >= 0 && info->type < PORT_MAX) + name = serialtypes[info->type]; +#if defined(__mc68000__) || defined(CONFIG_APUS) + else if (info->type >= 100 && info->type < 100 + M68K_PORT_MAX) + name = serialtypes68k[info->type - 100]; +#endif + else + name = "unknown"; + len += sprintf (buffer + len, "%d: name:%s port:0x%08x tx:%d rx:%d", + i, name, info->port, info->icount.tx, info->icount.rx); + + if (info->icount.frame) + len += sprintf(buffer + len, " fe:%d", info->icount.frame); + if (info->icount.parity) + len += sprintf(buffer + len, " pe:%d", info->icount.parity); + if (info->icount.brk) + len += sprintf(buffer + len, " brk:%d", info->icount.brk); + if (info->icount.overrun) + len += sprintf(buffer + len, " oe:%d", info->icount.overrun); + len += sprintf(buffer + len, "\n"); + + if (len + begin > offset + size) + goto done; + if (len + begin < offset) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (offset >= len + begin) + return 0; + *start = buffer + (begin - offset); + return (size < begin + len - offset ? size : begin + len - offset); +} +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf = 0; +static struct semaphore tmp_buf_sem = MUTEX; + +static inline int serial_paranoia_check(struct m68k_async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + const char *badinfo = + "Warning: null m68k_async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +void rs_stop(struct tty_struct *tty) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + info->sw->enab_tx_int( info, 0 ); +} + +void rs_start(struct tty_struct *tty) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + info->sw->enab_tx_int( info, 1 ); +} + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &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); + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +static int startup(struct m68k_async_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->port || !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; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d...", info->line); +#endif + + /* initialize the hardware specific stuff for the port */ + info->sw->init(info); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set the speed and other port parameters. + */ + info->sw->change_speed(info); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct m68k_async_struct * info) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d\n", info->line); +#endif + + 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); + + /* do hardware specific deinitialization for the port */ + info->sw->deinit( info, info->tty && + !(info->tty->termios->c_cflag & HUPCL) ); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + 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++; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + info->sw->enab_tx_int( info, 1 ); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, total = 0; + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf || !tmp_buf) + return 0; + + if (from_user) + down(&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) { + restore_flags(flags); + copy_from_user(tmp_buf, buf, c); + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + } 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(&tmp_buf_sem); + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) + info->sw->enab_tx_int( info, 1 ); + restore_flags(flags); + return total; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + 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); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) { + info->x_char = STOP_CHAR(tty); + /* make sure the XOFF char is sent out if the TX was idle */ + info->sw->enab_tx_int( info, 1 ); + } + + if (C_CRTSCTS(tty)) + info->sw->throttle( info, 1 ); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + unsigned long flags; + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + /* Protect against an tx int between the test and resetting x_char. + * This would cause the XON to be lost. */ + save_flags(flags); + cli(); + if (info->x_char) { + info->x_char = 0; + restore_flags(flags); + } + else { + restore_flags(flags); + info->x_char = START_CHAR(tty); + /* make sure the XOFF char is sent out if the TX was idle */ + info->sw->enab_tx_int( info, 1 ); + } + } + + if (C_CRTSCTS(tty)) + info->sw->throttle( info, 0 ); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct m68k_async_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = 0; /* meaningless for non-Intel */ + tmp.irq = 0; /* meaningless for non-Intel */ + 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; /* meaningless for non-Intel */ + + /* At least baud_base and costum_divisor set by port-specific + * function + */ + info->sw->get_serial_info( info, &tmp ); + + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct m68k_async_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct m68k_async_struct old_info; + int retval = 0; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + old_info = *info; + + /* If a new custom divisor is to be set, let it check by the hardware + * specific code first! (It is given the new info struct in case the + * baud_base has also changed and valid divisors depend on the baud_base.) + */ + if (new_serial.custom_divisor != info->custom_divisor || + new_serial.baud_base != info->baud_base) { + if (info->sw->check_custom_divisor( info, new_serial.baud_base, + new_serial.custom_divisor )) + return( -EINVAL ); + } + + if (((new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) + && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->custom_divisor = new_serial.custom_divisor; + info->type = new_serial.type; + info->close_delay = new_serial.close_delay * HZ/100; + info->closing_wait = new_serial.closing_wait * HZ/100; + + if (!info->port || !info->type) + return 0; + if (info->flags & ASYNC_INITIALIZED) { + if (((old_info.flags & ASYNC_SPD_MASK) != + (info->flags & ASYNC_SPD_MASK)) || + (old_info.custom_divisor != info->custom_divisor) || + (old_info.baud_base != info->baud_base)) + info->sw->change_speed(info); + } else + retval = startup(info); + return retval; +} + + +static int get_modem_info(struct m68k_async_struct * info, unsigned int *value) +{ + unsigned int result; + + result = info->sw->get_modem_info (info); + return put_user(result,value); +} + +static int set_modem_info(struct m68k_async_struct * info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg; + int new_dtr = -1, new_rts = -1; + + if (get_user(arg, value)) + return -EFAULT; + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + new_rts = 1; + if (arg & TIOCM_DTR) + new_dtr = 1; + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + new_rts = 0; + if (arg & TIOCM_DTR) + new_dtr = 0; + break; + case TIOCMSET: + new_dtr = !!(arg & TIOCM_DTR); + new_rts = !!(arg & TIOCM_RTS); + break; + default: + return -EINVAL; + } + return( info->sw->set_modem_info( info, new_dtr, new_rts ) ); +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct m68k_async_struct * info = (struct m68k_async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + if (!info->port) + return; + save_flags(flags); + cli(); + if (break_state == -1) + info->sw->set_break(info, 1); + else + info->sw->set_break(info, 0); + restore_flags(flags); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct m68k_async_struct * info = (struct m68k_async_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERCONFIG: + /* return do_autoconfig(info); */ + return ( 0 ); + + case TIOCSERGETLSR: /* Get line status register */ + return put_user(0, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct m68k_async_struct *) arg, + info, sizeof(struct m68k_async_struct))) + return -EFAULT; + return 0; + + case TIOCSERGETMULTI: + case TIOCSERSETMULTI: + return -EINVAL; + + /* + * 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) || + put_user(cnow.dsr, &p_cuser->dsr) || + put_user(cnow.rng, &p_cuser->rng) || + put_user(cnow.dcd, &p_cuser->dcd)) + return -EFAULT; + return 0; + + default: + if (info->sw->ioctl) + return( info->sw->ioctl( tty, file, info, cmd, arg ) ); + else + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + info->sw->change_speed(info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * 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 rs_close(struct tty_struct *tty, struct file * filp) +{ + struct m68k_async_struct * info = (struct m68k_async_struct *)tty->driver_data; + unsigned long flags; + unsigned long timeout; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * 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("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + 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. + */ + if (info->flags & ASYNC_INITIALIZED) { + info->sw->stop_receive(info); + /* + * 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 (!(info->sw->trans_empty(info))) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->timeout); + if (signal_pending(current)) + break; + if (time_after(jiffies, timeout)) + break; + } + current->state = TASK_RUNNING; + } + 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); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct m68k_async_struct * info = (struct m68k_async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + rs_flush_buffer(tty); + 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); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct m68k_async_struct *info) +{ + struct wait_queue wait = { current, NULL }; + int retval; + int do_clocal = 0; + unsigned long flags; + + /* + * 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 + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -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 + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + info->line, info->count); +#endif + 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)) + info->sw->set_modem_info( info, 1, 1 ); + 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 || (info->sw->get_modem_info( info ) & TIOCM_CAR))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +/* + * 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 rs_open(struct tty_struct *tty, struct file * filp) +{ + struct m68k_async_struct *info; + int retval, line; + unsigned long page; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) + return -ENXIO; + info = rs_table + line; +#ifdef CONFIG_KMOD + if (!info->port) { + char modname[30]; + sprintf(modname, "char-major-%d-%d", TTY_MAJOR, MINOR(tty->device)); + request_module(modname); + } +#endif + if (!info->port) + return -ENXIO; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; + + if (info->sw->check_open) { + if ((retval = info->sw->check_open( info, tty, filp ))) + return( retval ); + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->count); +#endif + info->count++; + tty->driver_data = info; + info->tty = tty; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + 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 + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + MOD_INC_USE_COUNT; + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + 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; + info->sw->change_speed(info); + } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + info->sw->change_speed(info); + } +#endif + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * Boot-time initialization code: Init the serial ports present on + * this machine type. + * + * Current HW Port to minor/device name mapping: + * + * Atari + * TT | Falcon || minor | name + * -----------------------+---------------------------++-------+------- + * ST-MFP port (Modem1) | (Modem1, internal only) || 64 | ttyS0 + * SCC B (Modem2) | SCC B (Modem2) || 65 | ttyS1 + * TT-MFP port (Serial1) | || 66 | ttyS2 + * SCC A (Serial2) | || 67 | ttyS3 + * SCC A (LAN) | SCC A (LAN) || 68 | ttyS4 + * Atari MIDI | Atari MIDI || 69 | ttyS5 + * + * New 22/12/94: Midi is implemented as a serial device to make use of + * MIDI networks easier (SLIP on ttyS5). If there is need for MIDI + * specific high-level code, it can be implemented as a line + * discipline in future. ttyS4 is reserved to make space for the LAN + * device. It seems to be the better solution to split Serial2 and LAN + * into separate minors. And maybe the port to device mapping will + * change in future... + * + * 02/08/95: Now the mapping has changed! My old mapping scheme of the serial + * ports was a flaw in respect to order the devices following their + * capabilities. And it confused the users, to... The "new" order is the same + * as the one used by TOS. The only difference is that Serial2/LAN is split + * into two devices, only one of which can be open at one time. If one of + * these devices is opened, the respective port's hardware is activated via + * IO7 of the PSG (if connected...) + * + * Amiga + * Amiga built-in serial port || 64 | ttyS0 + * + * New 13/07/95: Support for multiple serial-boards of the same kind, + * and boards with dual (or higher) uarts. This is done by letting the + * drivers 'allocate' tty's in the rs_table[rs_count] array. A counter + * (rs_count) is therefore passed to all serial-init routines, that + * adds the amount of uarts detected, and returns the new value. + * I think this is the best way to manage the various serial-boards + * available (atleast for the Amiga), and should cause no harm to the + * old drivers. - Jes Sorensen (jds@kom.auc.dk) + * + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static inline void show_serial_version(void) +{ + printk(KERN_INFO "M68K Serial driver version 1.01\n"); +} + +EXPORT_SYMBOL(rs_table); +EXPORT_SYMBOL(tq_serial); +EXPORT_SYMBOL(m68k_register_serial); +EXPORT_SYMBOL(m68k_unregister_serial); +EXPORT_SYMBOL(rs_start); +EXPORT_SYMBOL(rs_stop); + +/* + * The serial driver boot-time initialization code! + */ +int __init m68k_rs_init(void) +{ + int i, rs_count; + struct m68k_async_struct * info; + +#ifdef CONFIG_Q40 + if (MACH_IS_Q40) + return 0; +#endif + rs_count = 0; /* All machines start at rs_table[0] (minor 64). */ + + init_bh(SERIAL_BH, do_serial_bh); + +#ifdef CONFIG_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_CONSDEV) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "serial"; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + /* TODO: serial_driver.wait_until_sent = rs_wait_until_sent; */ +#ifdef CONFIG_PROC_FS + serial_driver.read_proc = rs_read_proc; +#endif + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + + if (tty_register_driver(&serial_driver)) { + printk("Couldn't register serial driver\n"); + return -EIO; + } + if (tty_register_driver(&callout_driver)) { + tty_unregister_driver(&serial_driver); + printk("Couldn't register callout driver\n"); + return -EIO; + } + + for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { + info->magic = SERIAL_MAGIC; + info->line = i; + info->port = 0; + info->tty = 0; + info->type = PORT_UNKNOWN; + info->custom_divisor = 0; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->callout_termios =callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + info->delta_msr_wait = 0; + info->icount.cts = info->icount.dsr = 0; + info->icount.rng = info->icount.dcd = 0; + info->icount.rx = info->icount.tx = 0; + info->icount.frame = info->icount.parity = 0; + info->icount.overrun = info->icount.brk = 0; + info->next_port = 0; + info->prev_port = 0; + } + +#ifndef MODULE + switch (m68k_machtype) { + case MACH_ATARI: +#ifdef CONFIG_ATARI_SCC + atari_SCC_init(); +#endif +#ifdef CONFIG_ATARI_MFPSER + atari_MFPser_init(); +#endif +#ifdef CONFIG_ATARI_MIDI + atari_MIDI_init(); +#endif + break; + + case MACH_AMIGA: +#ifdef CONFIG_AMIGA_BUILTIN_SERIAL + amiga_serinit(); +#endif +#ifdef CONFIG_GVPIOEXT + ioext_init(); +#endif +#ifdef CONFIG_MULTIFACE_III_TTY + multiface_init(); +#endif +#ifdef CONFIG_WHIPPET_SERIAL + whippet_init(); +#endif +#ifdef CONFIG_HYPERCOM1 + hypercom1_init(); +#endif + break; + case MACH_MVME147: +#ifdef CONFIG_MVME147_SCC + m147_SCC_init(); +#endif + break; + case MACH_MVME16x: +#ifdef CONFIG_MVME162_SCC + mvme_SCC_init(); +#endif + break; + case MACH_BVME6000: +#ifdef CONFIG_BVME6000_SCC + bvme_SCC_init(); +#endif + break; + case MACH_MAC: +#ifdef CONFIG_MAC_SCC + mac_SCC_init(); +#endif + case MACH_HP300: +#ifdef CONFIG_HPDCA + hpdca_init(); +#endif + } /* end switch on machine type */ +#endif + + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + * + * ++roman: Removed PCish stuff from here... New calling interface: The caller + * can set req->line to a value >= 0 to request a particular slot. If + * req->line is < 0, the first free slot is assigned. Other fields that must + * be filled in before the call are 'port' and 'type'. + */ +int m68k_register_serial(struct serial_struct *req) +{ + int i; + unsigned long flags; + struct m68k_async_struct *info; + + save_flags(flags); + cli(); +#if !defined(__mc68000__) && !defined(CONFIG_APUS) + for (i = 0; i < NR_PORTS; i++) { + if (rs_table[i].port == req->port) + break; + } +#else + if (req->line >= 0) { + if (req->line >= NR_PORTS) + return -EINVAL; + if (rs_table[req->line].type != PORT_UNKNOWN || + rs_table[req->line].count > 0) { + /* already allocated */ + restore_flags(flags); + return -EBUSY; + } + i = req->line; + } + else { + for (i = 0; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } +#endif + if (i == NR_PORTS) { + restore_flags(flags); + return -EAGAIN; + } + info = &rs_table[i]; + if (rs_table[i].count) { + restore_flags(flags); + printk("Couldn't configure serial #%d (port=%d,irq=%d): " + "device already open\n", i, req->port, req->irq); + return -EBUSY; + } +#if !defined(__mc68000__) && !defined(CONFIG_APUS) + info->irq = req->irq; + info->port = req->port; + autoconfig(info); + if (info->type == PORT_UNKNOWN) { + restore_flags(flags); + printk("register_serial(): autoconfig failed\n"); + return -1; + } + printk(KERN_INFO "tty%02d at 0x%04x (irq = %d)", info->line, + info->port, info->irq); +#else + info->port = req->port; + info->type = req->type; + printk(KERN_INFO "ttyS%d at 0x%08x: ", info->line, info->port); +#endif + if (info->type >= 0 && info->type < PORT_MAX) + printk( "%s\n", serialtypes[info->type] ); +#if defined(__mc68000__) || defined(CONFIG_APUS) + else if (info->type >= 100 && info->type < 100 + M68K_PORT_MAX) + printk( "%s\n", serialtypes68k[info->type - 100] ); +#endif + else + printk( "\n" ); + restore_flags(flags); + return info->line; +} + +void m68k_unregister_serial(int line) +{ + unsigned long flags; + struct m68k_async_struct *info = &rs_table[line]; + + save_flags(flags); + cli(); + if (info->tty) + tty_hangup(info->tty); + info->type = PORT_UNKNOWN; +#if defined(__mc68000__) || defined(CONFIG_APUS) + info->port = 0; +#endif + printk(KERN_INFO "tty%02d unloaded\n", info->line); + restore_flags(flags); +} + +#ifdef MODULE +int init_module(void) +{ + return m68k_rs_init(); +} + +void cleanup_module(void) +{ + if (tty_unregister_driver(&serial_driver)) + printk("SERIAL: failed to unregister serial driver\n"); + if (tty_unregister_driver(&callout_driver)) + printk("SERIAL: failed to unregister callout driver\n"); +} +#endif /* MODULE */ + + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_CONSOLE + +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +extern void amiga_serial_console_write(struct console *co, const char *s, unsigned int count); +extern int amiga_serial_console_wait_key(struct console *co); +extern void amiga_init_serial_console(struct async_struct *info, int cflag); + +extern void atari_mfp_console_write (struct console *co, const char *str, unsigned int count); +extern int atari_mfp_console_wait_key(struct console *co); +extern void atari_init_mfp_port( int cflag ); + +extern void atari_scc_console_write (struct console *co, const char *str, unsigned int count); +extern int atari_scc_console_wait_key(struct console *co); +extern void atari_init_scc_port( int cflag ); + +extern void atari_midi_console_write (struct console *co, const char *str, unsigned int count); +extern int atari_midi_console_wait_key(struct console *co); +extern void atari_init_midi_port( int cflag ); + +extern void mac_sccb_console_write (struct console *co, const char *str, unsigned int count); +extern int mac_sccb_console_wait_key(struct console *co); +extern void mac_init_sccb_port( int cflag ); + +extern void mac_scca_console_write (struct console *co, const char *str, unsigned int count); +extern int mac_scca_console_wait_key(struct console *co); +extern void mac_init_scca_port( int cflag ); + +extern void mvme147_init_console_port (struct console *co, int cflag); +extern void mvme16x_init_console_port (struct console *co, int cflag); +extern void bvme6000_init_console_port (struct console *co, int cflag); + +extern void hpdca_serial_console_write(struct console *co, const char *str, unsigned int count); +extern int hpdca_serial_console_wait_key(struct console *co); +extern int hpdca_init_serial_console(int cflag); + +/* + * Setup initial baud/bits/parity. + */ +__initfunc(static int serial_console_setup(struct console *co, char *options)) +{ + char *s; + int baud = 0, bits, parity; + int cflag = CREAD | HUPCL | CLOCAL; + + bits = 8; + parity = 'n'; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* Now construct a cflag setting. */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + case 8: + default: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARENB|PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* Initialization of the port and filling in the missing fields of the + * sercons struct must happen here, since register_console() already uses + * write to print the log buffer. */ + + /* Currently this supports the Amiga builtin port only */ + if (MACH_IS_AMIGA && co->index == 0) { + co->write = amiga_serial_console_write; + co->wait_key = amiga_serial_console_wait_key; + /* no initialization yet */ + /* amiga_init_serial_console(rs_table+co->index, */ + /* serial_console_cflag); */ + } + /* On Atari, Modem1 (ttyS0), Modem2 (ttyS1) and MIDI (ttyS5) are supported + * Note: On a TT, 57.6 and 115.2 kbps are not possible and are replaced by + * 76.8 and 153.6 kbps. + * Note2: On MIDI, 7812.5 bps is selected by 4800 on the command line, and + * 500 kbps by 115200. All other rates give standard 31250bps. Mode 7N is + * not possible and replaced by 7O2 ... */ + else if (MACH_IS_ATARI && co->index == 0) { + co->write = atari_mfp_console_write; + co->wait_key = atari_mfp_console_wait_key; + atari_init_mfp_port( cflag ); + } + else if (MACH_IS_ATARI && co->index == 1) { + co->write = atari_scc_console_write; + co->wait_key = atari_scc_console_wait_key; + atari_init_scc_port( cflag ); + } + else if (MACH_IS_ATARI && co->index == 5) { + co->write = atari_midi_console_write; + co->wait_key = atari_midi_console_wait_key; + atari_init_midi_port( cflag ); + } + else if (MACH_IS_MVME147 && co->index == 0) { + mvme147_init_console_port (co, cflag); + } + else if (MACH_IS_MAC && co->index == 0) { + co->write = mac_scca_console_write; + co->wait_key = mac_scca_console_wait_key; + mac_init_scca_port( cflag ); + } + else if (MACH_IS_MAC && co->index == 1) { + co->write = mac_sccb_console_write; + co->wait_key = mac_sccb_console_wait_key; + mac_init_sccb_port( cflag ); + } + else if (MACH_IS_MVME16x && co->index == 0) { + mvme16x_init_console_port (co, cflag); + } + else if (MACH_IS_BVME6000 && co->index == 0) { + bvme6000_init_console_port (co, cflag); + } + return( 0 ); +} + +static void dummy_console_write( struct console *co, const char *str, + unsigned int count ) +{ +} + +static int dummy_wait_key( struct console *co ) +{ + return( '\r' ); +} + +static struct console sercons = { + "ttyS", + dummy_console_write, /* filled in by serial_console_setup */ + NULL, + serial_console_device, + dummy_wait_key, /* filled in by serial_console_setup */ + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * This is here to set the speed etc. for a non-initialized + * line. We have no termios struct yet, so we just use "cflag". + */ +long m68k_serial_console_init(long kmem_start, long kmem_end) +{ + /* I've opted to init the HP serial console here. Doing it in + * serial_console_setup (above) is clearly far too late, + * and in the machine-dependent setup is too early. + * This may not be precisely correct or very clean but it's + * easy, and I'm not going to spend any time fixing m68kserial.c + * because it's going to go away soon. + * -- Peter Maydell + */ +#ifdef CONFIG_HPDCA + if (MACH_IS_HP300) { + if (hpdca_init_serial_console(B9600|CS8)) { + sercons.write = hpdca_serial_console_write; + sercons.wait_key = hpdca_serial_console_wait_key; + } + } +#endif + register_console(&sercons); + return kmem_start; +} +#endif /* CONFIG_SERIAL_CONSOLE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/mac_SCC.c linux/drivers/char/mac_SCC.c --- v2.2.17/drivers/char/mac_SCC.c Fri Apr 21 12:46:04 2000 +++ linux/drivers/char/mac_SCC.c Fri Oct 13 23:52:23 2000 @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include @@ -61,6 +61,7 @@ #include #include #include +#include #ifndef CONFIG_MAC #include #endif @@ -708,8 +709,6 @@ static void SCC_init_port( struct m68k_async_struct *info, int type, int channel ) { - static int got_autovector = 0; - #ifdef SCC_DEBUG printk("mac_SCC: init_port, info %x \n", info); #endif @@ -729,16 +728,6 @@ * mac_SCC_interrupt with the proper arguments ... */ - if (!got_autovector) { - if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info)) - panic("macserial: can't get irq %d", IRQ4); -#ifdef SCC_DEBUG - printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n", - IRQ4, channel, info); -#endif - got_autovector = 1; - } - if (info->private->zs_chan_a == info->private->zs_channel) { /* Channel A */ if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info)) @@ -1129,7 +1118,14 @@ static void SCC_get_serial_info(struct m68k_async_struct * info, struct serial_struct * retinfo) { + retinfo->type = info->type; + retinfo->line = info->line; + retinfo->port = info->port; + retinfo->irq = info->irq; + retinfo->flags= info->flags; retinfo->baud_base = info->baud_base; + retinfo->close_delay=info->close_delay; + retinfo->closing_wait=info->closing_wait; retinfo->custom_divisor = info->custom_divisor; } @@ -1234,7 +1230,20 @@ copy_to_user((struct m68k_async_struct *) arg, info, sizeof(struct m68k_async_struct)); return 0; - + case TIOCGSERIAL: + { + struct serial_struct tmp; + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct)); + if (error) + return error; + if (!arg) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + SCC_get_serial_info(info, &tmp); + return copy_to_user((struct serial_struct *)arg, + &tmp, sizeof(tmp)); + } default: return -ENOIOCTLCMD; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/mem.c linux/drivers/char/mem.c --- v2.2.17/drivers/char/mem.c Fri Apr 21 12:46:04 2000 +++ linux/drivers/char/mem.c Wed Nov 8 23:03:17 2000 @@ -52,18 +52,6 @@ #ifdef CONFIG_MDA_CONSOLE extern void mda_console_init(void); #endif -#if defined(CONFIG_PPC) || defined(CONFIG_MAC) -extern void adbdev_init(void); -#endif -#ifdef CONFIG_USB_UHCI -int uhci_init(void); -#endif -#ifdef CONFIG_USB_OHCI -int ohci_init(void); -#endif -#ifdef CONFIG_USB_OHCI_HCD -int ohci_hcd_init(void); -#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -620,17 +608,6 @@ if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); -#ifdef CONFIG_USB -#ifdef CONFIG_USB_UHCI - uhci_init(); -#endif -#ifdef CONFIG_USB_OHCI - ohci_init(); -#endif -#ifdef CONFIG_USB_OHCI_HCD - ohci_hcd_init(); -#endif -#endif #if defined (CONFIG_FB) fbmem_init(); #endif @@ -678,9 +655,6 @@ #endif #ifdef CONFIG_VIDEO_BT848 i2c_init(); -#endif -#if defined(CONFIG_PPC) || defined(CONFIG_MAC) - adbdev_init(); #endif #ifdef CONFIG_VIDEO_DEV videodev_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/misc.c linux/drivers/char/misc.c --- v2.2.17/drivers/char/misc.c Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/misc.c Wed Nov 8 23:03:17 2000 @@ -43,9 +43,6 @@ #include #include #include -#ifdef CONFIG_APM -#include -#endif #include #include @@ -87,6 +84,7 @@ extern int pc110pad_init(void); extern int pmu_device_init(void); extern int tosh_init(void); +extern int rng_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -241,9 +239,6 @@ #ifdef CONFIG_DTLK dtlk_init(); #endif -#ifdef CONFIG_APM - apm_init(); -#endif #ifdef CONFIG_H8 h8_init(); #endif @@ -253,7 +248,7 @@ #ifdef CONFIG_BVME6000 rtc_DP8570A_init(); #endif -#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC) +#if defined(CONFIG_RTC) || defined(CONFIG_PPC_RTC) || defined(CONFIG_SUN_MOSTEK_RTC) rtc_init(); #endif #ifdef CONFIG_ATARI_DSP56K @@ -279,6 +274,9 @@ #endif #ifdef CONFIG_SGI streamable_init (); +#endif +#ifdef CONFIG_INTEL_RNG + rng_init (); #endif #ifdef CONFIG_TOSHIBA tosh_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c --- v2.2.17/drivers/char/n_hdlc.c Sun Jun 11 21:44:13 2000 +++ linux/drivers/char/n_hdlc.c Fri Sep 1 22:03:12 2000 @@ -118,13 +118,6 @@ #include #endif -#if LINUX_VERSION_CODE < VERSION(2,3,0) -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL} -#define init_waitqueue_head(head) *(head) = NULL -#define set_current_state(a) current->state = (a) -#endif - #if LINUX_VERSION_CODE >= VERSION(2,1,4) #include #define GET_USER(error,value,addr) error = get_user(value,addr) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/nvram.c linux/drivers/char/nvram.c --- v2.2.17/drivers/char/nvram.c Sun Jun 11 21:44:13 2000 +++ linux/drivers/char/nvram.c Wed Nov 1 16:54:42 2000 @@ -25,9 +25,10 @@ * the kernel and is not a module. Since the functions are used by some Atari * drivers, this is the case on the Atari. * + * 1.0a Paul Gortmaker: use rtc_lock, fix get/put_user in cli bugs. */ -#define NVRAM_VERSION "1.0" +#define NVRAM_VERSION "1.0a" #include #include @@ -78,10 +79,12 @@ #define mach_set_checksum atari_set_checksum #define mach_proc_infos atari_proc_infos +static spinlock_t rtc_lock; /* optimized away; no SMP m68K */ + #endif /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with - * interrupts disabled. Due to the index-port/data-port design of the RTC, we + * rtc_lock held. Due to the index-port/data-port design of the RTC, we * don't want two different things trying to get to it at once. (e.g. the * periodic 11 min sync from time.c vs. this driver.) */ @@ -233,23 +236,28 @@ unsigned long flags; unsigned i = *ppos; char *tmp = buf; + int checksum; if (i != *ppos) return -EINVAL; - save_flags(flags); - cli(); - - if (!nvram_check_checksum_int()) { - restore_flags(flags); + spin_lock_irqsave(&rtc_lock, flags); + checksum = nvram_check_checksum_int(); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (!checksum) return( -EIO ); - } for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp ) - put_user( nvram_read_int(i), tmp ); + { + int val; + spin_lock_irqsave(&rtc_lock, flags); + val = nvram_read_int(i); + spin_unlock_irqrestore(&rtc_lock, flags); + put_user( val, tmp ); + } *ppos = i; - restore_flags(flags); return( tmp - buf ); } @@ -260,26 +268,31 @@ unsigned i = *ppos; const char *tmp = buf; char c; + int checksum; if (i != *ppos) return -EINVAL; - save_flags(flags); - cli(); - - if (!nvram_check_checksum_int()) { - restore_flags(flags); + spin_lock_irqsave(&rtc_lock, flags); + checksum = nvram_check_checksum_int(); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (!checksum) return( -EIO ); - } for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp ) { get_user( c, tmp ); + spin_lock_irqsave(&rtc_lock, flags); nvram_write_int( c, i ); + spin_unlock_irqrestore(&rtc_lock, flags); } + + spin_lock_irqsave(&rtc_lock, flags); nvram_set_checksum_int(); + spin_unlock_irqrestore(&rtc_lock, flags); + *ppos = i; - restore_flags(flags); return( tmp - buf ); } @@ -295,14 +308,13 @@ if (!capable(CAP_SYS_ADMIN)) return( -EACCES ); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); for( i = 0; i < NVRAM_BYTES; ++i ) nvram_write_int( 0, i ); nvram_set_checksum_int(); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return( 0 ); case NVRAM_SETCKS: /* just set checksum, contents unchanged @@ -311,10 +323,9 @@ if (!capable(CAP_SYS_ADMIN)) return( -EACCES ); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); nvram_set_checksum_int(); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return( 0 ); default: @@ -363,11 +374,10 @@ int i, len = 0; off_t begin = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); for( i = 0; i < NVRAM_BYTES; ++i ) contents[i] = nvram_read_int( i ); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); *eof = mach_proc_infos( contents, buffer, &len, &begin, offset, size ); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.2.17/drivers/char/pc_keyb.c Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/pc_keyb.c Tue Nov 28 16:13:57 2000 @@ -58,6 +58,7 @@ static void kbd_write_output_w(int data); #ifdef CONFIG_PSMOUSE static void aux_write_ack(int val); +static int aux_reconnect = 0; #endif spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; @@ -399,18 +400,20 @@ } mouse_reply_expected = 0; } - else if(scancode == AUX_RECONNECT){ - queue->head = queue->tail = 0; /* Flush input queue */ - /* ping the mouse :) */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MOUSE); - kb_wait(); - kbd_write_output(AUX_ENABLE_DEV); - /* we expect an ACK in response. */ - mouse_reply_expected++; - kb_wait(); - return; - } + + else if(scancode == AUX_RECONNECT && aux_reconnect) + { + queue->head = queue->tail = 0; /* Flush input queue */ + /* ping the mouse :) */ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MOUSE); + kb_wait(); + kbd_write_output(AUX_ENABLE_DEV); + /* we expect an ACK in response. */ + mouse_reply_expected++; + kb_wait(); + return; + } add_mouse_randomness(scancode); if (aux_count) { @@ -428,6 +431,9 @@ #endif } +static unsigned char kbd_exists = 1; +static unsigned char status_mask = 0; /* At probe time we want all */ + /* * This reads the keyboard status port, and does the * appropriate action. @@ -444,17 +450,21 @@ unsigned char scancode; scancode = kbd_read_input(); -# ifdef CHECK_RECONNECT_SCANCODE - printk(KERN_INFO "-=db=-: kbd_read_input() : scancode == %d\n",scancode); -# endif - if (status & KBD_STAT_MOUSE_OBF) { - handle_mouse_event(scancode); - } else { - if (do_acknowledge(scancode)) - handle_scancode(scancode, !(scancode & 0x80)); - mark_bh(KEYBOARD_BH); + + /* Check for errors. Shouldnt ever happen but it does on Compaq + Presario 16[89]. */ + + if(!(status& status_mask)) + { + if (status & KBD_STAT_MOUSE_OBF) { + handle_mouse_event(scancode); + } else { + kbd_exists = 1; + if (do_acknowledge(scancode)) + handle_scancode(scancode, !(scancode & 0x80)); + mark_bh(KEYBOARD_BH); + } } - status = kbd_read_status(); if(!work--) @@ -506,7 +516,7 @@ mdelay(1); if (!--timeout) { #ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "Keyboard timeout[2]\n"); + printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?\n"); #endif return 0; } @@ -520,8 +530,10 @@ void pckbd_leds(unsigned char leds) { - if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds)) - send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ + if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) { + send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ + kbd_exists = 0; + } } /* @@ -545,6 +557,7 @@ kbd_startup_reset = 1; } + #define KBD_NO_DATA (-1) /* No data */ #define KBD_BAD_DATA (-2) /* Parity or other error */ @@ -736,12 +749,18 @@ #if defined CONFIG_PSMOUSE psaux_init(); #endif - + /* Switch keyboard processing to checking error bits */ + status_mask = KBD_STAT_GTO|KBD_STAT_PERR; /* Ok, finally allocate the IRQ, and off we go.. */ kbd_request_irq(keyboard_interrupt); } #if defined CONFIG_PSMOUSE + +void __init aux_reconnect_setup(char *str, int *ints) +{ + aux_reconnect=1; +} /* * Check if this is a dual port controller. diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.2.17/drivers/char/pcxx.c Fri Apr 21 12:46:04 2000 +++ linux/drivers/char/pcxx.c Sun Oct 1 11:19:19 2000 @@ -1781,10 +1781,9 @@ /* * pcxxdelay - delays a specified number of milliseconds */ -static void pcxxdelay(int msec) +static void pcxxdelay(int mseconds) { - while(msec-- > 0) - __delay(loops_per_sec/1000); + mdelay(mseconds); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/q40_keyb.c linux/drivers/char/q40_keyb.c --- v2.2.17/drivers/char/q40_keyb.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/q40_keyb.c Fri Oct 13 23:59:43 2000 @@ -0,0 +1,471 @@ +/* + * linux/drivers/char/q40_keyb.c + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Some configuration switches are present in the include file... */ + +#define KBD_REPORT_ERR + +/* Simple translation table for the SysRq keys */ + +#define SYSRQ_KEY 0x54 + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char q40kbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + +/* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/ +/* 0x00 means not a valid entry or no conversion known */ + +unsigned static char q40cl[256] = +{/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */ + 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00, /* 0x00 - 0x0f */ + 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00, /* 0x10 - 0x1f */ + 0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00, /* 0x20 - 0x2f 'f' is at 0x2b, what is 0x28 ???*/ + 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00, /* 0x30 - 0x3f */ + 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00, /* 0x40 - 0x4f */ + 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00, /* 0x50 - 0x5f*/ + 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f */ + 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00, /* 0x70 - 0x7f */ + 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f 0x84/0x37 is SySrq*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xf0 - 0xff */ +}; + +/* another table, AT 0xe0 codes to PC 0xe0 codes, + 0xff special entry for SysRq - DROPPED right now */ +static unsigned char q40ecl[]= +{/* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x00 - 0x0f*/ + 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x10 - 0x1f */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x20 - 0x2f*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x30 - 0x3f*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00, /* 0x40 - 0x4f*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00, /* 0x50 - 0x5f*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00, /* 0x60 - 0x6f*/ + 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00, /* 0x70 - 0x7f*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x80 - 0x8f*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0x90 - 0x9f*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xa0 - 0xaf*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xb0 - 0xbf*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xc0 - 0xcf*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xd0 - 0xdf*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0xe0 - 0xef*/ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 /* 0xf0 - 0xff*/ +}; + + +spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; + + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable. + * The keycodes 1-88,96-111,119 are fairly standard, and + * should probably not be changed - changing might confuse X. + * X also interprets scancode 0x5d (KEY_Begin). + * + * For 1-88 keycode equals scancode. + */ + +#define E0_KPENTER 96 +#define E0_RCTRL 97 +#define E0_KPSLASH 98 +#define E0_PRSCR 99 +#define E0_RALT 100 +#define E0_BREAK 101 /* (control-pause) */ +#define E0_HOME 102 +#define E0_UP 103 +#define E0_PGUP 104 +#define E0_LEFT 105 +#define E0_RIGHT 106 +#define E0_END 107 +#define E0_DOWN 108 +#define E0_PGDN 109 +#define E0_INS 110 +#define E0_DEL 111 + +#define E1_PAUSE 119 + +/* + * The keycodes below are randomly located in 89-95,112-118,120-127. + * They could be thrown away (and all occurrences below replaced by 0), + * but that would force many users to use the `setkeycodes' utility, where + * they needed not before. It does not matter that there are duplicates, as + * long as no duplication occurs for any single keyboard. + */ +#define SC_LIM 89 + +#define FOCUS_PF1 85 /* actual code! */ +#define FOCUS_PF2 89 +#define FOCUS_PF3 90 +#define FOCUS_PF4 91 +#define FOCUS_PF5 92 +#define FOCUS_PF6 93 +#define FOCUS_PF7 94 +#define FOCUS_PF8 95 +#define FOCUS_PF9 120 +#define FOCUS_PF10 121 +#define FOCUS_PF11 122 +#define FOCUS_PF12 123 + +#define JAP_86 124 +/* tfj@olivia.ping.dk: + * The four keys are located over the numeric keypad, and are + * labelled A1-A4. It's an rc930 keyboard, from + * Regnecentralen/RC International, Now ICL. + * Scancodes: 59, 5a, 5b, 5c. + */ +#define RGN1 124 +#define RGN2 125 +#define RGN3 126 +#define RGN4 127 + +static unsigned char high_keys[128 - SC_LIM] = { + RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ + 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ + FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ + FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ +}; + +/* BTC */ +#define E0_MACRO 112 +/* LK450 */ +#define E0_F13 113 +#define E0_F14 114 +#define E0_HELP 115 +#define E0_DO 116 +#define E0_F17 117 +#define E0_KPMINPLUS 118 +/* + * My OmniKey generates e0 4c for the "OMNI" key and the + * right alt key does nada. [kkoller@nyx10.cs.du.edu] + */ +#define E0_OK 124 +/* + * New microsoft keyboard is rumoured to have + * e0 5b (left window button), e0 5c (right window button), + * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] + * [or: Windows_L, Windows_R, TaskMan] + */ +#define E0_MSLW 125 +#define E0_MSRW 126 +#define E0_MSTM 127 + +/* this can be changed using setkeys : */ +static unsigned char e0_keys[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ + E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ + E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +static unsigned int prev_scancode = 0; /* remember E0, E1 */ + +int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + if (scancode < SC_LIM || scancode > 255 || keycode > 127) + return -EINVAL; + if (scancode < 128) + high_keys[scancode - SC_LIM] = keycode; + else + e0_keys[scancode - 128] = keycode; + return 0; +} + +int q40kbd_getkeycode(unsigned int scancode) +{ + return + (scancode < SC_LIM || scancode > 255) ? -EINVAL : + (scancode < 128) ? high_keys[scancode - SC_LIM] : + e0_keys[scancode - 128]; +} + + +#define disable_keyboard() +#define enable_keyboard() + + + +int q40kbd_pretranslate(unsigned char scancode, char raw_mode) +{ + if (scancode == 0xff) { + /* in scancode mode 1, my ESC key generates 0xff */ + /* the calculator keys on a FOCUS 9000 generate 0xff */ +#ifndef KBD_IS_FOCUS_9000 +#ifdef KBD_REPORT_ERR + if (!raw_mode) + printk(KERN_DEBUG "Keyboard error\n"); +#endif +#endif + prev_scancode = 0; + return 0; + } + + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + return 1; +} + +int q40kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + /*printk("translate ...\n");*/ + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = E1_PAUSE; + prev_scancode = 0; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); +#endif + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + /* + * The keyboard maintains its own internal caps lock and + * num lock statuses. In caps lock mode E0 AA precedes make + * code and E0 2A follows break code. In num lock mode, + * E0 2A precedes make code and E0 AA follows break code. + * We do our own book-keeping, so we will just ignore these. + */ + /* + * For my keyboard there is no caps lock mode, but there are + * both Shift-L and Shift-R modes. The former mode generates + * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. + * So, we should also ignore the latter. - aeb@cwi.nl + */ + if (scancode == 0x2a || scancode == 0x36) + return 0; + + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); +#endif + return 0; + } + } + } else if (scancode >= SC_LIM) { + /* This happens with the FOCUS 9000 keyboard + Its keys PF1..PF12 are reported to generate + 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f + Moreover, unless repeated, they do not generate + key-down events, so we have to zero up_flag below */ + /* Also, Japanese 86/106 keyboards are reported to + generate 0x73 and 0x7d for \ - and \ | respectively. */ + /* Also, some Brazilian keyboard is reported to produce + 0x73 and 0x7e for \ ? and KP-dot, respectively. */ + + *keycode = high_keys[scancode - SC_LIM]; + + if (!*keycode) { + if (!raw_mode) { +#ifdef KBD_REPORT_UNKN + printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" + " - ignored\n", scancode); +#endif + } + return 0; + } + } else + *keycode = scancode; + return 1; +} + +char q40kbd_unexpected_up(unsigned char keycode) +{ + /* unexpected, but this can happen: maybe this was a key release for a + FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ + if (keycode >= SC_LIM || keycode == 85) + return 0; + else + return 0200; +} + +static int keyup=0; +static int qprev=0; + +static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + unsigned char status; + + disable_keyboard(); + spin_lock_irqsave(&kbd_controller_lock, flags); + kbd_pt_regs = regs; + + status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); + if (status ) + { + unsigned char scancode,qcode; + + qcode = master_inb(KEYCODE_REG); + + if (qcode != 0xf0) + { + if (qcode == 0xe0) + { + qprev=0xe0; + handle_scancode(qprev); + goto exit; + } + + scancode=qprev ? q40ecl[qcode] : q40cl[qcode]; +#if 0 +/* next line is last resort to hanlde some oddities */ + if (qprev && !scancode) scancode=q40cl[qcode]; +#endif + qprev=0; + if (!scancode) + { + printk("unknown scancode %x\n",qcode); + goto exit; + } + if (scancode==0xff) /* SySrq */ + scancode=SYSRQ_KEY; + + handle_scancode(scancode | (keyup ? 0200 : 0)); + keyup=0; + mark_bh(KEYBOARD_BH); + + } + else + keyup=1; + } +exit: + spin_unlock_irqrestore(&kbd_controller_lock, flags); + master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */ + enable_keyboard(); +} + + + + +#ifdef CONFIG_MAGIC_SYSRQ +int kbd_is_sysrq(unsigned char keycode) +{ + return( keycode == SYSRQ_KEY ); +} +#endif /* CONFIG_MAGIC_SYSRQ */ + + + + +#define KBD_NO_DATA (-1) /* No data */ +#define KBD_BAD_DATA (-2) /* Parity or other error */ + +static int __init kbd_read_input(void) +{ + int retval = KBD_NO_DATA; + unsigned char status; + + status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG); + if (status) { + unsigned char data = master_inb(KEYCODE_REG); + + retval = data; + master_outb(-1,KEYBOARD_UNLOCK_REG); + } + return retval; +} + +extern void q40kbd_leds(unsigned char leds) +{ /* nothing can be done */ } + +static void __init kbd_clear_input(void) +{ + int maxread = 100; /* Random number */ + + do { + if (kbd_read_input() == KBD_NO_DATA) + break; + } while (--maxread); +} + + +void __init q40kbd_init_hw(void) +{ +#if 0 + /* Get the keyboard controller registers (incomplete decode) */ + request_region(0x60, 16, "keyboard"); +#endif + /* Flush any pending input. */ + kbd_clear_input(); + + /* Ok, finally allocate the IRQ, and off we go.. */ + request_irq(Q40_IRQ_KEYBOARD, keyboard_interrupt, 0, "keyboard", NULL); + master_outb(-1,KEYBOARD_UNLOCK_REG); + master_outb(1,KEY_IRQ_ENABLE_REG); + +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.2.17/drivers/char/qpmouse.c Fri Apr 21 12:46:05 2000 +++ linux/drivers/char/qpmouse.c Thu Aug 31 15:16:11 2000 @@ -349,9 +349,14 @@ printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n"); /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ + queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if(queue==NULL) + { + printk(KERN_ERR "qpmouse: no queue memory.\n"); + return -ENOMEM; + } qp_present = 1; misc_register(&qp_mouse); - queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; queue->proc_list = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c --- v2.2.17/drivers/char/radio-cadet.c Fri Apr 21 12:46:05 2000 +++ linux/drivers/char/radio-cadet.c Mon Sep 25 15:57:25 2000 @@ -548,7 +548,7 @@ { #ifndef MODULE if(cadet_probe()<0) { - return EINVAL; + return -EINVAL; } #endif if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/radio-maestro.c linux/drivers/char/radio-maestro.c --- v2.2.17/drivers/char/radio-maestro.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/radio-maestro.c Fri Sep 29 10:08:06 2000 @@ -0,0 +1,378 @@ +/* Maestro PCI sound card radio driver for Linux support + * (c) 2000 A. Tlalka, atlka@pg.gda.pl + * Notes on the hardware + * + * + Frequency control is done digitally + * + No volume control - only mute/unmute - you have to use Aux line volume + * control on Maestro card to set the volume + * + Radio status (tuned/not_tuned and stereo/mono) is valid some time after + * frequency setting (>100ms) and only when the radio is unmuted. + * version 0.02 + * + io port is automatically detected - only the first radio is used + * version 0.03 + * + thread access locking additions + * version 0.04 + * + code improvements + * + VIDEO_TUNER_LOW is permanent + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "0.04" + +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ + +#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */ + +#define IO_MASK 4 /* mask register offset from GPIO_DATA + bits 1=unmask write to given bit */ +#define IO_DIR 8 /* direction register offset from GPIO_DATA + bits 0/1=read/write direction */ + +#define GPIO6 0x0040 /* mask bits for GPIO lines */ +#define GPIO7 0x0080 +#define GPIO8 0x0100 +#define GPIO9 0x0200 + +#define STR_DATA GPIO6 /* radio TEA5757 pins and GPIO bits */ +#define STR_CLK GPIO7 +#define STR_WREN GPIO8 +#define STR_MOST GPIO9 + +#define FREQ_LO 50*16000 +#define FREQ_HI 150*16000 + +#define FREQ_IF 171200 /* 10.7*16000 */ +#define FREQ_STEP 200 /* 12.5*16 */ + +#define FREQ2BITS(x) ((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\ + /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */ + +#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) + + + +static int radio_open(struct video_device *, int); +static int radio_ioctl(struct video_device *, unsigned int, void *); +static void radio_close(struct video_device *); + +static struct video_device maestro_radio= +{ + "Maestro radio", + VID_TYPE_TUNER, + VID_HARDWARE_SF16MI, + radio_open, + radio_close, + NULL, + NULL, + NULL, + radio_ioctl, + NULL, + NULL +}; + +static struct radio_device +{ + __u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ + muted, /* VIDEO_AUDIO_MUTE */ + stereo, /* VIDEO_TUNER_STEREO_ON */ + tuned; /* signal strength (0 or 0xffff) */ + struct semaphore lock; +} radio_unit = {0, 0, 0, 0, MUTEX}; + +static int users = 0; + +static void sleep_125ms(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ >> 3); +} + +static void udelay4(void) +{ + udelay(4); +} + +static void udelay16(void) +{ + udelay(16); +} + +static __u32 radio_bits_get(struct radio_device *dev) +{ + register __u16 io=dev->io, l, rdata; + register __u32 data=0; + __u16 omask; + omask = inw(io + IO_MASK); + outw(~(STR_CLK | STR_WREN), io + IO_MASK); + outw(0, io); + udelay16(); + for (l=24;l--;) { + outw(STR_CLK, io); /* HI state */ + udelay4(); + if(!l) + dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff; + outw(0, io); /* LO state */ + udelay4(); + data <<= 1; /* shift data */ + rdata = inw(io); + if(!l) + dev->stereo = rdata & STR_MOST ? + 0 : VIDEO_TUNER_STEREO_ON; + else + if(rdata & STR_DATA) + data++; + udelay4(); + } + if(dev->muted) + outw(STR_WREN, io); + udelay4(); + outw(omask, io + IO_MASK); + return data & 0x3ffe; +} + +static void radio_bits_set(struct radio_device *dev, __u32 data) +{ + register __u16 io=dev->io, l, bits; + __u16 omask, odir; + omask = inw(io + IO_MASK); + odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); + outw(odir | STR_DATA, io + IO_DIR); + outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); + udelay16(); + for (l=25;l;l--) { + bits = ((data >> 18) & STR_DATA) | STR_WREN ; + data <<= 1; /* shift data */ + outw(bits, io); /* start strobe */ + udelay4(); + outw(bits | STR_CLK, io); /* HI level */ + udelay4(); + outw(bits, io); /* LO level */ + udelay4(); + } + if(!dev->muted) + outw(0, io); + udelay4(); + outw(omask, io + IO_MASK); + outw(odir, io + IO_DIR); + sleep_125ms(); +} + +inline static int radio_function(struct video_device *dev, + unsigned int cmd, void *arg) +{ + struct radio_device *card=dev->priv; + switch(cmd) { + case VIDIOCGCAP: { + struct video_capability v; + strcpy(v.name, "Maestro radio"); + v.type=VID_TYPE_TUNER; + v.channels=v.audios=1; + v.maxwidth=v.maxheight=v.minwidth=v.minheight=0; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + (void)radio_bits_get(card); + v.flags = VIDEO_TUNER_LOW | card->stereo; + v.signal = card->tuned; + strcpy(v.name, "FM"); + v.rangelow = FREQ_LO; + v.rangehigh = FREQ_HI; + v.mode = VIDEO_MODE_AUTO; + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + return 0; + } + case VIDIOCGFREQ: { + unsigned long tmp=BITS2FREQ(radio_bits_get(card)); + if(copy_to_user(arg, &tmp, sizeof(tmp))) + return -EFAULT; + return 0; + } + case VIDIOCSFREQ: { + unsigned long tmp; + if(copy_from_user(&tmp, arg, sizeof(tmp))) + return -EFAULT; + if ( tmpFREQ_HI ) + return -EINVAL; + radio_bits_set(card, FREQ2BITS(tmp)); + return 0; + } + case VIDIOCGAUDIO: { + struct video_audio v; + strcpy(v.name, "Radio"); + v.audio=v.volume=v.bass=v.treble=v.balance=v.step=0; + v.flags=VIDEO_AUDIO_MUTABLE | card->muted; + v.mode=VIDEO_SOUND_STEREO; + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + { + register __u16 io=card->io; + register __u16 omask = inw(io + IO_MASK); + outw(~STR_WREN, io + IO_MASK); + outw((card->muted = v.flags & VIDEO_AUDIO_MUTE) + ? STR_WREN : 0, io); + udelay4(); + outw(omask, io + IO_MASK); + sleep_125ms(); + return 0; + } + } + case VIDIOCGUNIT: { + struct video_unit v; + v.video=VIDEO_NO_UNIT; + v.vbi=VIDEO_NO_UNIT; + v.radio=dev->minor; + v.audio=0; + v.teletext=VIDEO_NO_UNIT; + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + default: return -ENOIOCTLCMD; + } +} + +static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct radio_device *card=dev->priv; + int ret; + down(&card->lock); + ret = radio_function(dev, cmd, arg); + up(&card->lock); + return ret; +} + +static int radio_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void radio_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + + +inline static __u16 radio_install(struct pci_dev *pcidev); + +#ifdef MODULE +MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl"); +MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio."); + +EXPORT_NO_SYMBOLS; + +void cleanup_module(void) +{ + video_unregister_device(&maestro_radio); +} + +int init_module(void) +#else +__initfunc(int maestro_radio_init(struct video_init *v)) +#endif +{ + register __u16 found=0; + struct pci_dev *pcidev = NULL; + if(!pci_present()) + return -ENODEV; + while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, + PCI_DEVICE_ID_ESS_ESS1968, + pcidev))) + found |= radio_install(pcidev); + while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, + PCI_DEVICE_ID_ESS_ESS1978, + pcidev))) + found |= radio_install(pcidev); + if(!found) { + printk(KERN_INFO "radio-maestro: no devices found.\n"); + return -ENODEV; + } + return 0; +} + +inline static __u16 radio_power_on(struct radio_device *dev) +{ + register __u16 io=dev->io; + register __u32 ofreq; + __u16 omask, odir; + omask = inw(io + IO_MASK); + odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); + outw(odir & ~STR_WREN, io + IO_DIR); + dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE; + outw(odir, io + IO_DIR); + outw(~(STR_WREN | STR_CLK), io + IO_MASK); + outw(dev->muted ? 0 : STR_WREN, io); + udelay16(); + outw(omask, io + IO_MASK); + ofreq = radio_bits_get(dev); + if((ofreqFREQ2BITS(FREQ_HI))) + ofreq = FREQ2BITS(FREQ_LO); + radio_bits_set(dev, ofreq); + return (ofreq == radio_bits_get(dev)); +} + +inline static __u16 radio_install(struct pci_dev *pcidev) +{ + if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) + return 0; + + radio_unit.io = (pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK) + + GPIO_DATA; + maestro_radio.priv = &radio_unit; + if(radio_power_on(&radio_unit)) { + if(video_register_device(&maestro_radio, VFL_TYPE_RADIO)==-1) { + printk("radio-maestro: can't register device!"); + return 0; + } + printk(KERN_INFO "radio-maestro: version " + DRIVER_VERSION + " time " + __TIME__ " " + __DATE__ + "\n"); + printk(KERN_INFO "radio-maestro: radio chip initialized\n"); + return 1; + } else + return 0; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/linux_compat.h linux/drivers/char/rio/linux_compat.h --- v2.2.17/drivers/char/rio/linux_compat.h Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/rio/linux_compat.h Sat Oct 28 11:22:06 2000 @@ -16,11 +16,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + #define disable(oldspl) save_flags (oldspl) #define restore(oldspl) restore_flags (oldspl) -#define sysbrk(x) kmalloc ((x), GFP_KERNEL) +#define sysbrk(x) kmalloc ((x),in_interrupt()? GFP_ATOMIC : GFP_KERNEL) #define sysfree(p,size) kfree ((p)) #define WBYTE(p,v) writeb(v, &p) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c --- v2.2.17/drivers/char/rio/rio_linux.c Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/rio/rio_linux.c Thu Dec 7 14:45:41 2000 @@ -165,7 +165,7 @@ /* startuptime */ HZ*2, /* how long to wait for card to run */ /* slowcook */ 0, /* TRUE -> always use line disc. */ /* intrpolltime */ 1, /* The frequency of OUR polls */ - /* breakinterval */ 25, /* x10 mS */ + /* breakinterval */ 25, /* x10 mS XXX: units seem to be 1ms not 10! -- REW*/ /* timer */ 10, /* mS */ /* RtaLoadBase */ 0x7000, /* HostLoadBase */ 0x7C00, @@ -205,11 +205,11 @@ static INT rio_fw_release(struct inode *inode, struct file *filp); static int rio_init_drivers(void); +int RIOShortCommand(struct rio_info *p, struct Port *PortP, + int command, int len, int arg); void my_hd (void *addr, int len); - - static struct tty_driver rio_driver, rio_callout_driver; static struct tty_driver rio_driver2, rio_callout_driver2; @@ -386,8 +386,8 @@ int rio_ismodem (kdev_t device) { - return (MAJOR (device) != RIO_NORMAL_MAJOR0) && - (MAJOR (device) != RIO_NORMAL_MAJOR1); + return (MAJOR (device) == RIO_NORMAL_MAJOR0) || + (MAJOR (device) == RIO_NORMAL_MAJOR1); } @@ -458,7 +458,6 @@ func_enter (); HostP = (struct Host*)ptr; /* &p->RIOHosts[(long)ptr]; */ - rio_dprintk (RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec); @@ -519,8 +518,8 @@ RIOServiceHost(p, HostP, irq); - rio_dprintk ( RIO_DEBUG_IFLOW, "riointr() doing host %d type %d\n", - (int) ptr, HostP->Type); + rio_dprintk ( RIO_DEBUG_IFLOW, "riointr() doing host %p type %d\n", + ptr, HostP->Type); clear_bit (RIO_BOARD_INTR_LOCK, &HostP->locks); rio_dprintk (RIO_DEBUG_IFLOW, "rio: exit rio_interrupt (%d/%d)\n", @@ -627,8 +626,12 @@ /* Nothing special here... */ static void rio_shutdown_port (void * ptr) { + struct Port *PortP; + func_enter(); + PortP = (struct Port *)ptr; + PortP->gs.tty = NULL; #if 0 port->gs.flags &= ~ GS_ACTIVE; if (!port->gs.tty) { @@ -706,9 +709,8 @@ PortP->gs.count = 0; } - + PortP->gs.tty = NULL; rio_dec_mod_count (); - func_exit (); } @@ -731,20 +733,22 @@ static int rio_ioctl (struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { -#if 0 int rc; - struct rio_port *port = tty->driver_data; + struct Port *PortP; int ival; - /* func_enter2(); */ + func_enter(); + PortP = (struct Port *)tty->driver_data; rc = 0; switch (cmd) { +#if 0 case TIOCGSOFTCAR: rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned int *) arg); break; +#endif case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(int))) == 0) { @@ -754,16 +758,43 @@ (ival ? CLOCAL : 0); } break; + case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) - gs_getserial(&port->gs, (struct serial_struct *) arg); + gs_getserial(&PortP->gs, (struct serial_struct *) arg); + break; + case TCSBRK: + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_TTY, "BREAK on deleted RTA\n"); + rc = -EIO; + } else { + if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); + rc = -EIO; + } + } + break; + case TCSBRKP: + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_TTY, "BREAK on deleted RTA\n"); + rc = -EIO; + } else { + int l; + l = arg?arg*100:250; + if (l > 255) l = 255; + if (RIOShortCommand(p, PortP, SBREAK, 2, arg?arg*100:250) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); + rc = -EIO; + } + } break; case TIOCSSERIAL: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0) - rc = gs_setserial(&port->gs, (struct serial_struct *) arg); + rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg); break; +#if 0 case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) { @@ -795,17 +826,13 @@ ((ival & TIOCM_RTS) ? 1 : 0)); } break; - +#endif default: rc = -ENOIOCTLCMD; break; } - /* func_exit(); */ + func_exit(); return rc; -#else - return -ENOIOCTLCMD; -#endif - } @@ -1276,6 +1303,7 @@ hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; + hp->HostLock = SPIN_LOCK_UNLOCKED; rio_dprintk (RIO_DEBUG_PROBE, "Ivec: %x\n", hp->Ivec); rio_dprintk (RIO_DEBUG_PROBE, "Mode: %x\n", hp->Mode); @@ -1331,6 +1359,7 @@ * Moreover, the ISA card will work with the * special PCI copy anyway. -- REW */ hp->Mode = 0; + hp->HostLock = SPIN_LOCK_UNLOCKED; vpdp = get_VPD_PROM (hp); rio_dprintk (RIO_DEBUG_PROBE, "Got VPD ROM\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/rio_linux.h linux/drivers/char/rio/rio_linux.h --- v2.2.17/drivers/char/rio/rio_linux.h Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/rio/rio_linux.h Thu Dec 7 14:45:41 2000 @@ -94,22 +94,22 @@ recompile.... */ #if 1 #define rio_spin_lock_irqsave(sem, flags) do { \ + spin_lock_irqsave(sem, flags);\ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlockirqsave: %p %s:%d\n", \ sem, __FILE__, __LINE__);\ - spin_lock_irqsave(sem, flags);\ } while (0) #define rio_spin_unlock_irqrestore(sem, flags) do { \ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlockirqrestore: %p %s:%d\n",\ sem, __FILE__, __LINE__);\ - spin_unlock_irqrestore(sem, flags);\ + spin_unlock_irqrestore(sem, flags);\ } while (0) #define rio_spin_lock(sem) do { \ + spin_lock(sem);\ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlock: %p %s:%d\n",\ sem, __FILE__, __LINE__);\ - spin_lock(sem);\ } while (0) #define rio_spin_unlock(sem) do { \ @@ -165,7 +165,7 @@ #define rio_memcpy_fromio memcpy_fromio #endif -#define DEBUG +#define DEBUG 1 /* diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/rioboot.c linux/drivers/char/rio/rioboot.c --- v2.2.17/drivers/char/rio/rioboot.c Sat Sep 9 18:42:35 2000 +++ linux/drivers/char/rio/rioboot.c Sat Oct 28 11:22:06 2000 @@ -38,11 +38,11 @@ #include #include #include +#include #include #include #include #include - #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/riocmd.c linux/drivers/char/rio/riocmd.c --- v2.2.17/drivers/char/rio/riocmd.c Sat Sep 9 18:42:36 2000 +++ linux/drivers/char/rio/riocmd.c Thu Dec 7 14:46:51 2000 @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -80,7 +83,6 @@ #include "control.h" #include "cirrus.h" - static struct IdentifyRta IdRta; static struct KillNeighbour KillUnit; @@ -534,7 +536,7 @@ PortP->ModemState, ReportedModemStatus); PortP->ModemState = ReportedModemStatus; #ifdef MODEM_SUPPORT - if ( PortP->Mapped ) { + if ( PortP->Mapped && (PortP->PortState & PORT_ISOPEN) && !(PortP->PortState & RIO_CLOSING)) { /***********************************************************\ ************************************************************* *** *** @@ -546,12 +548,15 @@ ** If the device is a modem, then check the modem ** carrier. */ + if (PortP->gs.tty == NULL) break; - - if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && - ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) { + if (PortP->gs.tty->termios == NULL) + break; + + if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && + ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) { rio_dprintk (RIO_DEBUG_CMD, "Is there a Carrier?\n"); /* ** Is there a carrier? @@ -577,8 +582,9 @@ ** Has carrier just dropped? */ if (PortP->State & RIO_CARR_ON) { - if (PortP->State & (PORT_ISOPEN|RIO_WOPEN|RIO_MOPEN)) - tty_hangup (PortP->gs.tty); + if (PortP->State & (PORT_ISOPEN|RIO_WOPEN|RIO_MOPEN)) + tty_hangup (PortP->gs.tty); + PortP->State &= ~RIO_CARR_ON; rio_dprintk (RIO_DEBUG_CMD, "Carrirer just went down\n"); #ifdef STATS @@ -622,7 +628,8 @@ struct CmdBlk *CmdBlkP; CmdBlkP = (struct CmdBlk *)sysbrk(sizeof(struct CmdBlk)); - bzero(CmdBlkP, sizeof(struct CmdBlk)); + if (CmdBlkP) + bzero(CmdBlkP, sizeof(struct CmdBlk)); return CmdBlkP; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/rioinit.c linux/drivers/char/rio/rioinit.c --- v2.2.17/drivers/char/rio/rioinit.c Sat Sep 9 18:42:36 2000 +++ linux/drivers/char/rio/rioinit.c Sat Oct 28 11:22:06 2000 @@ -1446,7 +1446,7 @@ } RIODefaultName(p, HostP, rup); } - HostP->UnixRups[rup].RupLock = -1; + HostP->UnixRups[rup].RupLock = SPIN_LOCK_UNLOCKED; } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c --- v2.2.17/drivers/char/rio/riotable.c Sat Sep 9 18:42:36 2000 +++ linux/drivers/char/rio/riotable.c Sat Oct 28 11:22:06 2000 @@ -37,6 +37,8 @@ #include #include #include +#include + #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rio/riotty.c linux/drivers/char/rio/riotty.c --- v2.2.17/drivers/char/rio/riotty.c Sat Sep 9 18:42:36 2000 +++ linux/drivers/char/rio/riotty.c Thu Dec 7 14:45:41 2000 @@ -95,7 +95,7 @@ #endif static void RIOClearUp(struct Port *PortP); -static int RIOShortCommand(struct rio_info *p, struct Port *PortP, +int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg); @@ -451,8 +451,11 @@ PortP->gs.tty->termios->c_state |= WOPEN; */ PortP->State |= RIO_WOPEN; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + if (RIODelay (PortP, HUNDRED_MS) == RIO_FAIL) #if 0 if ( sleep((caddr_t)&tp->tm.c_canqo, TTIPRI|PCATCH)) +#endif { /* ** ACTION: verify that this is a good thing @@ -470,7 +473,6 @@ func_exit (); return -EINTR; } -#endif } PortP->State &= ~RIO_WOPEN; } @@ -526,8 +528,10 @@ #endif struct Port *PortP =ptr; /* pointer to the port structure */ int deleted = 0; - int try = 25; - int repeat_this = 0xff; + int try = -1; /* Disable the timeouts by setting them to -1 */ + int repeat_this = -1; /* Congrats to those having 15 years of + uptime! (You get to break the driver.) */ + long end_time; struct tty_struct * tty; unsigned long flags; int Modem; @@ -540,6 +544,12 @@ /* tp = PortP->TtyP;*/ /* Get tty */ tty = PortP->gs.tty; rio_dprintk (RIO_DEBUG_TTY, "TTY is at address 0x%x\n",(int)tty); + + if (PortP->gs.closing_wait) + end_time = jiffies + PortP->gs.closing_wait; + else + end_time = jiffies + MAX_SCHEDULE_TIMEOUT; + Modem = rio_ismodem(tty->device); #if 0 /* What F.CKING cache? Even then, a higly idle multiprocessor, @@ -572,7 +582,8 @@ ** clear the open bits for this device */ PortP->State &= (Modem ? ~RIO_MOPEN : ~RIO_LOPEN); - + PortP->State &= ~RIO_CARR_ON; + PortP->ModemState &= ~MSVR1_CD; /* ** If the device was open as both a Modem and a tty line ** then we need to wimp out here, as the port has not really @@ -604,7 +615,7 @@ */ rio_dprintk (RIO_DEBUG_TTY, "Timeout 1 starts\n"); -#if 0 + if (!deleted) while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted && (PortP->TxBufferIn != PortP->TxBufferOut) ) { @@ -625,7 +636,7 @@ } rio_spin_lock_irqsave(&PortP->portSem, flags); } -#endif + PortP->TxBufferIn = PortP->TxBufferOut = 0; repeat_this = 0xff; @@ -659,9 +670,9 @@ } if (!deleted) - while (try && (PortP->PortState & PORT_ISOPEN)) { + while (PortP->PortState & PORT_ISOPEN) { try--; - if (try == 0) { + if (time_after (jiffies, end_time)) { rio_dprintk (RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n" ); RIOPreemptiveCmd(p, PortP,FCLOSE); break; @@ -673,7 +684,11 @@ RIOClearUp( PortP ); goto close_end; } - RIODelay_ni(PortP, HUNDRED_MS); + if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); + RIOPreemptiveCmd(p, PortP,FCLOSE); + break; + } } rio_spin_lock_irqsave(&PortP->portSem, flags); rio_dprintk (RIO_DEBUG_TTY, "Close: try was %d on completion\n", try ); @@ -778,7 +793,7 @@ ** Other values of len aren't allowed, and will cause ** a panic. */ -static int RIOShortCommand(struct rio_info *p, struct Port *PortP, +int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg) { PKT *PacketP; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.2.17/drivers/char/rtc.c Fri Apr 21 12:46:06 2000 +++ linux/drivers/char/rtc.c Sat Oct 28 13:46:20 2000 @@ -42,10 +42,9 @@ /* * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with - * interrupts disabled. Due to the index-port/data-port (0x70/0x71) - * design of the RTC, we don't want two different things trying to - * get to it at once. (e.g. the periodic 11 min sync from time.c vs. - * this driver.) + * the rtc_lock held. Due to the index-port/data-port (0x70/0x71) design + * of the RTC, we don't want two different things trying to get to it at + * once. (e.g. the periodic 11 min sync from time.c vs. this driver.) */ #include @@ -110,13 +109,15 @@ static unsigned long epoch = 1900; /* year corresponding to 0x00 */ -unsigned char days_in_mo[] = -{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* * A very tiny interrupt handler. It runs with SA_INTERRUPT set, - * so that there is no possibility of conflicting with the - * set_rtc_mmss() call that happens during some timer interrupts. + * but there is possibility of conflicting with the set_rtc_mmss() + * call (the rtc irq and the timer irq can easily run at the same + * time in two different CPUs). So we need to serializes + * accesses to the chip with the rtc_lock spinlock that each + * architecture should implement in the timer code. * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) */ @@ -131,7 +132,10 @@ rtc_irq_data += 0x100; rtc_irq_data &= ~0xff; + /* runs with irq locally disabled (see SA_INTERRUPT flag). */ + spin_lock(&rtc_lock); rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); + spin_unlock(&rtc_lock); wake_up_interruptible(&rtc_wait); if (rtc_status & RTC_TIMER_ON) @@ -276,8 +280,7 @@ if (sec >= 60) sec = 0xff; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -288,7 +291,7 @@ CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); CMOS_WRITE(sec, RTC_SECONDS_ALARM); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } @@ -336,12 +339,11 @@ if ((yrs -= epoch) > 255) /* They are unsigned */ return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (yrs > 169) { - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return -EINVAL; } if (yrs >= 100) @@ -370,7 +372,7 @@ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ @@ -405,12 +407,11 @@ rtc_freq = arg; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; val |= (16 - tmp); CMOS_WRITE(val, RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } #ifdef __alpha__ @@ -465,15 +466,14 @@ unsigned char tmp; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); tmp = CMOS_READ(RTC_CONTROL); tmp &= ~RTC_PIE; tmp &= ~RTC_AIE; tmp &= ~RTC_UIE; CMOS_WRITE(tmp, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (rtc_status & RTC_TIMER_ON) { rtc_status &= ~RTC_TIMER_ON; @@ -546,11 +546,10 @@ while (jiffies - uip_watchdog < 2*HZ/100) barrier(); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(year); /* This should never happen... */ @@ -568,11 +567,10 @@ init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); rtc_freq = 1024; return 0; } @@ -596,12 +594,11 @@ printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq); mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); rtc_irq_data += ((rtc_freq/HZ)<<8); rtc_irq_data &= ~0xff; rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); } /* @@ -615,11 +612,10 @@ unsigned char batt, ctrl; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); batt = CMOS_READ(RTC_VALID) & RTC_VRT; ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); p = buf; @@ -690,10 +686,9 @@ unsigned long flags; unsigned char uip; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return uip; } @@ -723,8 +718,7 @@ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated * by the RTC when initially set to a non-zero value. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); @@ -732,7 +726,7 @@ rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); rtc_tm->tm_year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -763,13 +757,12 @@ * Only the values that we read from the RTC are set. That * means only tm_hour, tm_min, and tm_sec. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -794,13 +787,12 @@ unsigned char val; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_CONTROL); val &= ~bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); rtc_irq_data = 0; } @@ -809,12 +801,11 @@ unsigned char val; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_CONTROL); val |= bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); rtc_irq_data = 0; - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/saa7111.c linux/drivers/char/saa7111.c --- v2.2.17/drivers/char/saa7111.c Fri Apr 21 12:46:06 2000 +++ linux/drivers/char/saa7111.c Mon Sep 11 17:49:08 2000 @@ -85,7 +85,7 @@ 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; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/saa7185.c linux/drivers/char/saa7185.c --- v2.2.17/drivers/char/saa7185.c Fri Apr 21 12:46:06 2000 +++ linux/drivers/char/saa7185.c Mon Sep 11 17:49:08 2000 @@ -85,7 +85,7 @@ 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; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/ser_hpdca.c linux/drivers/char/ser_hpdca.c --- v2.2.17/drivers/char/ser_hpdca.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/ser_hpdca.c Sat Oct 14 00:04:25 2000 @@ -0,0 +1,997 @@ +/* + * Driver for the 98626/98644/internal serial interface on hp300/hp400 + * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs) + * + * This driver was written by Peter Maydell + * based on informaition gleaned from the NetBSD driver and the ser_ioext + * driver. Copyright(C) Peter Maydell 05/1998. + * The most significant difference between us and ser_ioext is that + * we have to worry about UARTs with no FIFO (ignoring the Amiga vs HP differences...) + * + * We worry about multiple boards in a system because ser_ioext does and + * it seems the sensible thing to do. It's untested, though. Also, are we + * duplicating work done by the hardware-independent m68k serial layer? + * (multiple devices seems like an obvious thing to go for...) + * + * The driver is called hpdca because the NetBSD driver is 'dca' and + * I wanted something less generic than hp300... + * + * N.B. On the hp700 and some hp300s, there is a "secret bit" with + * undocumented behavior. The third bit of the Modem Control Register + * (MCR_IEN == 0x08) must be set to enable interrupts. Failure to do + * so can result in deadlock on those machines, whereas there don't seem to + * be any harmful side-effects from setting this bit on non-affected + * machines. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include /* hwreg_present() */ +#include /* readb(), writeb() */ +#include + +#include "ser_hpdca.h" + +/* Set these to 0 when the driver is finished */ +#define HPDCA_DEBUG 1 +#define DEBUG_IRQ 1 +#define DEBUG 1 +#define DEBUG_FLOW 1 + +#define FIFO_TRIGGER_LEVEL FIFO_TRIG_8 + +/***************************** Prototypes *****************************/ +static void hpdca_ser_interrupt(volatile struct uart_16c550 *uart, int line, + int hasfifo, int *spurious_count); +static void ser_init( struct m68k_async_struct *info ); +static void ser_deinit( struct m68k_async_struct *info, int leave_dtr ); +static void ser_enab_tx_int( struct m68k_async_struct *info, int enab_flag ); +static int ser_check_custom_divisor(struct m68k_async_struct *info, + int baud_base, int divisor); +static void ser_change_speed( struct m68k_async_struct *info ); +static void ser_throttle( struct m68k_async_struct *info, int status ); +static void ser_set_break( struct m68k_async_struct *info, int break_flag ); +static void ser_get_serial_info( struct m68k_async_struct *info, + struct serial_struct *retinfo ); +static unsigned int ser_get_modem_info( struct m68k_async_struct *info ); +static int ser_set_modem_info( struct m68k_async_struct *info, int new_dtr, + int new_rts ); +static void ser_stop_receive(struct m68k_async_struct *info); +static int ser_trans_empty(struct m68k_async_struct *info); +/************************* End of Prototypes **************************/ + +/* + * SERIALSWITCH structure for the dca + */ + +static SERIALSWITCH hpdca_ser_switch = { + ser_init, + ser_deinit, + ser_enab_tx_int, + ser_check_custom_divisor, + ser_change_speed, + ser_throttle, + ser_set_break, + ser_get_serial_info, + ser_get_modem_info, + ser_set_modem_info, + NULL, + ser_stop_receive, ser_trans_empty, NULL +}; + +/* table of divisors to use for various baud rates. DCABRD() is a macro + * which gives the correct ratio for the clock speed (hp300 vs hp700) + */ +static int hpdca_baud_table[16] = { + /* B0 */ 0, /* Never use this value !!! */ + /* B50 */ DCABRD(50), + /* B75 */ DCABRD(75), + /* B110 */ DCABRD(110), + /* B134 */ DCABRD(134), + /* B150 */ DCABRD(150), + /* B200 */ DCABRD(200), + /* B300 */ DCABRD(300), + /* B600 */ DCABRD(600), + /* B1200 */ DCABRD(1200), + /* B1800 */ DCABRD(1800), + /* B2400 */ DCABRD(2400), + /* B4800 */ DCABRD(4800), + /* B9600 */ DCABRD(9600), + /* B19200 */ DCABRD(19200), + /* B38400 */ DCABRD(38400) /* The last of the standard rates. */ +}; + +int hpdca_num; +hpdcaInfoType hpdca_info[MAX_HPDCA]; + +/* + * Functions + * + * dev_id = hpdca_info. + * + */ +static void hpdca_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* We have to take this interrupt and work out which board it's for. */ + int b; + + if (hpdca_num == 0) { + /* This interrupt can't be for us */ + return; + } + + for (b = 0; b < hpdca_num; b++) { + hpdca_struct *board = hpdca_info[b].board; + hpdcaInfoType *board_info = &hpdca_info[b]; + + if ((board->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE)) + /* interrupts not enabled, not for us */ + continue; + + /* Service any uart irqs. */ + hpdca_ser_interrupt(board_info->uart, board_info->line, + board_info->hasfifo, &board_info->spurious_count); + + if (board_info->spurious_count > 10000) { + board->dca_ic &= ~IC_IE; + printk("Too many spurious interrupts, disabling board irq\n"); + board_info->spurious_count = 0; + } + } /* for b */ +} + +/* +** hpdca_ser_interrupt() +** +** Check for and handle interrupts for this uart. +*/ +static void hpdca_ser_interrupt(volatile struct uart_16c550 *uart, int line, + int hasfifo, int *spurious_count) +{ + struct m68k_async_struct *info = rs_table + line; + + u_char iir; + u_char lsr; + int ch; + + iir = uart->IIR; + + ++*spurious_count; + +#if DEBUG_IRQ + printk("ttyS%d: IER=%02X, IIR=%02X, LSR=%02X, MSR=%02X\n", + line, uart->IER, iir, uart->LSR, uart->MSR); +#endif + + while (!(iir & IRQ_PEND)) { + /* IRQ for this uart */ +#if DEBUG_IRQ + printk("IRQ_PEND on ttyS%d...\n", line); +#endif + + /* This really is our interrupt */ + *spurious_count = 0; + + switch (iir & (IRQ_ID1 | IRQ_ID2 | IRQ_ID3)) { + case IRQ_RLS: /* Receiver Line Status */ +#if DEBUG_FLOW + printk("RLS irq on ttyS%d\n", line); +#endif + case IRQ_CTI: /* Character Timeout */ + case IRQ_RDA: /* Received Data Available */ +#if DEBUG_IRQ + printk("irq (IIR=%02X) on ttyS%d\n", line, iir); +#endif + /* + * Copy chars to the tty-queue ... + * Be careful that we aren't passing one of the + * Receiver Line Status interrupt-conditions without noticing. + */ + if (!hasfifo) + { + /* with no FIFO reads are trivial */ + ch = uart->RBR; + rs_receive_char(info, ch, 0); +#ifdef DEBUG_IRQ + printk("Read a char from FIFOless uart: %02X\n", ch); +#endif + } + else + { + int got = 0; + + lsr = uart->LSR; +#if DEBUG_IRQ + printk("uart->LSR & DR = %02X\n", lsr & DR); +#endif + while (lsr & DR) { + u_char err = 0; + ch = uart->RBR; +#if DEBUG_IRQ + printk("Read a char from the uart: %02X, lsr=%02X\n", + ch, lsr); +#endif + if (lsr & BI) { + err = TTY_BREAK; + } + else if (lsr & PE) { + err = TTY_PARITY; + } + else if (lsr & OE) { + err = TTY_OVERRUN; + } + else if (lsr & FE) { + err = TTY_FRAME; + } +#if DEBUG_IRQ + printk("rs_receive_char(ch=%02X, err=%02X)\n", ch, err); +#endif + rs_receive_char(info, ch, err); + got++; + lsr = uart->LSR; + } +#if DEBUG_FLOW + printk("[%d<]", got); +#endif + } + break; + + case IRQ_THRE: /* Transmitter holding register empty */ + { + int fifo_space = (hasfifo ? 16 : 1); /* no FIFO => send one char */ + int sent = 0; + +#if DEBUG_IRQ + printk("THRE-irq for ttyS%d\n", line); +#endif + + /* If the uart is ready to receive data and there are chars in */ + /* the queue we transfer all we can to the uart's FIFO */ + if (info->xmit_cnt <= 0 || info->tty->stopped || + info->tty->hw_stopped) { + /* Disable transmitter empty interrupt */ + uart->IER &= ~(ETHREI); + /* Need to send a char to acknowledge the interrupt */ + uart->THR = 0; +#if DEBUG_FLOW + if (info->tty->hw_stopped) { + printk("[-]"); + } + if (info->tty->stopped) { + printk("[*]"); + } +#endif + break; + } + + /* Handle software flow control */ + if (info->x_char) { +#if DEBUG_FLOW + printk("[^%c]", info->x_char + '@'); +#endif + uart->THR = info->x_char; + info->x_char = 0; + fifo_space--; + sent++; + } + + /* Fill the fifo */ + while (fifo_space > 0) { + fifo_space--; +#if DEBUG_IRQ + printk("Sending %02x to the uart.\n", + info->xmit_buf[info->xmit_tail]); +#endif + uart->THR = info->xmit_buf[info->xmit_tail++]; + sent++; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + if (--info->xmit_cnt == 0) { + break; + } + } +#if DEBUG_FLOW + printk("[>%d]", sent); +#endif + + if (info->xmit_cnt == 0) { +#if DEBUG_IRQ + printk("Sent last char - turning off THRE interrupts\n"); +#endif + /* Don't need THR interrupts any more */ + uart->IER &= ~(ETHREI); + } + + if (info->xmit_cnt < WAKEUP_CHARS) { + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + } + } + break; + + case IRQ_MS: /* Must be modem status register interrupt? */ + { + u_char msr = uart->MSR; +#if DEBUG_IRQ + printk("MS-irq for ttyS%d: %02x\n", line, msr); +#endif + + if (info->flags & ASYNC_INITIALIZED) { + if (msr & DCTS) { + rs_check_cts(info, (msr & CTS)); /* active high */ +#if DEBUG_FLOW + printk("[%c-%d]", (msr & CTS) ? '^' : 'v', + info->tty ? info->tty->hw_stopped : -1); +#endif + } + if (msr & DDCD) { +#if DEBUG + printk("rs_dcd_changed(%d)\n", !(msr & DCD)); +#endif + rs_dcd_changed(info, !(msr & DCD)); /* active low */ + } + } + } + break; + + default: +#if DEBUG_IRQ + printk("Unexpected irq for ttyS%d\n", line); +#endif + break; + } /* switch (iir) */ + iir = uart->IIR; + } /* while IRQ_PEND */ +} + +static void ser_init(struct m68k_async_struct *info) +{ +#if DEBUG + printk("ser_init\n"); +#endif + + while ((curruart(info)->LSR) & DR) { +#if HPDCA_DEBUG + printk("Emptying uart\n"); +#endif + (void)curruart(info)->RBR; + } + + /* Set DTR and RTS */ + curruart(info)->MCR |= (DTR | RTS | OUT2); + + /* Enable interrupts. IF_EXTER irq has already been enabled in hpdca_init()*/ + /* DON'T enable ETHREI here because there is nothing to send yet (murray) */ + curruart(info)->IER |= (ERDAI | ELSI | EMSI); + + MOD_INC_USE_COUNT; +} + + +static void ser_deinit(struct m68k_async_struct *info, int leave_dtr) +{ +#if DEBUG + printk("ser_deinit\n"); +#endif + + /* Wait for the uart to get empty */ + while(!(curruart(info)->LSR & TEMT)) { +#if HPDCA_DEBUG + printk("Waiting for the transmitter to finish\n"); +#endif + } + + while(curruart(info)->LSR & DR) { +#if HPDCA_DEBUG + printk("Uart not empty - flushing!\n"); +#endif + (void)curruart(info)->RBR; + } + + /* No need to disable UART interrupts since this will already + * have been done via ser_enab_tx_int() and ser_stop_receive() + */ + + ser_RTSoff(info); + if (!leave_dtr) { + ser_DTRoff(info); + } + + MOD_DEC_USE_COUNT; +} + +/* +** ser_enab_tx_int() +** +** Enable or disable tx interrupts. +** Note that contrary to popular belief, it is not necessary to +** send a character to cause an interrupt to occur. Whenever the +** THR is empty and THRE interrupts are enabled, an interrupt will occur. +** (murray) +*/ +static void ser_enab_tx_int(struct m68k_async_struct *info, int enab_flag) +{ + if (enab_flag) { + curruart(info)->IER |= ETHREI; + } + else { + curruart(info)->IER &= ~(ETHREI); + } +} + +static int ser_check_custom_divisor(struct m68k_async_struct *info, + int baud_base, int divisor) +{ + /* Always return 0 or else setserial spd_hi/spd_vhi doesn't work */ + return 0; +} + +static void ser_change_speed(struct m68k_async_struct *info) +{ + unsigned int cflag, baud, chsize, stopb, parity, aflags; + unsigned int div = 0, ctrl = 0; + +#if DEBUG + printk("ser_change_speed\n"); +#endif + + if (!info->tty || !info->tty->termios) + return; + + cflag = info->tty->termios->c_cflag; + baud = cflag & CBAUD; + chsize = cflag & CSIZE; + stopb = cflag & CSTOPB; + parity = cflag & (PARENB | PARODD); + aflags = info->flags & ASYNC_SPD_MASK; + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + +#if DEBUG + printk("Changing to baud-rate %i\n", baud); +#endif + + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + if (baud < 1 || baud > 4) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; + } + + /* Maximum speed is 38400 */ + if (baud > 15) + baud = 15; + div = hpdca_baud_table[baud]; + + if (!div) { + /* speed == 0 -> drop DTR */ +#if DEBUG + printk("Dropping DTR\n"); +#endif + ser_DTRoff(info); + return; + } + + /* + * We have to set DTR when a valid rate is chosen, otherwise DTR + * might get lost when programs use this sequence to clear the line: + * + * change_speed(baud = B0); + * sleep(1); + * change_speed(baud = Bx); x != 0 + * + * The pc-guys do this as well. + */ + ser_DTRon(info); + + if (chsize == CS8) { +#if DEBUG + printk("Setting serial word-length to 8-bits\n"); +#endif + ctrl |= data_8bit; + } + else if (chsize == CS7) { +#if DEBUG + printk("Setting serial word-length to 7-bits\n"); +#endif + ctrl |= data_7bit; + } + else if (chsize == CS6) { +#if DEBUG + printk("Setting serial word-length to 6-bits\n"); +#endif + ctrl |= data_6bit; + } + else if (chsize == CS5) { +#if DEBUG + printk("Setting serial word-length to 5-bits\n"); +#endif + ctrl |= data_5bit; + }; + + + /* If stopb is true we set STB which means 2 stop-bits - */ + /* otherwise we only get 1 stop-bit. */ + ctrl |= (stopb ? STB : 0); + + /* if parity disabled, ctrl |= 0 + * if odd parity, ctrl |= PEN + * if even parity, ctrl |= PEN|EPS + * Not my code -- PMM :-> + */ + ctrl |= ((parity & PARENB) ? + ((parity & PARODD) ? (PEN) : (PEN | EPS)) : 0x00 ); + +#if DEBUG + printk ("Storing serial-divisor %i\n", div); +#endif + + curruart(info)->LCR = (ctrl | DLAB); + + /* Store high byte of divisor */ + curruart(info)->DLM = ((div >> 8) & 0xff); + + /* Store low byte of divisor */ + + curruart(info)->DLL = (div & 0xff); + + curruart(info)->LCR = ctrl; +} + + +static void ser_throttle(struct m68k_async_struct *info, int status){ + +#if DEBUG + printk("ser_throttle\n"); +#endif + if (status){ + ser_RTSoff(info); + } + else{ + ser_RTSon(info); + } +} + + +static void ser_set_break(struct m68k_async_struct *info, int break_flag) +{ +#if HPDCA_DEBUG + printk("ser_set_break\n"); +#endif + if (break_flag) + curruart(info)->LCR |= SET_BREAK; + else + curruart(info)->LCR &= ~SET_BREAK; +} + + +static void ser_get_serial_info(struct m68k_async_struct *info, + struct serial_struct *retinfo) +{ + int b; + +#if DEBUG + printk("ser_get_serial_info\n"); +#endif + + retinfo->baud_base = HPDCA_BAUD_BASE; + /* This field is currently ignored by the upper layers of + * the serial driver, but we set it anyway :-> + * Is this really the best way to find out which board our caller + * is referring to??? + */ + for (b = 0; b < hpdca_num; b++) + if (hpdca_info[b].uart == curruart(info)) + retinfo->xmit_fifo_size = (hpdca_info[b].hasfifo ? 16 : 1); + + retinfo->custom_divisor = info->custom_divisor; +} + +static unsigned int ser_get_modem_info(struct m68k_async_struct *info) +{ + unsigned char msr, mcr; + +#if DEBUG + printk("ser_get_modem_info\n"); +#endif + + msr = curruart(info)->MSR; + mcr = curruart(info)->MCR; /* The DTR and RTS are located in the */ + /* ModemControlRegister ... */ + + return( + ((mcr & DTR) ? TIOCM_DTR : 0) | + ((mcr & RTS) ? TIOCM_RTS : 0) | + + ((msr & DCD) ? 0 : TIOCM_CAR) | /* DCD is active low */ + ((msr & CTS) ? TIOCM_CTS : 0) | + ((msr & DSR) ? TIOCM_DSR : 0) | + ((msr & RING_I) ? TIOCM_RNG : 0) + ); +} + +static int ser_set_modem_info(struct m68k_async_struct *info, int new_dtr, + int new_rts) +{ +#if DEBUG + printk("ser_set_modem_info new_dtr=%i new_rts=%i\n", new_dtr, new_rts); +#endif + if (new_dtr == 0) + ser_DTRoff(info); + else if (new_dtr == 1) + ser_DTRon(info); + + if (new_rts == 0) + ser_RTSoff(info); + else { + if (new_rts == 1) + ser_RTSon(info); + } + + return 0; +} + +static void ser_stop_receive (struct m68k_async_struct *info) +{ + /* Disable uart receive and status interrupts */ + curruart(info)->IER &= ~(ERDAI | ELSI | EMSI); +} + +static int ser_trans_empty (struct m68k_async_struct *info) +{ + return (curruart(info)->LSR & THRE); +} + +/* +** init_hpdca_uart(): init the uart. Returns 1 if UART has a FIFO, 0 otherwise +** +*/ +static int init_hpdca_uart(struct uart_16c550 *uart) +{ + /* Wait for the uart to get empty */ + while (!(uart->LSR & TEMT)) { +#if HPDCA_DEBUG + printk("Waiting for transmitter to finish\n"); +#endif + } + + /* + * Disable all uart interrups (they will be re-enabled in + * ser_init when they are needed). + */ + uart->IER = 0; + /* Master interrupt enable - National semconductors doesn't like + * to follow standards, so their version of the chip is + * different and I only had a copy of their data-sheets :-( + */ + uart->MCR = OUT2; + + /* + * Set the uart to a default setting of 8N1 - 9600 + */ + uart->LCR = (data_8bit | DLAB); + uart->DLM = 0; + uart->DLL = 48; + uart->LCR = (data_8bit); + + /* Enable + reset the tx and rx FIFO's. Set the rx FIFO-trigger count. + * If we then find that the bits in IIR that indicate enabling of + * the FIFOs are zero, we conclude that this uart has no FIFOs. + */ + uart->FCR = (FIFO_ENA | RCVR_FIFO_RES | XMIT_FIFO_RES | FIFO_TRIGGER_LEVEL); + udelay(100); /* wait for uart to get its act together */ + return (uart->IIR & (FIFO_ENA1 | FIFO_ENA0)); +} + +#ifdef CONFIG_SERIAL_CONSOLE + +/* + * Support for a serial console on the DCA port. We used to do this in config.c + * so it got set up early (and even if you didn't ask for serial console), but we + * don't any more. (PB) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * [I don't believe this!-- PMM] + * + * However, we still want it set up earlier than the normal serial device driver, + * so I've added a hook in m68kserial.c's serial_console_init() which is IMHO the + * right place for it. -- PMM + */ +static volatile struct uart_16c550 *uart = NULL; +static int conscode; + +/* Warning: we get called very early, so you can't allocate memory! + * [we could pass this function kmem_start, kmem_end if necessary] + */ +__initfunc(int hpdca_init_serial_console(int cflag)) +{ + /* here cflag encodes rqd baud rate, parity, etc */ + int baud = cflag & CBAUD; + int ctrl = 0; + int div, scode; + u_char stat; + int dly; + + switch (cflag & CSIZE) + { + case CS5: + ctrl = data_5bit; + break; + case CS6: + ctrl = data_6bit; + break; + case CS7: + ctrl = data_7bit; + break; + case CS8: + ctrl = data_8bit; + break; + } + + ctrl |= ((cflag & PARENB) ? ((cflag & PARODD) ? 0x8 : 0x18) : 0x00); + + if (baud < B1200 || baud > B38400) + baud = B9600; /* sensible default for unimplemented rates */ + + div = hpdca_baud_table[baud]; + /* Unfortunately we have to do a complete scan of the DIO bus in + * order to locate the serial port... + */ + for (scode = 0; scode < DIO_SCMAX; ++scode) + { + u_char *va; + u_char id; + + /* skip the hole and the internal HPIB controller */ + if (DIO_SCINHOLE(scode) || DIO_ISIHPIB(scode)) + continue; + + va = dio_scodetoviraddr(scode); + if (!va) + continue; + + if (!hwreg_present(va + DIO_IDOFF)) /* nothing there */ + continue; + + id = DIO_ID(va); /* get the ID byte */ + + if (id != DIO_ID_DCA0 && id != DIO_ID_DCA0REM + && id != DIO_ID_DCA1 && id != DIO_ID_DCA1REM) + continue; + + printk("Console is HP DCA at select code %d\n", scode); + /* OK, this is the DCA, set it up */ + writeb(0xff, va); /* DCA reset */ + /* should udelay(100) here */ + for(dly = 0; dly < 10000; dly++) + barrier(); /* defeat GCC optimisation! */ + + uart = (struct uart_16c550 *)(va+16); /* offset of the UART on the board */ + conscode = scode; /* save so we don't init this board again */ + + break; + } + + if (!uart) /* no DCA detected, abort */ + return 0; + + uart->IER = 0; /* disable interrupts */ + uart->MCR = OUT2; /* master interrupt enable */ + uart->LCR = (ctrl | DLAB); /* usual messing around to set divisor */ + uart->DLM = ((div >> 8) & 0xff); + uart->DLL = (div & 0xff); + uart->LCR = ctrl; + for(dly = 0; dly < 10000; dly++) + barrier(); /* defeat GCC optimisation! */ + stat = uart->IIR; /* ack any interrupts raised */ + + return 1; /* success */ +} + +static inline void hpdca_out(char c) +{ + u_char stat; + int timo; + + timo = 50000; + while (!(uart->LSR & THRE) && --timo) + barrier(); + uart->THR = c; + timo = 1500000; + while (!(uart->LSR & THRE) && --timo) /* wait for Tx to complete */ + barrier(); + stat = uart->IIR; /* ack any generated interrupts */ +} + + +void hpdca_serial_console_write(struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + hpdca_out('\r'); + hpdca_out(*str++); + } +} + +int hpdca_serial_console_wait_key(struct console *co) +{ + u_char stat; + + while(!(uart->LSR & DR)) + barrier(); + stat = uart->IIR; /* clear any generated ints */ + return(uart->RBR); +} + +#ifdef UNDEF +static struct console hpdca_console_driver = { + "debug", + hpdca_serial_console_write, + NULL, /* read */ + NULL, /* device */ + hpdca_serial_console_wait_key, + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL +}; +#endif /* UNDEF */ +#endif /* CONFIG_SERIAL_CONSOLE */ + +/* + * Detect and initialize all HP dca boards in this system. + */ +__initfunc(int hpdca_init(void)) +{ + int isr_installed = 0; + unsigned int scode = 0; + static char support_string[50] = "HP 98644A dca serial"; + int ipl; + + if (!MACH_IS_HP300) + return -ENODEV; + + memset(hpdca_info, 0, sizeof(hpdca_info)); + + for (;;) { + hpdca_struct *board; + int line; + struct uart_16c550 *uart; + struct serial_struct req; + + /* We detect boards by looking for DIO boards which match a + * given subset of IDs. dio_find() returns the board's scancode. + * The scancode to physaddr mapping is a property of the hardware, + * as is the scancode to IPL (interrupt priority) mapping. + */ + scode = dio_find(DIO_ID_DCA0); + if (!scode) + scode = dio_find(DIO_ID_DCA0REM); + if (!scode) + scode = dio_find(DIO_ID_DCA1); + if (!scode) + scode = dio_find(DIO_ID_DCA1REM); + if (!scode) + break; /* no, none at all */ + +#ifdef HPDCA_DEBUG + printk("Found DCA scode %d",scode); +#endif + board = (hpdca_struct *) dio_scodetoviraddr(scode); + ipl = dio_scodetoipl(scode); +#ifdef HPDCA_DEBUG + printk(" at viraddr %08lX, ipl %d\n",(u_long)board, ipl); +#endif + hpdca_info[hpdca_num].board = board; + hpdca_info[hpdca_num].scode = scode; +#ifdef CONFIG_SERIAL_CONSOLE + if (scode == conscode) + { + printk("Whoops, that's the console!\n"); + dio_config_board(scode); + /* What are we actually supposed to do here??? */ + continue; + } +#endif + /* Reset the DCA */ + board->dca_reset = 0xff; + udelay(100); + + /* Register the serial port device. */ + uart = &board->uart; + + req.line = -1; /* first free ttyS? device */ + req.type = SER_HPDCA; + req.port = (int)uart; /* yuck */ + if ((line = register_serial(&req)) < 0) { + printk( "Cannot register HP dca serial port: no free device\n" ); + break; + } + + /* Add this uart to our hpdca_info[] table */ + hpdca_info[hpdca_num].line = line; + hpdca_info[hpdca_num].uart = uart; + + rs_table[line].sw = &hpdca_ser_switch; + + /* We don't use these values */ + rs_table[line].nr_uarts = 0; + rs_table[line].board_base = board; + + /* init the UART proper and find out if it's got a FIFO */ + hpdca_info[hpdca_num].hasfifo = init_hpdca_uart(uart); + + /* Install ISR if it hasn't been installed already */ + if (!isr_installed) { + request_irq(ipl, hpdca_interrupt, 0, + support_string, hpdca_info); + isr_installed++; + } + hpdca_num++; + + /* tell the DIO code that this board is configured */ + dio_config_board(scode); + } + + return(0); +} + +#ifdef MODULE +int init_module(void) +{ + return(hpdca_init()); +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < hpdca_num; i++) { + hpdca_struct *board = hpdca_info[i].board; + int j; + + /* Disable board-interrupts */ + board->dca_ic &= ~IC_IE; + + /* Disable "master" interrupt select on uart */ + board->uart.MCR = 0; + + /* Disable all uart interrupts */ + board->uart.IER = 0; + + unregister_serial(hpdca_info[i].line); + + dio_unconfig_board(board->scode); + } + + if (hpdca_num != 0) { + /* Indicate to the IRQ handler that nothing needs to be serviced */ + hpdca_num = 0; + free_irq(dio_scodetoipl(hpdca_info[0].scode), hpdca_info); + } +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/ser_hpdca.h linux/drivers/char/ser_hpdca.h --- v2.2.17/drivers/char/ser_hpdca.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/ser_hpdca.h Sat Oct 14 00:04:25 2000 @@ -0,0 +1,91 @@ +/* + * Defines for the 98626/98644/internal serial interface on hp300/hp400 + * (based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs) + * + * This driver was written by Peter Maydell + * based on informaition gleaned from the NetBSD driver and the ser_ioext + * driver. Copyright(C) 05/1998. + * + * The driver is called hpdca because the NetBSD driver is 'dca' and + * I wanted something less generic than hp300... + * + * The NetBSD driver works for hp700 as well. I don't have one so I + * took the easy route and dropped support. However, this might be a good + * place to start if you're adding it back in again... + * + * N.B. On the hp700 and some hp300s, there is a "secret bit" with + * undocumented behavior. The third bit of the Modem Control Register + * (MCR_IEN == 0x08) must be set to enable interrupts. Failure to do + * so can result in deadlock on those machines, whereas there don't seem to + * be any harmful side-effects from setting this bit on non-affected + * machines. + */ + +#ifndef _SER_HPDCA_H_ +#define _SER_HPDCA_H_ + +/* 16bit baud rate divisor (lower byte in dca_data, upper in dca_ier). + * NB:the hp300 constant is for a clk frequency of 2.4576 + * ie HPDCA_BAUD_BASE = 2457600 / 16 + */ +#define HPDCA_BAUD_BASE 153600 +#define DCABRD(x) (HPDCA_BAUD_BASE / (x)) + +/* interface reset/id (300 only) */ +#define DCAID0 0x02 +#define DCAREMID0 0x82 +#define DCAID1 0x42 +#define DCAREMID1 0xC2 + +/* interrupt control (300 only) */ +#define DCAIPL(x) ((((x) >> 4) & 3) + 3) +#define IC_IR 0x40 +#define IC_IE 0x80 + +/* the 16c552 is two 16c550s and a parallel port, so its definitions + * of various register bits are OK for us. + */ +#include + +/* This is what the register layout looks like: */ +typedef struct +{ + /* card registers */ + u_char gap0; + volatile u_char dca_id; /* (read) */ +#define dca_reset dca_id /* (write) */ + u_char gap1; + volatile u_char dca_ic; /* interrupt control */ + u_char gap2; + volatile u_char dca_ocbrc; + u_char gap3; + volatile u_char dca_lcsm; + u_char gap4[8]; + /* chip registers */ + struct uart_16c550 uart; +} hpdca_struct; + +/* purely because the IOEXT code I'm copying uses 5 :-> */ +#define MAX_HPDCA 5 + +typedef struct +{ + volatile struct uart_16c550 *uart; + int hasfifo; /* does this UART have a FIFO? */ + hpdca_struct *board; + int scode; /* select code of this board */ + int spurious_count; + int line; +} hpdcaInfoType; + +extern int hpdca_num; /* number of detected boards */ +extern hpdcaInfoType hpdca_info[MAX_HPDCA]; + +#define curruart(info) ((struct uart_16c550 *)(info->port)) + +#define ser_DTRon(info) curruart(info)->MCR |= DTR +#define ser_RTSon(info) curruart(info)->MCR |= RTS +#define ser_DTRoff(info) curruart(info)->MCR &= ~DTR +#define ser_RTSoff(info) curruart(info)->MCR &= ~RTS + +#endif /* ndef _SER_HPDCA_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/ser_hypercom1.c linux/drivers/char/ser_hypercom1.c --- v2.2.17/drivers/char/ser_hypercom1.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/ser_hypercom1.c Fri Oct 13 23:57:54 2000 @@ -0,0 +1,658 @@ +#define HYPERCOM1_VERSION 1 +#define HYPERCOM1_REV 13 +#define HYPERCOM1_DATE "8.7.99" +/* + * HyperCOM1 driver for LinuxAPUS/M68K + * Project started 25-May-1999 by Gordon Huby + * Email: + * --------------------------------------------------------------------------- + * This code is based on ser_ioext.c by Jes Sorensen (jds@kom.auc.dk) + * and ser_whippet.c by Chris Sumner (chris@cpsumner.freeserve.co.uk) + * --------------------------------------------------------------------------- + * $Id: ser_hypercom1.c,v 1.13 1999/07/08 17:41:48 gordon Exp $ + * --------------------------------------------------------------------------- + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * --------------------------------------------------------------------------- + */ + +/* #include */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ser_hypercom1.h" + +/* comment out for no debuging */ +/* #define HYPERCOM1_DEBUG 1 */ + +/* port number */ +#ifndef SER_HYPERCOM1 +#define SER_HYPERCOM1 113 +#endif + +/* Some usefull macros */ +#define ser_DTRon(uart) ((uart->MCR) |= MCR_DTR) +#define ser_DTRoff(uart) ((uart->MCR) &= ~(MCR_DTR)) +#define ser_RTSon(uart) ((uart->MCR) |= MCR_RTS) +#define ser_RTSoff(uart) ((uart->MCR) &= ~(MCR_RTS)) + +/***************************** Prototypes *****************************/ +static void ser_init(struct m68k_async_struct *info); +static void ser_deinit(struct m68k_async_struct *info,int leave_dtr); +static void ser_enab_tx_int(struct m68k_async_struct *info,int enab_flag); +static int ser_check_custom_divisor(struct m68k_async_struct *info,int baud_base,int divisor); +static void ser_change_speed(struct m68k_async_struct *info); +static void ser_throttle(struct m68k_async_struct *info,int status); +static void ser_break(struct m68k_async_struct *info,int break_flag); +static void ser_get_serial_info(struct m68k_async_struct *info,struct serial_struct *retinfo); +static unsigned int ser_get_modem_info(struct m68k_async_struct *info); +static int ser_set_modem_info(struct m68k_async_struct *info,int new_dtr,int new_rts); +static int ser_ioctl(struct tty_struct *tty,struct file *file, + struct m68k_async_struct *info,unsigned int cmd,unsigned long arg); +static void ser_stop_receive(struct m68k_async_struct *info); +static int ser_trans_empty(struct m68k_async_struct *info); +/************************* End of Prototypes **************************/ + +/* + * SERIALSWITCH structure for HyperCOM1 serial port + */ + +static SERIALSWITCH hypercom1_ser_switch = { + ser_init, + ser_deinit, + ser_enab_tx_int, + ser_check_custom_divisor, + ser_change_speed, + ser_throttle, + ser_break, + ser_get_serial_info, + ser_get_modem_info, + ser_set_modem_info, + ser_ioctl, + ser_stop_receive, + ser_trans_empty, + NULL, +}; + +static u_int hypercom1_baud_table[20] = { + 0, + 50, + 75, + 110, + 134, + 150, + 200, + 300, + 600, + 1200, + 1800, + 2400, + 4800, + 9600, + 19200, + 38400, /* The last of the standard rates. */ + 57600, /* ASYNC_SPD_HI */ + 115200, /* ASYNC_SPD_VHI */ + 230400, /* ASYNC_SPD_SHI */ + 480600, /* ASYNC_SPD_WARP */ +}; + +/***************************************************************************/ +static const u_char fifo_trigger_level = TX_FIFO_TRIG_16 | RX_FIFO_TRIG_28; /* changeable */ +/*-------------------------------------------------------------------------*/ +static struct STARTECH_16C650 *hypercom1; +static struct m68k_async_struct *amiga_info; +static int line; +/***************************************************************************/ + +/* + * ser_interrupt() + */ +static void ser_interrupt(int irq, void *data, struct pt_regs *regs) +{ + struct m68k_async_struct *info = data; + u_char lsr,isr,ier; + +#ifdef HYPERCOM1_DEBUG + printk("ser_interrupt()\n"); +#endif + isr = hypercom1->ISR; + ier = hypercom1->IER; + + while (!(isr & IRQ_PEND)) { /* loop until no more ints */ + + switch (isr & IRQ_MASK) { + case IRQ_RLS: /* Receiver Line Status */ + case IRQ_RDTO: /* Receiver Data Timeout */ + case IRQ_RDR: /* Receiver Data Ready */ + /* + * Copy chars to the tty-queue ... + * Be careful that we aren't passing one of the + * Receiver Line Status interrupt-conditions without noticing. + */ + { + int ch; + + lsr = hypercom1->LSR; + while (lsr & LSR_RDR) { + u_char err; + ch = hypercom1->RHR; + + if (lsr & LSR_BI) err = TTY_BREAK; + else if (lsr & LSR_PE) err = TTY_PARITY; + else if (lsr & LSR_ORE) err = TTY_OVERRUN; + else if (lsr & LSR_FE) err = TTY_FRAME; + else err = 0; + + rs_receive_char(info, ch, err); + lsr = hypercom1->LSR; + } + } + break; + case IRQ_THRE: /* Transmitter holding register empty */ + { + int fifo_space = FIFO_SIZE; + int ch; + + while (fifo_space > 0) { + fifo_space--; + if ((ch = rs_get_tx_char(info)) >= 0) + hypercom1->THR = (u_char)ch; + if (ch == -1 || rs_no_more_tx(info)) { + ier &= ~(IER_THR); + break; + } + } +#ifdef HYPERCOM1_DEBUG + printk("fifo_space=%d\n",fifo_space); +#endif + } + break; + case IRQ_MSR: /* Must be modem status register interrupt? */ + { + u_char msr = hypercom1->MSR; + + if (info->flags & ASYNC_INITIALIZED) { + if (msr & MSR_DCTS) { +#ifdef HYPERCOM1_DEBUG + printk("CTS = %s\n",(msr & MSR_CTS) ? "ON" : "OFF"); +#endif + rs_check_cts(info, (msr & MSR_CTS)); + } + if (msr & MSR_DCD) + rs_dcd_changed(info, (msr & MSR_CD)); + } + } + break; + + } /* switch (iir) */ + + isr = hypercom1->ISR; + } /* while IRQ_PEND */ + +/* Re-enable UART interrupts */ + hypercom1->IER = ier; +} + +/*-------------------------------------------------------------------------*/ + +/* + * ser_init() init the port as necessary, set RTS and DTR and enable interrupts + * It does not need to set the speed and other parameters, because change_speed, + * is called too. + */ + +static void ser_init(struct m68k_async_struct *info) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_init()\n"); +#endif + /* Enable DTR and RTS */ + hypercom1->MCR |= (MCR_DTR | MCR_RTS | MCR_OP2); + + hypercom1->FCR = FCR_FE | FCR_RFR | FCR_XFR | fifo_trigger_level; + +/* Enable interrupts. IF_EXTER irq has already been enabled in hypercom1_init()*/ +/* DON'T enable IER_THR here because there is nothing to send yet (murray) */ + + hypercom1->IER |= (IER_RHR | IER_RLS | IER_MSI); + + MOD_INC_USE_COUNT; +} + +/*-------------------------------------------------------------------------*/ + +/* + * deinit(): Stop and shutdown the port (e.g. disable interrupts, ...) + */ +static void ser_deinit(struct m68k_async_struct *info,int leave_dtr) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_deinit()\n"); +#endif + hypercom1->IER=0x00; + + hypercom1->FCR = FCR_FE | FCR_RFR | FCR_XFR | fifo_trigger_level; + + ser_RTSoff(hypercom1); + if (!leave_dtr) ser_DTRoff(hypercom1); + + MOD_DEC_USE_COUNT; +} + +/*-------------------------------------------------------------------------*/ + +/* + * enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt + * independently from other interrupt sources. If the int is + * enabled, the transmitter should also be restarted, i.e. if there + * are any chars to be sent, they should be put into the Tx + * register. The real en/disabling of the interrupt may be a no-op + * if there is no way to do this or it is too complex. This Tx ints + * are just disabled to save some interrupts if the transmitter is + * stopped anyway. But the restarting must be implemented! + */ +static void ser_enab_tx_int(struct m68k_async_struct *info,int enab_flag) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_enab_tx_int(%s)\n",(enab_flag) ? "ON" : "OFF"); +#endif + if (enab_flag) hypercom1->IER |= IER_THR; + else hypercom1->IER &= ~(IER_THR); +} + +/*-------------------------------------------------------------------------*/ + +/* + * check_custom_divisor(): Check the given custom divisor for legality + * and return 0 if OK, non-zero otherwise. + */ +static int ser_check_custom_divisor(struct m68k_async_struct *info,int baud_base,int divisor) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_check_custom_divisor()\n"); +#endif + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * change_speed(): Set port speed, character size, number of stop + * bits and parity from the termios structure. If the user wants + * to set the speed with a custom divisor, he is required to + * check the baud_base first! + */ +static void ser_change_speed(struct m68k_async_struct *info) +{ + u_int cflag, real_baud, baud, chsize, stopb, parity, aflags; + u_int div = 0, ctrl = 0; + +#ifdef HYPERCOM1_DEBUG + printk("ser_change_speed()\n"); +#endif + if (!info->tty || !info->tty->termios) return; + + cflag = info->tty->termios->c_cflag; + baud = cflag & CBAUD; + chsize = cflag & CSIZE; + stopb = cflag & CSTOPB; + parity = cflag & (PARENB | PARODD); + aflags = info->flags & ASYNC_SPD_MASK; + + if (cflag & CRTSCTS) info->flags |= ASYNC_CTS_FLOW; + else info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; + else info->flags |= ASYNC_CHECK_CD; + + if (baud & CBAUDEX) + baud = baud - (B57600 - B38400 -1); + +#ifdef HYPERCOM1_DEBUG + printk("Baud=%d\n",baud); +#endif + if (baud == 15) { + switch (aflags) { + case ASYNC_SPD_HI: + baud += 1; + break; + case ASYNC_SPD_VHI: + baud += 2; + break; + case ASYNC_SPD_SHI: + baud += 3; + break; + case ASYNC_SPD_WARP: + baud += 4; + break; + case ASYNC_SPD_CUST: + div = info->custom_divisor; + break; + } + } + + if (!div) { + /* Maximum speed is 460800 */ + if (baud > 19) baud = 19; + real_baud = hypercom1_baud_table[baud]; + if (real_baud==0) div=0; + else div = HYPERCOM1_BAUD_BASE/real_baud; + } + +#ifdef HYPERCOM1_DEBUG + printk("divisor=%d, baud rate=%d\n",div,real_baud); +#endif + if (!div) { + /* speed == 0 -> drop DTR */ + ser_DTRoff(hypercom1); + return; + } + +/* + * We have to set DTR when a valid rate is chosen, otherwise DTR + * might get lost when programs use this sequence to clear the line: + * + * change_speed(baud = B0); + * sleep(1); + * change_speed(baud = Bx); x != 0 + * + * The pc-guys do this aswell. + */ + ser_DTRon(hypercom1); + + if (chsize == CS8) ctrl |= data_8bit; + else if (chsize == CS7) ctrl |= data_7bit; + else if (chsize == CS6) ctrl |= data_6bit; + else if (chsize == CS5) ctrl |= data_5bit; + +/* If stopb is true we set STB which means 2 stop-bits */ +/* otherwise we only get 1 stop-bit. */ + + ctrl |= (stopb ? LCR_SB : 0); + + ctrl |= ((parity & PARENB) ? ((parity & PARODD) ? (LCR_PE) : (LCR_PE | LCR_EP)) : 0x00 ); + + hypercom1->LCR = (ctrl | LCR_DLE); + + /* Store high byte of divisor */ + hypercom1->DLM = ((div >> 8) & 0xff); + +#ifdef HYPERCOM1_DEBUG + printk("DLM = 0x%.2X\n",((div >> 8) & 0xff)); +#endif + /* Store low byte of divisor */ + hypercom1->DLL = (div & 0xff); + +#ifdef HYPERCOM1_DEBUG + printk("DLL = 0x%.2X\n",(div & 0xff)); +#endif + hypercom1->LCR = ctrl; +} + +/*-------------------------------------------------------------------------*/ + +/* + * throttle(): Set or clear the RTS line according to 'status'. + */ +static void ser_throttle(struct m68k_async_struct *info,int status) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_throttle(rts=%s)\n", (status) ? "OFF" : "ON"); +#endif + if (status) ser_RTSoff(hypercom1); + else ser_RTSon(hypercom1); +} + +/*-------------------------------------------------------------------------*/ + +/* + * set_break(): Set or clear the 'Send a Break' flag. + */ +static void ser_break(struct m68k_async_struct *info,int break_flag) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_set_break(%s)\n", (break_flag) ? "ON" : "OFF"); +#endif + if (break_flag) hypercom1->LCR |= LCR_SETB; + else hypercom1->LCR &= ~LCR_SETB; + + return; +} + +/*-------------------------------------------------------------------------*/ + +/* + * get_serial_info(): Fill in the baud_base and custom_divisor + * fields of a serial_struct. It may also modify other fields, if + * needed. + */ +static void ser_get_serial_info(struct m68k_async_struct *info,struct serial_struct *retinfo) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_get_serial_info()\n"); +#endif + retinfo->baud_base = HYPERCOM1_BAUD_BASE; + retinfo->xmit_fifo_size = FIFO_SIZE; /* This field is currently ignored, */ + /* by the upper layers of the */ + /* serial-driver. */ + retinfo->custom_divisor = info->custom_divisor; +} + +/*-------------------------------------------------------------------------*/ + +/* + * get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS. + */ +static unsigned int ser_get_modem_info(struct m68k_async_struct *info) +{ + u_char msr, mcr; + +#ifdef HYPERCOM1_DEBUG + printk("ser_get_modem()\n"); +#endif + + msr = hypercom1->MSR; + mcr = hypercom1->MCR; /* The DTR and RTS are located in the */ + /* ModemControlRegister ... */ + return ( + ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | + ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | + + ((msr & MSR_CD) ? TIOCM_CAR : 0) | + ((msr & MSR_CTS) ? TIOCM_CTS : 0) | + ((msr & MSR_DSR) ? TIOCM_DSR : 0) | + ((msr & MSR_RING) ? TIOCM_RNG : 0) + ); +} + +/*-------------------------------------------------------------------------*/ + +/* + * set_modem_info(): Set the status of RTS and DTR according to + * 'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change + */ +static int ser_set_modem_info(struct m68k_async_struct *info,int new_dtr,int new_rts) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_set_modem(dtr=%s, rts=%s)\n",(new_dtr == 0) ? "OFF" : "ON",(new_rts == 0) ? "OFF" : "ON"); +#endif + + if (new_dtr == 0) ser_DTRoff(hypercom1); + else if (new_dtr == 1) ser_DTRon(hypercom1); + + if (new_rts == 0) ser_RTSoff(hypercom1); + else if (new_rts == 1) ser_RTSon(hypercom1); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* + * ioctl(): Process any port-specific ioctl's. This pointer may be + * NULL, if the port has no own ioctl's. + */ +static int ser_ioctl(struct tty_struct *tty,struct file *file, + struct m68k_async_struct *info,unsigned int cmd,unsigned long arg) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_ioctl()\n"); +#endif + return -ENOIOCTLCMD; +} + +/*-------------------------------------------------------------------------*/ + +/* + * stop_receive(): Turn off the Rx part of the port, so no more characters + * will be received. This is called before shutting the port down. + */ +static void ser_stop_receive(struct m68k_async_struct *info) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_stop_receive()\n"); +#endif + /* Disable uart receive and status interrupts */ + hypercom1->IER &= ~(IER_RHR | IER_RLS | IER_MSI); +} + +/*-------------------------------------------------------------------------*/ + +/* + * trans_empty(): Return !=0 if there are no more characters still to be + * sent out (Tx buffer register and FIFOs empty) + */ +static int ser_trans_empty(struct m68k_async_struct *info) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_trans_empty()\n"); +#endif + return (hypercom1->LSR & LSR_THE); +} + +/*-------------------------------------------------------------------------*/ + +static void ser_reset_port(void) +{ +#ifdef HYPERCOM1_DEBUG + printk("ser_reset_port()\n"); +#endif + hypercom1->IER=0x00; /* disable interrupts */ + hypercom1->MCR=MCR_OP2; /* master int */ + + (void)hypercom1->ISR; + (void)hypercom1->LSR; + (void)hypercom1->MSR; + + hypercom1->LCR=LCR_DLE; + hypercom1->DLL=0x30; + hypercom1->DLM=0x00; + + hypercom1->LCR=0x03; /* 8Bits, no parity, 1 stop bits, and disable latch enable */ + hypercom1->FCR=FCR_FE | FCR_RFR | FCR_XFR | fifo_trigger_level; +} + +/*-------------------------------------------------------------------------*/ + +static int check_port(void) +{ + int port_found=0; + + /* A write to SCRATCH with any byte, selects hypercom3/3+ first uart. */ + hypercom1->SCR=0xaa; + + if (hypercom1->LSR & LSR_TE) + port_found=1; + + return port_found; +} + +/*--------------------------------------------------------------------------*/ + +int hypercom1_init(void) +{ + unsigned long flags; + struct serial_struct req; + struct m68k_async_struct *info; + +#ifdef HYPERCOM1_DEBUG + printk("hypercom1_init\n"); +#endif + if (!(MACH_IS_AMIGA)) + return -ENODEV; + + /* Check if amiga1200 */ + if (amiga_model != AMI_1200) + return -ENODEV; + + /* init hypercom1 pointer */ + hypercom1 = (struct STARTECH_16C650 *) (zTwoBase + HYPERCOM1_PHYSADDR); + + /* Check if port exists */ + printk("Probing for HyperCOM1, version %d.%d date %s\n",HYPERCOM1_VERSION,HYPERCOM1_REV,HYPERCOM1_DATE); + if (check_port() == 0) { + printk("HyperCOM1 A1200 serial port not found\n"); + return -ENODEV; + } + printk("Found HyperCOM1 A1200 serial port\n"); + + ser_reset_port(); + + req.line = -1; + req.type = SER_HYPERCOM1; + req.port = (int) &(hypercom1->RHR); + + if ((line = register_serial( &req )) < 0) { + printk("Cannot register Hypercom1 serial port: no free device\n"); + return -EBUSY; + } + info = &rs_table[line]; + info->nr_uarts = 1; + info->sw = &hypercom1_ser_switch; + + amiga_info = info; /* static variable */ + + save_flags(flags); + cli(); + + /* Install handler for EXTER interupts */ + request_irq(IRQ_AMIGA_EXTER, ser_interrupt, 0, "hypercom1 serial port", info); + + restore_flags(flags); + return 0; +} + +/************************* Module Functions ********************************/ + +#ifdef MODULE +int init_module(void) +{ + return hypercom1_init(); +} + +void cleanup_module(void) +{ +#ifdef HYPERCOM1_DEBUG + printk("Closing HyperCOM1 Device!\n"); +#endif + unregister_serial(line); + + ser_reset_port(); + + free_irq(IRQ_AMIGA_EXTER,amiga_info); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/ser_hypercom1.h linux/drivers/char/ser_hypercom1.h --- v2.2.17/drivers/char/ser_hypercom1.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/ser_hypercom1.h Fri Oct 13 23:57:54 2000 @@ -0,0 +1,172 @@ +/* + * Serial driver for VMC's HyperCOM1 Serial Card for the Amiga1200. + * Copyright Gordon Huby 25-May-1999 + * Email: + * --------------------------------------------------------------------------- + * Hypercom1 == StarTech 16c650 UART + * --------------------------------------------------------------------------- + * $Id: ser_hypercom1.h,v 1.12 1999/07/08 18:51:03 gordon Exp $ + * --------------------------------------------------------------------------- + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * --------------------------------------------------------------------------- + */ + +#ifndef _SER_HYPERCOM1_H_ +#define _SER_HYPERCOM1_H_ + +#define HYPERCOM1_CLOCK_RATE (7372800) +#define HYPERCOM1_BAUD_BASE (HYPERCOM1_CLOCK_RATE/16) +#define HYPERCOM1_PHYSADDR (0xD80021) + +#define FIFO_SIZE (32) + +#ifndef PAD_S +#define PAD_S 3 +#endif + +struct STARTECH_16C650 { + u_char RHR; /* Reciever Holding Register */ + u_char pad0[PAD_S]; + u_char IER; /* Interupt Enable Register */ + u_char pad1[PAD_S]; + u_char FCR; /* FIFO control register */ + u_char pad2[PAD_S]; + u_char LCR; /* Line control register */ + u_char pad3[PAD_S]; + u_char MCR; /* Modem Control Register */ + u_char pad4[PAD_S]; + u_char LSR; /* Line Status Register */ + u_char pad5[PAD_S]; + u_char MSR; /* Modem Status Register */ + u_char pad6[PAD_S]; + u_char SCR; /* Scratchpad Register */ +}; + +#define THR RHR /* Transmit Holding Register */ +#define ISR FCR /* Interrupt Status Register */ + +#define LSB RHR /* Divisor latch lower address. Enabled only when bit 7 of MCR = 1 */ +#define MSB IER /* Divisor latch middle address. Enabled only when bit 7 of MC1 = 1 */ + +#define DLL LSB +#define DLM MSB + +#define EFR RHR /* Enhanced Feature Register Set, Enabled only when LCR is set to 0xBF */ +#define XON1 IER +#define XON2 FCR +#define XOFF1 LCR +#define XOFF2 MCR + +/* + * BIT DEFS FOR ST 16c650 + */ + +/* Interrupt Enable Register */ /* From Page 22 of st16c650.pdf */ +#define IER_RHR (1<<0) /* Recieve Holding Register */ +#define IER_THR (1<<1) /* Transmit Holding Register */ +#define IER_RLS (1<<2) /* Recieve Line Status Interrupt */ +#define IER_MSI (1<<3) /* Modem Status Interrupt */ +#define IER_SM (1<<4) /* Sleep Mode */ +#define IER_XOI (1<<5) /* Xoff Interrupt */ +#define IER_RTS (1<<6) /* RTS Interrupt */ +#define IER_CTS (1<<7) /* CTS Interupt */ + +/* Fifo control register */ +#define FCR_FE (1<<0) /* Fifo Enable */ +#define FCR_RFR (1<<1) /* Recieve Fifo reset */ +#define FCR_XFR (1<<2) /* XMIT Fifo Reset */ +#define FCR_DMS (1<<3) /* DMA Mode Select */ +#define FCR_TX_TRIG_LSB (1<<4) /* TX Trigger LSB */ +#define FCR_TX_TRIG_MSB (1<<5) /* TX Trigger MSB */ +#define FCR_RX_TRIG_LSB (1<<6) /* RX Trigger LSB */ +#define FCR_RX_TRIG_MSB (1<<7) /* RX Trigger MSB */ + +#define TX_FIFO_TRIG_16 (0x00) +#define TX_FIFO_TRIG_8 (FCR_TX_TRIG_LSB) +#define TX_FIFO_TRIG_24 (FCR_TX_TRIG_MSB) +#define TX_FIFO_TRIG_30 (FCR_TX_TRIG_LSB | FCR_TX_TRIG_MSB) + +#define RX_FIFO_TRIG_8 (0x00) +#define RX_FIFO_TRIG_16 (FCR_RX_TRIG_LSB) +#define RX_FIFO_TRIG_24 (FCR_RX_TRIG_MSB) +#define RX_FIFO_TRIG_28 (FCR_RX_TRIG_LSB | FCR_RX_TRIG_MSB) + +/* Interupt Status Register */ +#define ISR_IS (1<<0) /* INT status */ +#define ISR_IPB0 (1<<1) /* INT priority bit 0 */ +#define ISR_IPB1 (1<<2) /* INT priority bit 1 */ +#define ISR_IPB2 (1<<3) /* INT prioroty bit 2 */ +#define ISR_IPB3 (1<<4) /* INT priority bit 3 */ +#define ISR_IPB4 (1<<5) /* INT priority bit 4 */ +#define ISR_FE1 (1<<6) /* Fifo's enabled */ +#define ISR_FE2 (1<<7) /* Fifo's enabled */ + +#define IRQ_PEND ISR_IS /* Logic 0 = pending int, Logic 1 = no pending int */ +#define IRQ_RLS (0x06) /* Reciever line status register */ +#define IRQ_RDR (0x04) /* Recieved Data Ready */ +#define IRQ_RDTO (0x0C) /* Recieve Data time out */ +#define IRQ_THRE (0x02) /* Transmitter Holding Register Empty */ +#define IRQ_MSR (0x00) /* Modem Status Register */ +#define IRQ_RXOFF (0x10) /* (Recieved Xoff signal) / Special character */ +#define IRQ_CTSRTS (0x20) /* CTS, RTS change of state */ + +#define IRQ_MASK (ISR_IPB0 | ISR_IPB1 | ISR_IPB2 | ISR_IPB3 | ISR_IPB4) + +/* Line Control Register */ +#define LCR_WLB0 (1<<0) /* Word Length Bit 0 */ +#define LCR_WLB1 (1<<1) /* Word Length Bit 1 */ +#define LCR_SB (1<<2) /* Stop Bits */ +#define LCR_PE (1<<3) /* Parity enable */ +#define LCR_EP (1<<4) /* Even Parity */ +#define LCR_SP (1<<5) /* Set Parity */ +#define LCR_SETB (1<<6) /* Set Break */ +#define LCR_DLE (1<<7) /* Divisor Latch Enable */ + +#define data_5bit (0x00) +#define data_6bit (0x01) +#define data_7bit (0x02) +#define data_8bit (0x03) + +/* Modem Control Register */ +#define MCR_DTR (1<<0) /* DTR */ +#define MCR_RTS (1<<1) /* RTS */ +#define MCR_OP1 (1<<2) /* OP1 */ +#define MCR_OP2 (1<<3) /* OP1 / IRQx enable */ +#define MCR_LB (1<<4) /* Loop Back */ +#define MCR_ITS (1<<5) /* INT type select */ +#define MCR_IRE (1<<6) /* IR enable */ +#define MCR_CS (1<<7) /* Clock Select. logic 0=normal logic 1=4*baudrate*/ + +/* Line Status Register */ +#define LSR_RDR (1<<0) /* Recieve Data Ready */ +#define LSR_ORE (1<<1) /* OverRun Error */ +#define LSR_PE (1<<2) /* Parity Error */ +#define LSR_FE (1<<3) /* Framing Error */ +#define LSR_BI (1<<4) /* Break Interupt */ +#define LSR_THE (1<<5) /* Trans Holding Empty */ +#define LSR_TE (1<<6) /* Trans Empty */ +#define LSR_FDE (1<<7) /* Fifo Data Error */ + +/* Modem Status Register */ +#define MSR_DCTS (1<<0) /* Delta CTS */ +#define MSR_DDSR (1<<1) /* Delta DSR */ +#define MSR_DRI (1<<2) /* Delta RI */ +#define MSR_DCD (1<<3) /* Delta CD */ +#define MSR_CTS (1<<4) /* CTS */ +#define MSR_DSR (1<<5) /* DSR */ +#define MSR_RING (1<<6) /* RI */ +#define MSR_CD (1<<7) /* CD */ + +/* Enhanced Feature Register */ +#define EFR_CONT0 (1<<0) /* Cont0 TX RX Control */ +#define EFR_CONT1 (1<<1) /* Cont1 TX RX Control */ +#define EFR_CONT2 (1<<2) /* Cont2 TX RX Control */ +#define EFR_CONT3 (1<<3) /* Cont3 TX RX Control */ +#define EFR_ENA (1<<4) /* Enable IER bits 4-7, ISR FCR bits 4-5, MCR bits 5-7 */ +#define EFR_SCS (1<<5) /* Special Char Select */ +#define EFR_AUTORTS (1<<6) /* Auto RTS */ +#define EFR_AUTOCTS (1<<7) /* Auto CTS */ + +#endif /* _SER_HYPERCOM1_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/ser_mfc.c linux/drivers/char/ser_mfc.c --- v2.2.17/drivers/char/ser_mfc.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/ser_mfc.c Fri Oct 13 23:57:54 2000 @@ -0,0 +1,726 @@ + +/* serial driver for the two serial ports of a Multiface Card III + * + * Might also work with a SerialMaster or Multiface II, as far as I know + * the only difference is the frequency of the used quartz. + * Test it, and let me know if it works. Changing the baud table isn't worth a + * whole new driver. + * (To hardware hackers: It should be possible to get 115200 Baud with the older + * card by replacing the 3.6864 MHz quartz with a 7.3728 MHz one. But beware! + * The only one who knows that now effectively all baudrates are doubled is you + * and not any application. Besides, you should know what you are doing and you + * do it at your own risk.) + * + * Due to hardware constraints I decided to make the two ports of the card different. + * Port0 (the 9-pin-one) is only able to handle the following baud rates: + * 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400 + * (MFC II and Serial Master can do all standard rates.) + * Port1 (the 25-pin-one) can handle any approbriate custom baud rate. + * Tell me if you would prefer it the other way and why. Perhaps I'll make it + * configurable. + * + * Another solution would be to handle both ports the same way. + * But that would mean to support only standard baud rates or to get into + * big difficulties. On the other hand, you have more standard rates available. + * + * MIDI is missed with 5%. Can anyone tell me how to figure out which quartz + * is attached by software? I think the duart.device simply assumes 4.000MHz + * when you select MIDI baudrate. + * + * Another Hardware lack: If you select 5 bit character size a halve stop bit + * is sent too much. + * + * Hint to BSC: If they had used the IP2/3 pins for DCD and IP4/5 for DSR, + * I could use the change state interrupt feature of the duart instead of polling + * the DCD every vblank-interrupt. (Or does someone want to be interrupted when + * DSR changes state (i.e. modem switched on/off) instead of knowing when a + * connection is established/lost?) + * + * Note: The duart is able to handle the RTS/CTS-protocol in hardware. + * I use this feature to prevent receiver overruns by letting the DUART drop RTS + * when the FIFO is full + * + * created 15.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de) + * + * adapted 11.12.95 for 1.2.13 Joerg Dorchain + * + * improved 6. 2.96 Joerg Dorchain + * - fixed restart bug + * + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "multiface.h" +#include "mc68681.h" + +/* how many cards are to be supported */ +#define MAX_CARD 5 + +/***************************** Prototypes *****************************/ + +static void mfc_interrupt(int irq, void *data, struct pt_regs *fp); +static void mfc_vbl_inter(int irq, void *data, struct pt_regs *fp); +static void mfc_init( struct m68k_async_struct *info ); +static void mfc_deinit( struct m68k_async_struct *info, int leave_dtr ); +static void mfc_enab_tx_int( struct m68k_async_struct *info, int enab_flag ); +static int mfc_check_custom_divisor( struct m68k_async_struct *info, int + baud_base, int divisor ); +static void mfc_change_speed( struct m68k_async_struct *info ); +static void mfc_throttle( struct m68k_async_struct *info, int status ); +static void mfc_set_break( struct m68k_async_struct *info, int break_flag ); +static void mfc_get_serial_info( struct m68k_async_struct *info, + struct serial_struct *retinfo ); +static unsigned int mfc_get_modem_info( struct m68k_async_struct *info ); +static int mfc_set_modem_info( struct m68k_async_struct *info, int new_dtr, + int new_rts ); +static void mfc_stop_receive(struct m68k_async_struct *info); +static int mfc_trans_empty(struct m68k_async_struct *info); + +/************************* End of Prototypes **************************/ + + + +/* SERIALSWITCH structure for the Multiface serial ports */ + +static SERIALSWITCH mfc_ser_switch = { + mfc_init, mfc_deinit, mfc_enab_tx_int, + mfc_check_custom_divisor, mfc_change_speed, + mfc_throttle, mfc_set_break, + mfc_get_serial_info, mfc_get_modem_info, + mfc_set_modem_info, NULL, + mfc_stop_receive, mfc_trans_empty, NULL +}; + + + +/* These value go into the csr (Clock Select Registers) */ +/* 0xff means not available, B0 is handle special anyway */ + static u_char fixed_baud_III[16] = { + 0, /* B0 */ + 0xff, /* B50 */ + 0xff, /* B75 */ + 0xff, /* B110 */ + 0xff, /* B134 */ + 0xff, /* B150 */ + 0xff, /* B200 */ + 0x33, /* B300 */ + 0x44, /* B600 */ + 0x55, /* B1200 */ + 0xff, /* B1800 */ + 0x66, /* B2400 */ + 0x88, /* B4800 */ + 0x99, /* B9600 */ + 0xbb, /* B19200 */ + 0xcc /* B38400 */ + }; +/* These are precalculated timer values for standart rates */ + static u_short custom_baud_III[18] = { + 0, /* B0 */ + 4608, /* B50 */ + 3072, /* B75 */ + 2095, /* B110 - a little bit off (0.02%) */ + 1713, /* B134 - off by 0.0006% */ + 1536, /* B150 */ + 1152, /* B200 */ + 768, /* B300 */ + 384, /* B600 */ + 192, /* B1200 */ + 128, /* B1800 */ + 96, /* B2400 */ + 48, /* B4800 */ + 24, /* B9600 */ + 12, /* B19200 */ + 6, /* B38400 */ + 4, /* B57600 */ + 2 /* B115200 */ + }; + +static int nr_mfc; /* nr of ports configured */ +static int lines[MAX_CARD * 2]; /* accociated tty lines (index in rs_table) */ +static unsigned int board_index[MAX_CARD]; /* nr. of zorro slot */ +static unsigned char imask[MAX_CARD]; +static unsigned char acmask[MAX_CARD]; + +static void mfc_fill_tx(struct m68k_async_struct *info) +{ +struct duart *dp; +struct duarthalf *d; +int sta,i,mask,ch; + +dp=info->board_base; +d=(struct duarthalf *)info->port; +i=(info->nr_uarts-1)/2; +mask=(((info->nr_uarts-1)%2)==0)?1:16; +sta=d->sr_csr.sr; +while ((sta & 4) != 0) { /* fill the buffer */ + if ((ch = rs_get_tx_char( info )) >= 0) + d->hr.thr = ch; + else + break; + sta=d->sr_csr.sr; +} +if (rs_no_more_tx( info )) + imask[i] &= ~mask; +else + imask[i] |= mask; +dp->ir.imr = imask[i]; +} + +static u_char isr_entered = 0; + +static void mfc_interrupt(int irq, void *data, struct pt_regs *fp) +{ +int i; +int ireq; +struct duart *dp; +int ch; +int status; +int err; +int ipch; +u_short intenar; + + +intenar = (custom.intenar & IF_EXTER); +custom.intena = IF_EXTER; +if (isr_entered) { + printk("Reentering MFC isr.\n"); + custom.intena = (intenar | IF_SETCLR); + return; +} +isr_entered = 1; + +custom.intena = (intenar | IF_SETCLR); + +for (i = 0; i < nr_mfc; i += 2) { + dp = rs_table[lines[i]].board_base; + ireq = dp->ir.isr; + if ((ireq & imask[i/2]) !=0) { /* if it is "our" interrupt */ + /* first the transmitter */ + mfc_fill_tx(rs_table + lines[i]); /* channel A */ + mfc_fill_tx(rs_table + lines[i + 1]); /* channel B */ + { /* test for receiver ready */ + { + status = dp->pa.sr_csr.sr; /* empty the FIFO */ + while ((status & 1) != 0) { + ch = dp->pa.hr.rhr; + err = 0; + if ((status & SR_BREAK) != 0) + err |= TTY_BREAK; + if ((status & SR_FRAMING) != 0) + err |= TTY_FRAME; + if ((status & SR_PARITY) != 0) + err |= TTY_PARITY; + if ((status & SR_OVERRUN) != 0) + err |= TTY_OVERRUN; + rs_receive_char(rs_table + lines[i], ch, err); + status = dp->pa.sr_csr.sr; + } + } + { + status = dp->pb.sr_csr.sr; + while (( status & 1) != 0) { + ch = dp->pb.hr.rhr; + err = 0; + if ((status & SR_BREAK) != 0) + err |= TTY_BREAK; + if ((status & SR_FRAMING) != 0) + err |= TTY_FRAME; + if ((status & SR_PARITY) != 0) + err |= TTY_PARITY; + if ((status & SR_OVERRUN) != 0) + err |= TTY_OVERRUN; + rs_receive_char(rs_table + lines[i + 1], ch, err); + status = dp->pb.sr_csr.sr; + } + } + } + { /* CTS changed */ + ipch = dp->ipcr_acr.ipcr; + if ((ipch & 16) !=0) /* port a */ + rs_check_cts(rs_table + lines[i], !(ipch & 1)); + if ((ipch & 32) !=0) + rs_check_cts(rs_table + lines[i + 1], !(ipch & 2)); + } + } +} +custom.intreq = IF_EXTER; +isr_entered = 0; +} + +static u_char curr_dcd[MAX_CARD]; + +static void mfc_vbl_inter(int irq, void *data, struct pt_regs *fp) +{ +int i; +struct duart *dp; +u_char bits; + +for (i = 0; i < nr_mfc; i += 2) { + if (rs_table[lines[i]].flags & ASYNC_INITIALIZED) { + dp = rs_table[lines[i]].board_base; + bits = dp->ipr_opcr.ipr & 48; + if (bits ^ curr_dcd[i/2]) { + if (((bits ^ curr_dcd[i/2]) & 16) != 0) + rs_dcd_changed(rs_table + lines[i], !(bits & 16)); + if (((bits ^ curr_dcd[i/2]) & 32) != 0) + rs_dcd_changed(rs_table + lines[i + 1], !(bits & 32)); + } + curr_dcd[i/2] = bits; + } +} +} + +static void mfc_init( struct m68k_async_struct *info) +{ +struct duart *dp; +struct duarthalf *d; + +dp = info->board_base; +d = (struct duarthalf *)info->port; +if (((info->nr_uarts-1)%2) == 0) { /* port A */ + dp->start_sopc.sopc = 5; /* DTR & RTS on */ + imask[(info->nr_uarts-1)/2] |= 3|128; /* interrupts on */ + acmask[(info->nr_uarts-1)/2] |= 1; +} +else { + dp->start_sopc.sopc = 10; + imask[(info->nr_uarts-1)/2] |= 48|128; + acmask[(info->nr_uarts-1)/2] |= 2; +} +d->cr = CR_RESET_RX; +d->cr = CR_RESET_TX; +d->cr = CR_RESET_ERR; +d->cr = CR_RESET_BREAK; +d->cr = CR_STOP_BREAK; +d->cr = CR_RX_ON; +d->cr = CR_TX_ON; +curr_dcd[(info->nr_uarts-1)/2] = dp->ipr_opcr.ipr & 48; +custom.intena = IF_EXTER; +/* enable interrupts */ +dp->ir.imr = imask[(info->nr_uarts-1)/2]; +dp->ipcr_acr.acr = acmask[(info->nr_uarts-1)/2]; +custom.intena = (IF_EXTER | IF_SETCLR); +MOD_INC_USE_COUNT; +} + +static void mfc_deinit( struct m68k_async_struct *info, int leave_dtr) +{ +struct duart *dp; +struct duarthalf *d; +u_short intenar; + +dp = info->board_base; +d = (struct duarthalf *)info->port; +/* turn off interrupts CTS and DTR if required */ +if (((info->nr_uarts-1)%2) == 0) { + dp->stop_ropc.ropc = 1; + if (!leave_dtr) + dp->stop_ropc.ropc = 4; + imask[(info->nr_uarts-1)/2] &= ~3; + acmask[(info->nr_uarts-1)/2] &= ~1; +} +else { + dp->stop_ropc.ropc = 2; + if (!leave_dtr) + dp->stop_ropc.ropc = 8; + imask[(info->nr_uarts-1)/2] &= ~48; + acmask[(info->nr_uarts-1)/2] &= ~2; +} +intenar = (custom.intenar & IF_EXTER); +custom.intena = IF_EXTER; +dp->ir.imr = imask[(info->nr_uarts-1)/2]; +dp->ipcr_acr.acr = acmask[(info->nr_uarts-1)/2]; +custom.intena = (intenar | IF_SETCLR); +/* disable transmitter and receiver after current character */ +d->cr = CR_RX_OFF; +d->cr = CR_TX_OFF; +MOD_DEC_USE_COUNT; +} + +static void mfc_enab_tx_int(struct m68k_async_struct *info, int enab_flag) +{ +struct duart *dp; + +if (enab_flag) + mfc_fill_tx(info); /* fills the tx buf and enables interrupts */ +else { /* disable interrupts */ + /* we could also disable the transmitter at all */ + dp = info->board_base; + if (((info->nr_uarts-1)%2) == 0) + imask[(info->nr_uarts-1)/2] &= ~1; + else + imask[(info->nr_uarts-1)/2] &= ~16; + dp->ir.imr=imask[(info->nr_uarts-1)/2]; +} +} + +static int mfc_check_custom_divisor(struct m68k_async_struct *info, + int baud_base, int divisor) +{ +if (((info->nr_uarts-1)%2) == 0) + return 1; +if (baud_base != 230400) /* change for MFC II */ + return 1; +if (divisor < 2) + return 1; +return 0; +} + +static void mfc_change_speed(struct m68k_async_struct *info) +{ +u_int cflag, baud, chsize, stopb, parity, aflags; +u_int ctrl = 0; +u_short div = 0; +struct duart *dp; +struct duarthalf *d; +int dummy; + +if (!info->tty || ! info->tty->termios) + return; +dp = info->board_base; +d = (struct duarthalf *)info->port; +cflag = info->tty->termios->c_cflag; +baud = cflag & CBAUD; +chsize = cflag & CSIZE; +stopb = cflag & CSTOPB; +parity = cflag & (PARENB | PARODD); +aflags = info->flags & ASYNC_SPD_MASK; + +if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; +else + info->flags &= ~ASYNC_CTS_FLOW; +if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; +else + info->flags |= ASYNC_CHECK_CD; + +if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + if (baud < 1 || baud > 4) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; +} + +if (baud == 15) { + switch (aflags) { + case ASYNC_SPD_HI: + baud += 1; + break; + case ASYNC_SPD_VHI: + baud += 2; + break; + case ASYNC_SPD_SHI: + baud += 3; + break; + case ASYNC_SPD_WARP: + baud += 4; + break; + case ASYNC_SPD_CUST: + div = info->custom_divisor; + break; + } +} +if (!div) { + if (baud > 17) + baud = 17; + div = custom_baud_III[baud]; +} + +if (!div) { /* drop DTR */ + if (((info->nr_uarts-1)%2) == 0) + dp->stop_ropc.ropc = 4; + else + dp->stop_ropc.ropc = 8; + return; +} + +if (((info->nr_uarts-1)%2) == 0) { + dp->start_sopc.sopc = 4; /* set DTR */ + if (baud > 15) + baud =15; + if (fixed_baud_III[baud] != 0xff) + d->sr_csr.csr = fixed_baud_III[baud]; + else + printk("ttyS%d: ignored illegal baudrate %d\n", info->line,baud); +} +else { + dp->start_sopc.sopc = 8; + dp->ctu = div / 256; + dp->ctl = div % 256; + dummy = dp->start_sopc.start; +} +d->mr.mr2 = (stopb) ? MR2_2STOP: MR2_1STOP; + +if (chsize == CS8) + ctrl |= MR1_8BITS; +else if (chsize == CS7) + ctrl |= MR1_7BITS; +else if (chsize == CS6) + ctrl |= MR1_6BITS; +else if (chsize == CS5) + ctrl |= MR1_5BITS; + +if (parity & PARENB) + ctrl |= MR1_PARITY_WITH; +else + ctrl |= MR1_PARITY_NO; +if (parity & PARODD) + ctrl |= MR1_PARITY_ODD; + +d->cr = CR_RESET_MR; +d->mr.mr1 = ctrl|MR1_RxRTS_ON; +} + +static void mfc_throttle (struct m68k_async_struct *info, int status) +{ +struct duart *dp; + +dp = info->board_base; +if (((info->nr_uarts-1)%2) == 0) { + if (status) + dp->stop_ropc.ropc = 1; + else + dp->start_sopc.sopc = 1; +} +else { + if (status) + dp->stop_ropc.ropc = 2; + else + dp->start_sopc.sopc = 2; +} +} + +static void mfc_set_break (struct m68k_async_struct *info, int break_flag) +{ +struct duarthalf *d; + +d = (struct duarthalf *)info->port; +if (break_flag) + d->cr = CR_START_BREAK; +else + d->cr = CR_STOP_BREAK; +} + +static void mfc_get_serial_info( struct m68k_async_struct *info, + struct serial_struct *retinfo) +{ +if (((info->nr_uarts-1)%2) == 0) { + retinfo->baud_base = 0; + retinfo->custom_divisor = 0; +} +else { + retinfo->baud_base = 230400; + retinfo->custom_divisor = info->custom_divisor; +} +} + +static unsigned int mfc_get_modem_info(struct m68k_async_struct *info) +{ +struct duart *dp; +u_char inf; + +dp = info->board_base; +inf = dp->ipr_opcr.ipr; +if (((info->nr_uarts-1)%2) == 0) + return ((inf & 1) ? 0 : TIOCM_CTS) | + ((inf & 4) ? 0 : TIOCM_DSR) | + ((inf & 16) ? 0 : TIOCM_CAR) | + ((dp->pa.ri & 1) ? 0 : TIOCM_RNG); +else + return ((inf & 2) ? 0 : TIOCM_CTS) | + ((inf & 8) ? 0 : TIOCM_DSR) | + ((inf & 32) ? 0 : TIOCM_CAR) | + ((dp->pb.ri & 2) ? 0 : TIOCM_RNG); +/* No chance to check DTR & RTS easily */ +} + +static int mfc_set_modem_info(struct m68k_async_struct *info, int new_dtr, int new_rts) +{ +struct duart *dp; + +dp = info->board_base; +if (((info->nr_uarts-1)%2) == 0) { + if (new_dtr == 0) + dp->stop_ropc.ropc = 4; + else if (new_dtr == 1) + dp->start_sopc.sopc = 4; + if (new_rts == 0) + dp->stop_ropc.ropc = 1; + else if (new_rts == 1) + dp->start_sopc.sopc = 1; +} +else { + if (new_dtr == 0) + dp->stop_ropc.ropc = 8; + else if (new_dtr == 1) + dp->start_sopc.sopc = 8; + if (new_rts == 0) + dp->stop_ropc.ropc = 2; + else if (new_rts == 1) + dp->start_sopc.sopc = 2; +} +return 0; +} + +static void mfc_stop_receive(struct m68k_async_struct *info) +{ +struct duart *dp; + +dp = info->board_base; +if (((info->nr_uarts-1)%2) == 0) + imask[(info->nr_uarts-1)/2] &= ~2; +else + imask[(info->nr_uarts-1)/2] &= ~32; +dp-> ir.imr = imask[(info->nr_uarts-1)/2]; +} + +static int mfc_trans_empty(struct m68k_async_struct *info) +{ +struct duarthalf *dh; + +dh = (struct duarthalf *)info->port; +return (dh->sr_csr.sr & 8); +} + +int multiface_init(void) +{ +unsigned int key; +int line1, line2; +struct duart *dp; +int dummy; +const struct ConfigDev *cd; +struct serial_struct req; +struct m68k_async_struct *info; + +if (!MACH_IS_AMIGA) + return -ENODEV; + +nr_mfc = 0; +/* add MFC_II and serial master for test purposes */ +while((key=zorro_find(ZORRO_PROD_BSC_MULTIFACE_III,1, 0))) { + board_index[nr_mfc/2] = key; + cd = zorro_get_board(key); + dp = (struct duart *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+DUARTBASE)); + + req.line = -1; /* first free ttyS? device */ + req.type = SER_MFC_III; + req.port = (int)&dp->pa; + if ((line1 = m68k_register_serial( &req )) < 0) { + printk( "Cannot register MFC III serial port: no free device\n" ); + return -EBUSY; + } + lines[nr_mfc++] = line1; + info = &rs_table[line1]; + info->sw = &mfc_ser_switch; + info->nr_uarts = nr_mfc; + info->board_base = dp; + + req.line = -1; /* first free ttyS? device */ + req.type = SER_MFC_III; + req.port = (int)&dp->pb; + if ((line2 = m68k_register_serial( &req )) < 0) { + printk( "Cannot register MFC III serial port: no free device\n" ); + m68k_unregister_serial( line1 ); + return -EBUSY; + } + lines[nr_mfc++] = line2; + info = &rs_table[line2]; + info->sw = &mfc_ser_switch; + info->nr_uarts = nr_mfc--; + info->board_base = dp; + + if (nr_mfc < 4) { + request_irq(IRQ_AMIGA_EXTER, mfc_interrupt, 0, + "Multiface III serial", mfc_interrupt); + request_irq(IRQ_AMIGA_VERTB, mfc_vbl_inter, 0, + "Multiface III serial VBL", mfc_vbl_inter); + } + + dp->ir.imr = 0; /* turn off all interrupts */ + imask[nr_mfc/2] = 0; + dummy = dp->ir.isr; /* clear peding interrupts */ + dummy = dp->ipcr_acr.ipcr; + dp->stop_ropc.ropc = 255; /* all outputs off */ + dp->ipr_opcr.opcr = 0; /* change for serial-master */ + dp->pa.cr = CR_RX_OFF; /* disable receiver */ + dp->pb.cr = CR_RX_OFF; + dp->pa.cr = CR_TX_OFF; /* disable transmitter */ + dp->pb.cr = CR_TX_OFF; + dp->pa.cr = CR_RESET_RX; + dp->pb.cr = CR_RESET_RX; + dp->pa.cr = CR_RESET_TX; + dp->pb.cr = CR_RESET_TX; + dp->pa.cr = CR_RESET_ERR; + dp->pb.cr = CR_RESET_ERR; + dp->pa.cr = CR_RESET_BREAK; + dp->pb.cr = CR_RESET_BREAK; + dp->pa.cr = CR_STOP_BREAK; + dp->pb.cr = CR_STOP_BREAK; + dp->pa.cr = CR_RESET_MR; + dp->pb.cr = CR_RESET_MR; + /* set default 9600 8 N 1 */ + dp->pa.mr.mr1 = MR1_8BITS|MR1_PARITY_NO|MR1_RxRTS_ON; + dp->pb.mr.mr1 = MR1_8BITS|MR1_PARITY_NO|MR1_RxRTS_ON; + dp->pa.mr.mr2 = MR2_1STOP; + dp->pb.mr.mr2 = MR2_1STOP; + + dp->ipcr_acr.acr = 0xe0; /* BRG set 2, timer 1X crystal */ + acmask[nr_mfc/2] = 0xe0; + /* change the following baudrate stuff for MFC_II */ + dp->pa.sr_csr.csr = 0x99; /* 9600 from BRG */ + dp->pb.sr_csr.csr = 0xdd; /* from timer */ + dp->ctu = 0; + dp->ctl = 24; /* values for 9600 */ + dummy = dp->start_sopc.start; /* load timer with new values */ + nr_mfc++; + + zorro_config_board(key,1); +} +return 0; +} + +#ifdef MODULE +int init_module(void) +{ +return multiface_init(); +} + +void cleanup_module(void) +{ +int i; +struct duart *dp; + +for (i = 0; i < nr_mfc; i += 2) { + dp = rs_table[lines[i]].board_base; + dp->pa.cr = CR_RX_OFF | CR_TX_OFF; /* disable duart */ + dp->pb.cr = CR_RX_OFF | CR_TX_OFF; + dp->ir.imr = 0; /* turn off interrupts */ + m68k_unregister_serial(lines[i]); + m68k_unregister_serial(lines[i+1]); + zorro_unconfig_board(board_index[i/2], 1); +} +free_irq(IRQ_AMIGA_EXTER, mfc_interrupt); +free_irq(IRQ_AMIGA_VERTB, mfc_vbl_inter); +} +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/ser_whippet.c linux/drivers/char/ser_whippet.c --- v2.2.17/drivers/char/ser_whippet.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/ser_whippet.c Fri Oct 13 23:57:54 2000 @@ -0,0 +1,837 @@ +#define WHIPPET_VER "2.2.0pre7" +#define WHIPPET_REV 0 +#define WHIPPET_DATE "31/Jan/1999" + +/* + * ser_whippet.c - version info as above + * + * Copyright (C) 1997,98,99 Chris Sumner (chris@cpsumner.freeserve.co.uk) + * + * This is a driver for the Hisoft Whippet PCMCIA serial port for + * the Amiga. (16c550b UART) + * + * The code is mostly based on ser_ioext.c by Jes Sorensen, + * (jds@kom.auc.dk) but has been modified to cope with the different + * hardware footprint of the Whippet. + * + * Modified: + * + * 11/Feb/98 - General tidying up + * 31/Mar/98 - More tidying up + * 7/Apr/98 - Fixed nasty little bug concerning gayle ints + * 8/Apr/98 - Changed PCMCIA access timings to 100ns + * 31/Jul/98 - Changed email address + * 2/Nov/98 - Fixed to work with 2.1.124 + * 7/Nov/98 - Added support for ASYNC_SPD_SHI and _WARP + * 8/Nov/98 - Fixed a few small bugs + * 20/Nov/98 - Re-structured code a bit and tidied up + * 21/Nov/98 - Added support for modules + * 22/Nov/98 - Fixed inverted DCD bug + * 23/Nov/98 - Re-structured interrupt code and fixed a few bugs - (2.1.127) + * 31/Jan/99 - Changed email (again) and modified for 2.2.0pre7 + * + * To Do: + * + * - Test at 230k4 and 460k8 rates + * - Dynamic changing of fifo trigger level (via ioctl? via overrun count?) + * - Handling of card insertion and removal (more than just shout at user!) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef gayle +#undef gayle /* We use our own definition */ +#endif + +#include "ser_whippet.h" + +#define WHIPPET_DEBUG 0 /* debug level */ + +#define ser_DTRon(uart) (uart->MCR |= DTR) +#define ser_RTSon(uart) (uart->MCR |= RTS) +#define ser_DTRoff(uart) (uart->MCR &= ~DTR) +#define ser_RTSoff(uart) (uart->MCR &= ~RTS) + + +/***************************** Prototypes *****************************/ +static void ser_init(struct m68k_async_struct *info); +static void ser_deinit(struct m68k_async_struct *info, int leave_dtr); +static void ser_enab_tx_int(struct m68k_async_struct *info, int enab_flag); +static int ser_check_custom_divisor(struct m68k_async_struct *info, + int baud_base, int divisor); +static void ser_change_speed(struct m68k_async_struct *info); +static void ser_throttle(struct m68k_async_struct *info, int status); +static void ser_set_break(struct m68k_async_struct *info, int break_flag); +static void ser_get_serial_info(struct m68k_async_struct *info, + struct serial_struct *retinfo); +static unsigned int ser_get_modem_info(struct m68k_async_struct *info); +static int ser_set_modem_info(struct m68k_async_struct *info, int new_dtr, + int new_rts); +static int ser_ioctl(struct tty_struct *tty, struct file *file, + struct m68k_async_struct *info, unsigned int cmd, + unsigned long arg); +static void ser_stop_receive(struct m68k_async_struct *info); +static int ser_trans_empty(struct m68k_async_struct *info); +/************************* End of Prototypes **************************/ + +/* + * SERIALSWITCH structure for the Whippet serial interface. + */ + +static SERIALSWITCH whippet_ser_switch = { + ser_init, + ser_deinit, + ser_enab_tx_int, + ser_check_custom_divisor, + ser_change_speed, + ser_throttle, + ser_set_break, + ser_get_serial_info, + ser_get_modem_info, + ser_set_modem_info, + ser_ioctl, + ser_stop_receive, + ser_trans_empty, + NULL +}; + +static int whippet_baud_table[20] = { + /* B0 */ 0, + /* B50 */ 9216, + /* B75 */ 6144, + /* B110 */ 4189, /* 110.00238 */ + /* B134.5 */ 3426, /* 134.50087 */ + /* B150 */ 3072, + /* B200 */ 2304, + /* B300 */ 1536, + /* B600 */ 768, + /* B1200 */ 384, + /* B1800 */ 256, + /* B2400 */ 192, + /* B4800 */ 96, + /* B9600 */ 48, + /* B19200 */ 24, + /* B38400 */ 12, /* The last of the standard rates. */ + /* B57600 */ 8, /* ASYNC_SPD_HI */ + /* B115K2 */ 4, /* ASYNC_SPD_VHI */ + /* B230K4 */ 2, /* ASYNC_SPD_SHI */ + /* B460K8 */ 1 /* ASYNC_SPD_WARP */ +}; + + +static volatile struct GAYLE *gayle; /* gayle register struct */ +static volatile struct WHIPPET *whippet; /* whippet regs struct */ + +static int fifo_trig_level=FIFO_TRIG_4; /* can be changed */ + +/* + * There are 4 receiver FIFO-interrupt trigger levels (FIFO_TRIG_x), that + * indicates how many bytes are to be allowed in the receiver-FIFO before + * an interrupt is generated: + * x = 1 = 1 byte + * x = 4 = 4 bytes + * x = 8 = 8 bytes + * x = 14 = 14 bytes + * If you keep getting overruns try lowering this value one step at a time. + */ + +/***** start of ser_interrupt() - Handler for serial interrupt. *****/ + +static void ser_interrupt(int irq, void *data, struct pt_regs *regs) +{ +struct m68k_async_struct *info = data; +u_char iir,ier,lsr,gayleirq = gayle->intreq; + + if ((gayleirq & 0x7c)==0) return; /* quick exit */ + + if (gayleirq & 0x5c) { + gayle->intreq = ((gayleirq & 0x5c) ^ 0x5c) | (GAYLE_IRQ_IDE | GAYLE_IRQ_SC); + printk("gayle->intreq = 0x%02x; gayle->inten = 0x%02x\n",gayleirq, gayle->inten); + if (gayleirq & GAYLE_IRQ_CCDET) { + if (gayle->cardstatus & GAYLE_CS_CCDET) { + printk("Card inserted! Don't do that!\n"); + } else { + printk("Card removed! Don't do that!\n"); + } + } + } + + if ((gayleirq & GAYLE_IRQ_SC)==0) return; + +/* If we got here, then there is an interrupt waiting for us to service */ + + iir = whippet->IIR; + +/* Disable UART interrupts for now... */ + + ier = whippet->IER; whippet->IER = 0; + + while (!(iir & IRQ_PEND)) { /* loop until no more ints */ + + switch (iir & (IRQ_ID1 | IRQ_ID2 | IRQ_ID3)) { + case IRQ_RLS: /* Receiver Line Status */ + case IRQ_CTI: /* Character Timeout */ + case IRQ_RDA: /* Received Data Available */ + /* + * Copy chars to the tty-queue ... + * Be careful that we aren't passing one of the + * Receiver Line Status interrupt-conditions without noticing. + */ + { + int ch; + + lsr = whippet->LSR; + while (lsr & DR) { + u_char err; + ch = whippet->RBR; + + if (lsr & BI) err = TTY_BREAK; + else if (lsr & PE) err = TTY_PARITY; + else if (lsr & OE) err = TTY_OVERRUN; + else if (lsr & FE) err = TTY_FRAME; + else err = 0; + + rs_receive_char(info, ch, err); + lsr = whippet->LSR; + } + } + break; + + case IRQ_THRE: /* Transmitter holding register empty */ + { + int fifo_space = FIFO_SIZE; + + /* If the uart is ready to receive data and there are chars in */ + /* the queue we transfer all we can to the uart's FIFO */ + + if (rs_no_more_tx(info)) { +#if WHIPPET_DEBUG + printk("rs_no_more_tx()\n"); +#endif + /* Disable transmitter empty interrupt */ + ier &= ~(ETHREI); + + /* Read IIR to acknowledge the interrupt */ + (void)whippet->IIR; + break; + } + + /* Handle software flow control */ + if (info->x_char) { +#if WHIPPET_DEBUG + printk("Flow: X%s\n",(info->x_char == 19) ? "OFF" : "ON"); +#endif + whippet->THR = info->x_char; + info->icount.tx++; + info->x_char = 0; + fifo_space--; + } + + /* Fill the fifo */ + while (fifo_space > 0) { + fifo_space--; + whippet->THR = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail &= (SERIAL_XMIT_SIZE-1); + info->icount.tx++; + if (--info->xmit_cnt == 0) break; + } +#if WHIPPET_DEBUG + if (fifo_space == 0) printk("fifo full\n"); +#endif + /* Don't need THR interrupts any more */ + if (info->xmit_cnt == 0) { +#if WHIPPET_DEBUG + printk("TX ints OFF\n"); +#endif + ier &= ~(ETHREI); + } + + if (info->xmit_cnt < WAKEUP_CHARS) { +#if WHIPPET_DEBUG + printk("rs_sched_event()\n"); +#endif + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + } + } + break; + + case IRQ_MS: /* Must be modem status register interrupt? */ + { + u_char msr = whippet->MSR; + + if (info->flags & ASYNC_INITIALIZED) { + if (msr & DCTS) { +#if WHIPPET_DEBUG + printk("CTS = %s\n",(msr & CTS) ? "ON" : "OFF"); +#endif + rs_check_cts(info, (msr & CTS)); + } + if (msr & DDCD) + rs_dcd_changed(info, (msr & DCD)); + } + } + break; + + } /* switch (iir) */ + + iir = whippet->IIR; + } /* while IRQ_PEND */ + +/* Acknowledge gayle STATUS_CHANGE interrupt */ + + gayle->intreq = ((gayleirq & GAYLE_IRQ_SC) ^ GAYLE_IRQ_SC) | GAYLE_IRQ_IDE; + +/* Re-enable UART interrupts */ + + whippet->IER = ier; +} + +/***** end of ser_interrupt() *****/ + + +/***** start of ser_init() *****/ + +static void ser_init(struct m68k_async_struct *info) +{ +#if WHIPPET_DEBUG + printk("ser_init()\n"); +#endif + while ((whippet->LSR) & DR) + (void)whippet->RBR; /* read a byte */ + +/* Set DTR and RTS */ + whippet->MCR |= (DTR | RTS); + +/* Enable interrupts. IF_PORTS irq has already been enabled in whippet_init()*/ +/* DON'T enable ETHREI here because there is nothing to send yet (murray) */ + whippet->IER |= (ERDAI | ELSI | EMSI); + + MOD_INC_USE_COUNT; +} + +/***** end of ser_init() *****/ + + +/***** start of ser_deinit() *****/ + +static void ser_deinit(struct m68k_async_struct *info, int leave_dtr) +{ +#if WHIPPET_DEBUG + printk("ser_deinit()\n"); +#endif + /* Wait for the uart to get empty */ + while (!((whippet->LSR) & TEMT)) { + } + + while ((whippet->LSR) & DR) { + (void)whippet->RBR; + } + +/* No need to disable UART interrupts since this will already + * have been done via ser_enab_tx_int() and ser_stop_receive() + */ + + ser_RTSoff(whippet); + if (!leave_dtr) ser_DTRoff(whippet); + + MOD_DEC_USE_COUNT; +} + +/***** end of ser_deinit() *****/ + + +/***** start of ser_enab_tx_int() *****/ + +/* +** Enable or disable tx interrupts. +** Note that contrary to popular belief, it is not necessary to +** send a character to cause an interrupt to occur. Whenever the +** THR is empty and THRE interrupts are enabled, an interrupt will occur. +** (murray) +*/ +static void ser_enab_tx_int(struct m68k_async_struct *info, int enab_flag) +{ +#if WHIPPET_DEBUG + printk("ser_enab_tx_int(%s)\n",(enab_flag) ? "ON" : "OFF"); +#endif + if (enab_flag) whippet->IER |= ETHREI; + else whippet->IER &= ~(ETHREI); +} + +/***** end of ser_enab_tx_int() *****/ + + +static int ser_check_custom_divisor(struct m68k_async_struct *info, + int baud_base, int divisor) +{ +#if WHIPPET_DEBUG + printk("ser_check_custom_divisor()\n"); +#endif + /* Always return 0 or else setserial spd_hi/spd_vhi doesn't work */ + return 0; +} + + +/***** start of ser_change_speed() *****/ + +static void ser_change_speed(struct m68k_async_struct *info) +{ +u_int cflag, baud, chsize, stopb, parity, aflags; +u_int div = 0, ctrl = 0; + +#if WHIPPET_DEBUG + printk("ser_change_speed()\n"); +#endif + + if (!info->tty || !info->tty->termios) return; + + cflag = info->tty->termios->c_cflag; + baud = cflag & CBAUD; + chsize = cflag & CSIZE; + stopb = cflag & CSTOPB; + parity = cflag & (PARENB | PARODD); + aflags = info->flags & ASYNC_SPD_MASK; + + if (cflag & CRTSCTS) info->flags |= ASYNC_CTS_FLOW; + else info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; + else info->flags |= ASYNC_CHECK_CD; + + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + if (baud < 1 || baud > 2) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; + } + if (baud == 15) { + if (aflags == ASYNC_SPD_HI) /* 57k6 */ + baud += 1; + if (aflags == ASYNC_SPD_VHI) /* 115k2 */ + baud += 2; + if (aflags == ASYNC_SPD_SHI) /* 230k4 */ + baud += 3; + if (aflags == ASYNC_SPD_WARP) /* 460k8 */ + baud += 4; + if (aflags == ASYNC_SPD_CUST) + div = info->custom_divisor; + } + if (!div) { + /* Maximum speed is 460800 */ + if (baud > 19) baud = 19; + div = whippet_baud_table[baud]; + } + +#if WHIPPET_DEBUG + printk("divisor=%d, baud rate=%d\n",div,(div==0)? -1 : WHIPPET_BAUD_BASE/div); +#endif + + if (!div) { + /* speed == 0 -> drop DTR */ + ser_DTRoff(whippet); + return; + } + +/* + * We have to set DTR when a valid rate is chosen, otherwise DTR + * might get lost when programs use this sequence to clear the line: + * + * change_speed(baud = B0); + * sleep(1); + * change_speed(baud = Bx); x != 0 + * + * The pc-guys do this aswell. + */ + ser_DTRon(whippet); + + if (chsize == CS8) ctrl |= data_8bit; + else if (chsize == CS7) ctrl |= data_7bit; + else if (chsize == CS6) ctrl |= data_6bit; + else if (chsize == CS5) ctrl |= data_5bit; + +/* If stopb is true we set STB which means 2 stop-bits */ +/* otherwise we only get 1 stop-bit. */ + + ctrl |= (stopb ? STB : 0); + ctrl |= ((parity & PARENB) ? ((parity & PARODD) ? (PEN) : (PEN | + EPS)) : 0x00 ); + + whippet->LCR = (ctrl | DLAB); + + /* Store high byte of divisor */ + + whippet->DLM = ((div >> 8) & 0xff); + + /* Store low byte of divisor */ + + whippet->DLL = (div & 0xff); + whippet->LCR = ctrl; +} + +/***** end of ser_change_speed() *****/ + + +/***** start of ser_throttle() *****/ + +static void ser_throttle(struct m68k_async_struct *info, int status) +{ +#if WHIPPET_DEBUG + printk("ser_throttle(rts=%s)\n", (status) ? "OFF" : "ON"); +#endif + if (status) ser_RTSoff(whippet); + else ser_RTSon(whippet); +} + +/***** end of ser_throttle() *****/ + + +/***** start of ser_set_break() *****/ + +static void ser_set_break(struct m68k_async_struct *info, int break_flag) +{ +#if WHIPPET_DEBUG + printk("ser_set_break(%s)\n", (break_flag) ? "ON" : "OFF"); +#endif + if (break_flag) whippet->LCR |= SET_BREAK; + else whippet->LCR &= ~SET_BREAK; +} + +/***** end of ser_set_break() *****/ + + +/***** start of ser_get_serial_info() *****/ + +static void ser_get_serial_info(struct m68k_async_struct *info, + struct serial_struct *retinfo) +{ +#if WHIPPET_DEBUG + printk("ser_get_serial_info()\n"); +#endif + + retinfo->baud_base = WHIPPET_BAUD_BASE; + retinfo->xmit_fifo_size = FIFO_SIZE; /* This field is currently ignored, */ + /* by the upper layers of the */ + /* serial-driver. */ + retinfo->custom_divisor = info->custom_divisor; +} + +/***** end of ser_get_serial_info() *****/ + + +/***** start of ser_get_modem() *****/ + +static unsigned int ser_get_modem_info(struct m68k_async_struct *info) +{ +unsigned char msr, mcr; + +#if WHIPPET_DEBUG > 1 + printk("ser_get_modem()\n"); +#endif + + msr = whippet->MSR; + mcr = whippet->MCR; /* The DTR and RTS are located in the */ + /* ModemControlRegister ... */ + + return ( + ((mcr & DTR) ? TIOCM_DTR : 0) | + ((mcr & RTS) ? TIOCM_RTS : 0) | + + ((msr & DCD) ? TIOCM_CAR : 0) | + ((msr & CTS) ? TIOCM_CTS : 0) | + ((msr & DSR) ? TIOCM_DSR : 0) | + ((msr & RING_I) ? TIOCM_RNG : 0) + ); +} + +/***** end of ser_get_modem() *****/ + + +/***** start of ser_set_modem_info() *****/ + +static int ser_set_modem_info(struct m68k_async_struct *info, int new_dtr, + int new_rts) +{ +#if WHIPPET_DEBUG + printk("ser_set_modem(dtr=%s, rts=%s)\n",(new_dtr == 0) ? "OFF" : "ON",(new_rts == 0) ? "OFF" : "ON"); +#endif + + if (new_dtr == 0) ser_DTRoff(whippet); + else if (new_dtr == 1) ser_DTRon(whippet); + + if (new_rts == 0) ser_RTSoff(whippet); + else if (new_rts == 1) ser_RTSon(whippet); + + return 0; +}; + +/***** end of ser_set_modem_info() *****/ + + +/***** start of ser_stop_receive() *****/ + +static void ser_stop_receive (struct m68k_async_struct *info) +{ +#if WHIPPET_DEBUG + printk("ser_stop_receive()\n"); +#endif + /* Disable uart receive and status interrupts */ + whippet->IER &= ~(ERDAI | ELSI | EMSI); +} + +/***** end of ser_stop_receive() *****/ + + +/***** start of ser_trans_empty() *****/ + +static int ser_trans_empty (struct m68k_async_struct *info) +{ +#if WHIPPET_DEBUG + printk("ser_trans_empty()\n"); +#endif + return (whippet->LSR & THRE); +} + +/***** end of ser_trans_empty() *****/ + + +/***** start of ser_ioctl() *****/ +static int ser_ioctl(struct tty_struct *tty, struct file *file, + struct m68k_async_struct *info, unsigned int cmd, + unsigned long arg) +{ +/* switch(cmd) { + case: + }*/ + return -ENOIOCTLCMD; +} + +/***** end of ser_ioctl() *****/ + + +/***** start of ser_reset_port() *****/ + +void ser_reset_port(void) +{ +#if WHIPPET_DEBUG + printk("ser_reset_port()\n"); +#endif +/* + * Try and reset the serial port to a default state + */ + whippet->IER = 0x00; /* disable interrupts */ + (void)whippet->IIR; /* clear any pending misc interrupts */ + (void)whippet->LSR; /* clear any pending LSR interrupts */ + (void)whippet->MSR; /* clear any pending MSR interrupts */ + +/* + * Set the serial port to a default setting of 8N1 - 9600 + */ + whippet->LCR = (data_8bit | DLAB); + whippet->DLM = 0; + whippet->DLL = 48; + whippet->LCR = (data_8bit); + +/* + * Set the rx FIFO-trigger count. + */ + whippet->FCR = (RCVR_FIFO_RES | FIFO_ENA | + XMIT_FIFO_RES | fifo_trig_level ); + whippet->MCR = 0; +} + +/***** end of ser_reset_port() *****/ + + +/***** start of whippet_init() *****/ + +/* + * Detect and initialize any Whippet found in the system. + */ + +static int line; /* The line assigned to us by register_serial() */ + +static struct m68k_async_struct *amiga_info; /* our async struct */ + +int whippet_init(void) +{ +unsigned long flags; +struct serial_struct req; +struct m68k_async_struct *info; + +#if WHIPPET_DEBUG + printk("whippet_init()\n"); +#endif + if (!(MACH_IS_AMIGA)) + return -ENODEV; + + if ((amiga_model!=AMI_1200) && (amiga_model!=AMI_600)) + return -ENODEV; + + if (!(AMIGAHW_PRESENT(PCMCIA))) /* might be missing, you never know! */ + return -ENODEV; + +/* + * Initialise hardware structure pointers + */ + gayle = (struct GAYLE *)(zTwoBase + GAYLE_ADDRESS); + whippet = (struct WHIPPET *)(zTwoBase + WHIPPET_PHYSADDR); + +#if WHIPPET_DEBUG + printk("gayle->cardstatus = 0x%02x\n",gayle->cardstatus); + printk("gayle->intreq = 0x%02x\n",gayle->intreq); + printk("gayle->inten = 0x%02x\n",gayle->inten); + printk("gayle->config = 0x%02x\n",gayle->config); +#endif + printk("Probing for Whippet serial port... (v%s r%i - %s)\n",WHIPPET_VER, WHIPPET_REV, WHIPPET_DATE); + +/* + * Test gayle cardstatus bits for presence of a card + */ + if (!(gayle->cardstatus & GAYLE_CS_CCDET)) { + printk("No PCMCIA Card detected\n"); + return -ENODEV; +#if WHIPPET_DEBUG + } else { printk("PCMCIA Card detected\n"); +#endif + } + +/* + * Card detected, but is it a Whippet??? Let's try and find out... + */ + { + u_char ch1,ch2; + whippet->SCR = 0x42; + whippet->IER = 0x00; + ch1=whippet->SCR; /* should be 0x42 */ + whippet->SCR = 0x99; + whippet->IER = 0x00; + ch2=whippet->SCR; /* should be 0x99 */ + if ((ch1!=0x42) || (ch2!=0x99)) return -ENODEV; + } + + ser_reset_port(); /* initialise the serial port */ + +/* + * Set the necessary tty-stuff. + */ + req.line = -1; /* first free ttyS? device */ + req.type = SER_WHIPPET; + req.port = (int) &(whippet->RBR); + + if ((line = register_serial( &req )) < 0) { + printk( "Cannot register Whippet serial port: no free device\n" ); + return -EBUSY; + } + + info = &rs_table[line]; /* set info == struct *m68k_async_struct */ + + info->nr_uarts = 1; /* one UART */ + info->sw = &whippet_ser_switch; /* switch functions */ + info->icount.cts = info->icount.dsr = 0; + info->icount.rng = info->icount.dcd = 0; + info->icount.rx = info->icount.tx = 0; + info->icount.frame = info->icount.parity = 0; + info->icount.overrun = info->icount.brk = 0; + + amiga_info = info; /* initialise our static async struct */ + +/* + * Clear any spurious interrupts in gayle + */ + gayle->intreq = ((gayle->intreq & 0x6c) ^ 0x6c) | GAYLE_IRQ_IDE; + +/* + * Install ISR - level 2 - data is struct *m68k_async_struct + */ + request_irq(IRQ_AMIGA_PORTS, ser_interrupt, 0, "whippet serial", info); + + save_flags(flags); + cli(); + +#if WHIPPET_DEBUG + printk("gayle->cardstatus = 0x%02x\n",gayle->cardstatus); + printk("gayle->intreq = 0x%02x\n",gayle->intreq); + printk("gayle->inten = 0x%02x\n",gayle->inten); + printk("gayle->config = 0x%02x\n",gayle->config); +#endif + +/* + * Enable status_change interrupts in gayle + */ + + gayle->inten |= GAYLE_IRQ_SC; + gayle->cardstatus = GAYLE_CS_WR | GAYLE_CS_DA; + gayle->config = 0; + +#if WHIPPET_DEBUG + printk("gayle->cardstatus = 0x%02x\n",gayle->cardstatus); + printk("gayle->intreq = 0x%02x\n",gayle->intreq); + printk("gayle->inten = 0x%02x\n",gayle->inten); + printk("gayle->config = 0x%02x\n",gayle->config); +#endif + + restore_flags(flags); + +#if WHIPPET_DEBUG + printk("Detected Whippet Serial Port at 0x%08x (ttyS%i)\n",(int)whippet,line); +#endif + return 0; +} + +/***** end of whippet_init() *****/ + + +/***** Module functions *****/ + +#ifdef MODULE +int init_module(void) +{ + return whippet_init(); +} + +void cleanup_module(void) +{ +#if WHIPPET_DEBUG + printk("Closing Whippet Device!\n"); +#endif + unregister_serial(line); + +#if WHIPPET_DEBUG + printk("gayle->cardstatus = 0x%02x\n",gayle->cardstatus); + printk("gayle->intreq = 0x%02x\n",gayle->intreq); + printk("gayle->inten = 0x%02x\n",gayle->inten); + printk("gayle->config = 0x%02x\n",gayle->config); +#endif + ser_reset_port(); + + gayle->cardstatus = 0; + gayle->intreq = ((gayle->intreq & 0x6c) ^ 0x6c) | GAYLE_IRQ_IDE; + gayle->inten &= GAYLE_IRQ_IDE; + +#if WHIPPET_DEBUG + printk("gayle->cardstatus = 0x%02x\n",gayle->cardstatus); + printk("gayle->intreq = 0x%02x\n",gayle->intreq); + printk("gayle->inten = 0x%02x\n",gayle->inten); + printk("gayle->config = 0x%02x\n",gayle->config); +#endif + free_irq(IRQ_AMIGA_PORTS,amiga_info); +} +#endif + +/***** end of Module functions *****/ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/ser_whippet.h linux/drivers/char/ser_whippet.h --- v2.2.17/drivers/char/ser_whippet.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/ser_whippet.h Fri Oct 13 23:57:54 2000 @@ -0,0 +1,130 @@ +/* + * Defines for the Hisoft Whippet serial port for the Amiga 600/1200 + * range of computers. + * + * This code is (C) 1997,98 Chris Sumner (chris@cpsumner.freeserve.co.uk), + * based on 16c552.h and ser_ioext.h which are (C) 1995 Jes Sorensen. + * (jds@kom.auc.dk) + */ + +#ifndef _SER_WHIPPET_H_ +#define _SER_WHIPPET_H_ + +#define UART_CLK 7372800 +#define WHIPPET_BAUD_BASE (UART_CLK / 16) + +#define WHIPPET_PHYSADDR (0xA30600) /* from whippet.device */ + +struct WHIPPET { + u_char RBR; /* Reciever Buffer Register */ + u_char pad0[0xfff]; + u_char IER; /* Interrupt Enable Register */ + u_char pad1[0xfff]; + u_char IIR; /* Interrupt Identification Register */ + u_char pad2[0xfff]; + u_char LCR; /* Line Control Register */ + u_char pad3[0xfff]; + u_char MCR; /* Modem Control Register */ + u_char pad4[0xfff]; + u_char LSR; /* Line Status Register */ + u_char pad5[0xfff]; + u_char MSR; /* Modem Status Register */ + u_char pad6[0xfff]; + u_char SCR; /* Scratch Register */ +}; + +#define THR RBR /* Transmitter Holding Register */ +#define FCR IIR /* FIFO Control Register */ +#define DLL RBR /* Divisor Latch - LSB */ +#define DLM IER /* Divisor Latch - MSB */ + +/* + * Bit-defines for the various registers. + */ + +/* IER - Interrupt Enable Register */ + +#define ERDAI (1<<0) +#define ETHREI (1<<1) +#define ELSI (1<<2) +#define EMSI (1<<3) + +/* IIR - Interrupt Ident. Register */ + +#define IRQ_PEND (1<<0) /* NOTE: IRQ_PEND=0 implies irq pending */ +#define IRQ_ID1 (1<<1) +#define IRQ_ID2 (1<<2) +#define IRQ_ID3 (1<<3) +#define FIFO_ENA0 (1<<6) /* Both these are set when FCR(1<<0)=1 */ +#define FIFO_ENA1 (1<<7) + +#define IRQ_RLS (IRQ_ID1 | IRQ_ID2) +#define IRQ_RDA IRQ_ID2 +#define IRQ_CTI (IRQ_ID2 | IRQ_ID3) +#define IRQ_THRE IRQ_ID1 +#define IRQ_MS 0 + +/* FCR - FIFO Control Register */ + +#define FIFO_ENA (1<<0) +#define RCVR_FIFO_RES (1<<1) +#define XMIT_FIFO_RES (1<<2) +#define DMA_MODE_SEL (1<<3) +#define RCVR_TRIG_LSB (1<<6) +#define RCVR_TRIG_MSB (1<<7) + +#define FIFO_TRIG_1 0x00 +#define FIFO_TRIG_4 RCVR_TRIG_LSB +#define FIFO_TRIG_8 RCVR_TRIG_MSB +#define FIFO_TRIG_14 (RCVR_TRIG_LSB | RCVR_TRIG_MSB) + +#define FIFO_SIZE 16 + +/* LCR - Line Control Register */ + +#define WLS0 (1<<0) +#define WLS1 (1<<1) +#define STB (1<<2) +#define PEN (1<<3) +#define EPS (1<<4) +#define STICK_PARITY (1<<5) +#define SET_BREAK (1<<6) +#define DLAB (1<<7) + +#define data_5bit 0x00 +#define data_6bit 0x01 +#define data_7bit 0x02 +#define data_8bit 0x03 + + +/* MCR - Modem Control Register */ + +#define DTR (1<<0) +#define RTS (1<<1) +#define OUT1 (1<<2) +#define OUT2 (1<<3) +#define LOOP (1<<4) + +/* LSR - Line Status Register */ + +#define DR (1<<0) +#define OE (1<<1) +#define PE (1<<2) +#define FE (1<<3) +#define BI (1<<4) +#define THRE (1<<5) +#define TEMT (1<<6) +#define RCVR_FIFO_ERR (1<<7) + +/* MSR - Modem Status Register */ + +#define DCTS (1<<0) +#define DDSR (1<<1) +#define TERI (1<<2) +#define DDCD (1<<3) +#define CTS (1<<4) +#define DSR (1<<5) +#define RING_I (1<<6) +#define DCD (1<<7) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/serial167.c linux/drivers/char/serial167.c --- v2.2.17/drivers/char/serial167.c Fri Apr 21 12:46:06 2000 +++ linux/drivers/char/serial167.c Sat Oct 14 00:02:24 2000 @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include @@ -2788,6 +2788,57 @@ base_addr[CyIER] = ier; restore_flags(flags); +} + +/* This is a hack; if there are multiple chars waiting in the chip we + * discard all but the last one, and return that. The cd2401 is not really + * designed to be driven in polled mode. + */ + +int serial167_wait_key(struct console *co) +{ + volatile unsigned char *base_addr = (u_char *)BASE_ADDR; + unsigned long flags; + volatile u_char sink; + u_char ier; + int port; + int keypress = 0; + + save_flags(flags); cli(); + + /* Ensure receiver is enabled! */ + + port = 0; + base_addr[CyCAR] = (u_char)port; + while (base_addr[CyCCR]) + ; + base_addr[CyCCR] = CyENB_RCVR; + ier = base_addr[CyIER]; + base_addr[CyIER] = CyRxData; + + while (!keypress) { + if (pcc2chip[PccSCCRICR] & 0x20) + { + /* We have an Rx int. Acknowledge it */ + sink = pcc2chip[PccRPIACKR]; + if ((base_addr[CyLICR] >> 2) == port) { + int cnt = base_addr[CyRFOC]; + while (cnt-- > 0) + { + keypress = base_addr[CyRDR]; + } + base_addr[CyREOIR] = 0; + } + else + base_addr[CyREOIR] = CyNOTRANS; + } + } + + base_addr[CyIER] = ier; + + restore_flags(flags); + + return keypress; } #ifdef CONFIG_REMOTE_DEBUG diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/sx.c linux/drivers/char/sx.c --- v2.2.17/drivers/char/sx.c Sat Sep 9 18:42:36 2000 +++ linux/drivers/char/sx.c Sat Oct 14 00:42:50 2000 @@ -2523,6 +2523,7 @@ else pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint); + board->hw_base = tint & PCI_BASE_ADDRESS_MEM_MASK; board->base2 = board->base = (ulong) ioremap(board->hw_base, WINDOW_LEN (board)); if (!board->base) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/synclink.c linux/drivers/char/synclink.c --- v2.2.17/drivers/char/synclink.c Sat Sep 9 18:42:36 2000 +++ linux/drivers/char/synclink.c Fri Sep 1 22:02:52 2000 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * ==FILEDATE 20000705== + * ==FILEDATE 20000821== * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -102,14 +102,6 @@ #include #include -#if LINUX_VERSION_CODE < VERSION(2,3,0) -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL} -#define init_waitqueue_head(head) *(head) = NULL -#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX -#define set_current_state(a) current->state = (a) -#endif - #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE #define CONFIG_SYNCLINK_SYNCPPP 1 #endif @@ -124,7 +116,6 @@ #define netif_queue_stopped(a) ((a)->tbusy) #else #include "../net/wan/syncppp.h" -#define netif_queue_stopped(a) test_bit(LINK_STATE_XOFF,&(a)->state) #endif #endif @@ -401,8 +392,9 @@ /* * The size of the serial xmit buffer is 1 page, or 4096 bytes */ +#ifndef SERIAL_XMIT_SIZE #define SERIAL_XMIT_SIZE 4096 - +#endif /* * These macros define the offsets used in calculating the @@ -965,7 +957,7 @@ #endif static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "1.19"; +static char *driver_version = "1.22"; static struct tty_driver serial_driver, callout_driver; static int serial_refcount; @@ -4528,6 +4520,12 @@ if (!serial_table || !serial_termios || !serial_termios_locked){ printk("%s(%d):Can't allocate tty/termios arrays.\n", __FILE__,__LINE__); + if (serial_table) + kfree(serial_table); + if (serial_termios) + kfree(serial_termios); + if (serial_termios_locked) + kfree(serial_termios_locked); return -ENOMEM; } @@ -7396,12 +7394,7 @@ void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, unsigned short count ) { - /*******************************************************/ - /* A load interval of 16 allows for 4 32-bit writes at */ - /* 60ns each for a maximum latency of 240ns on the */ - /* local bus. */ - /*******************************************************/ - + /* 16 32-bit writes @ 60ns each = 960ns max latency on local bus */ #define PCI_LOAD_INTERVAL 64 unsigned short Intervalcount = count / PCI_LOAD_INTERVAL; @@ -7411,7 +7404,7 @@ for ( Index = 0 ; Index < Intervalcount ; Index++ ) { memcpy(TargetPtr, SourcePtr, PCI_LOAD_INTERVAL); - Dummy = *((unsigned long *)TargetPtr); + Dummy = *((volatile unsigned long *)TargetPtr); TargetPtr += PCI_LOAD_INTERVAL; SourcePtr += PCI_LOAD_INTERVAL; } @@ -7582,7 +7575,7 @@ sppp_attach(&info->pppdev); d = info->netdev; - d->name = info->netname; + strcpy(d->name, info->netname); d->base_addr = info->io_base; d->irq = info->irq_level; d->dma = info->dma_level; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.2.17/drivers/char/tty_io.c Sat Sep 9 18:42:37 2000 +++ linux/drivers/char/tty_io.c Wed Nov 8 23:03:17 2000 @@ -129,6 +129,9 @@ extern long console_8xx_init(long, long); extern int rs_8xx_init(void); #endif /* CONFIG_8xx */ +#ifdef CONFIG_MAC_SERIAL +extern long mac_scc_console_init(long, long); +#endif #ifdef CONFIG_3215 extern long con3215_init(long, long); #endif /* CONFIG_3215 */ @@ -2097,6 +2100,8 @@ #ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_8xx kmem_start = console_8xx_init(kmem_start, kmem_end); +#elif defined(CONFIG_MAC_SERIAL) + kmem_start = mac_scc_console_init(kmem_start, kmem_end); #else kmem_start = serial_console_init(kmem_start, kmem_end); #endif /* CONFIG_8xx */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/wd501p.h linux/drivers/char/wd501p.h --- v2.2.17/drivers/char/wd501p.h Fri Apr 21 23:14:54 2000 +++ linux/drivers/char/wd501p.h Mon Sep 11 18:02:33 2000 @@ -25,11 +25,21 @@ #define WDT_COUNT1 (io+1) #define WDT_COUNT2 (io+2) #define WDT_CR (io+3) -#define WDT_SR (io+4) -#define WDT_RT (io+5) -#define WDT_UNUSED (io+6) +#define WDT_SR (io+4) /* Buzzer start PCI */ +#define WDT_RT (io+5) /* Buzzer stop PCI */ +#define WDT_BUZZER (io+6) /* PCI only */ #define WDT_DC (io+7) +/* The following are only on the PCI card, they're outside of I/O space on + * the ISA card: */ +#define WDT_CLOCK (io+12) /* COUNT2: rd=16.67MHz, wr=2.0833MHz */ +/* inverted opto isolated reset output: */ +#define WDT_OPTONOTRST (io+13) /* wr=enable, rd=disable */ +/* opto isolated reset output: */ +#define WDT_OPTORST (io+14) /* wr=enable, rd=disable */ +/* programmable outputs: */ +#define WDT_PROGOUT (io+15) /* wr=enable, rd=disable */ + #define WDC_SR_WCCR 1 /* Active low */ #define WDC_SR_TGOOD 2 #define WDC_SR_ISOI0 4 @@ -39,6 +49,8 @@ #define WDC_SR_PSUUNDR 64 /* Active low */ #define WDC_SR_IRQ 128 /* Active low */ +#ifndef WDT_IS_PCI + /* * Feature Map 1 is the active high inputs not supported on your card. * Feature Map 2 is the active low inputs not supported on your card. @@ -62,6 +74,13 @@ #endif #ifdef CONFIG_WDT_500 /* Minimal board */ +#define FEATUREMAP1 (WDC_SR_TGOOD|WDC_SR_FANGOOD) +#define FEATUREMAP2 (WDC_SR_PSUOVER|WDC_SR_PSUUNDR) +#define WDT_OPTION_MASK (WDIOF_OVERHEAT) +#endif + +#else + #define FEATUREMAP1 (WDC_SR_TGOOD|WDC_SR_FANGOOD) #define FEATUREMAP2 (WDC_SR_PSUOVER|WDC_SR_PSUUNDR) #define WDT_OPTION_MASK (WDIOF_OVERHEAT) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/char/wdt_pci.c linux/drivers/char/wdt_pci.c --- v2.2.17/drivers/char/wdt_pci.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/wdt_pci.c Mon Sep 25 16:04:57 2000 @@ -0,0 +1,562 @@ +/* + * Industrial Computer Source WDT500/501 driver for Linux 2.1.x + * + * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * Release 0.08. + * + * Fixes + * Dave Gregorich : Modularisation and minor bugs + * Alan Cox : Added the watchdog ioctl() stuff + * Alan Cox : Fixed the reboot problem (as noted by + * Matt Crocker). + * Alan Cox : Added wdt= boot option + * Alan Cox : Cleaned up copy/user stuff + * Tim Hockin : Added insmod parameters, comment cleanup + * Parameterized timeout + * JP Nollmann : Added support for PCI wdt501p + * Alan Cox : Split ISA and PCI cards into two drivers + * Jeff Garzik : PCI cleanups + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define WDT_IS_PCI +#include "wd501p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PFX "wdt_pci: " + +/* + * Until Access I/O gets their application for a PCI vendor ID approved, + * I don't think that it's appropriate to move these constants into the + * regular pci_ids.h file. -- JPN 2000/01/18 + */ + +#ifndef PCI_VENDOR_ID_ACCESSIO +#define PCI_VENDOR_ID_ACCESSIO 0x494f +#endif +#ifndef PCI_DEVICE_ID_WDG_CSM +#define PCI_DEVICE_ID_WDG_CSM 0x22c0 +#endif + +static int wdt_is_open=0; + +/* + * You must set these - there is no sane way to probe for this board. + * You can use wdt=x,y to set these now. + */ + +static int io=0x240; +static int irq=11; + +#define WD_TIMO (100*60) /* 1 minute */ + +/* + * Programming support + */ + +static void wdtpci_ctr_mode(int ctr, int mode) +{ + ctr<<=6; + ctr|=0x30; + ctr|=(mode<<1); + outb_p(ctr, WDT_CR); +} + +static void wdtpci_ctr_load(int ctr, int val) +{ + outb_p(val&0xFF, WDT_COUNT0+ctr); + outb_p(val>>8, WDT_COUNT0+ctr); +} + +/* + * Kernel methods. + */ + + +/** + * wdtpci_status: + * + * Extract the status information from a WDT watchdog device. There are + * several board variants so we have to know which bits are valid. Some + * bits default to one and some to zero in order to be maximally painful. + * + * we then map the bits onto the status ioctl flags. + */ + +static int wdtpci_status(void) +{ + /* + * Status register to bit flags + */ + + int flag=0; + unsigned char status=inb_p(WDT_SR); + status|=FEATUREMAP1; + status&=~FEATUREMAP2; + + if(!(status&WDC_SR_TGOOD)) + flag|=WDIOF_OVERHEAT; + if(!(status&WDC_SR_PSUOVER)) + flag|=WDIOF_POWEROVER; + if(!(status&WDC_SR_PSUUNDR)) + flag|=WDIOF_POWERUNDER; + if(!(status&WDC_SR_FANGOOD)) + flag|=WDIOF_FANFAULT; + if(status&WDC_SR_ISOI0) + flag|=WDIOF_EXTERN1; + if(status&WDC_SR_ISII1) + flag|=WDIOF_EXTERN2; + return flag; +} + +/** + * wdtpci_interrupt: + * @irq: Interrupt number + * @dev_id: Unused as we don't allow multiple devices. + * @regs: Unused. + * + * Handle an interrupt from the board. These are raised when the status + * map changes in what the board considers an interesting way. That means + * a failure condition occuring. + */ + +static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Read the status register see what is up and + * then printk it. + */ + + unsigned char status=inb_p(WDT_SR); + + status|=FEATUREMAP1; + status&=~FEATUREMAP2; + + printk(KERN_CRIT "WDT status %d\n", status); + + if(!(status&WDC_SR_TGOOD)) + printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); + if(!(status&WDC_SR_PSUOVER)) + printk(KERN_CRIT "PSU over voltage.\n"); + if(!(status&WDC_SR_PSUUNDR)) + printk(KERN_CRIT "PSU under voltage.\n"); + if(!(status&WDC_SR_FANGOOD)) + printk(KERN_CRIT "Possible fan fault.\n"); + if(!(status&WDC_SR_WCCR)) +#ifdef SOFTWARE_REBOOT +#ifdef ONLY_TESTING + printk(KERN_CRIT "Would Reboot.\n"); +#else + printk(KERN_CRIT "Initiating system reboot.\n"); + machine_restart(NULL); +#endif +#else + printk(KERN_CRIT "Reset in 5ms.\n"); +#endif +} + + +static long long wdtpci_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +/** + * wdtpci_ping: + * + * Reload counter one with the watchdog timeout. We don't bother reloading + * the cascade counter. + */ + +static void wdtpci_ping(void) +{ + /* Write a watchdog value */ + inb_p(WDT_DC); + wdtpci_ctr_mode(1,2); + wdtpci_ctr_load(1,WD_TIMO); /* Timeout */ + outb_p(0, WDT_DC); +} + +/** + * wdtpci_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if(count) + { + wdtpci_ping(); + return 1; + } + return 0; +} + +/** + * wdtpci_read: + * @file: file handle to the watchdog board + * @buf: buffer to write 1 byte into + * @count: length of buffer + * @ptr: offset (no seek allowed) + * + * Read reports the temperature in degrees Fahrenheit. The API is in + * farenheit. It was designed by an imperial measurement luddite. + */ + +static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + unsigned short c=inb_p(WDT_RT); + unsigned char cp; + + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + return -ESPIPE; + + switch(MINOR(file->f_dentry->d_inode->i_rdev)) + { + case TEMP_MINOR: + c*=11; + c/=15; + cp=c+7; + if(copy_to_user(buf,&cp,1)) + return -EFAULT; + return 1; + default: + return -EINVAL; + } +} + +/** + * wdtpci_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. We only actually usefully support + * querying capabilities and current status. + */ + +static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER + |WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT, + 1, + "WDT500/501PCI" + }; + + ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */ + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + + case WDIOC_GETSTATUS: + return put_user(wdtpci_status(),(int *)arg); + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); + case WDIOC_KEEPALIVE: + wdtpci_ping(); + return 0; + } +} + +/** + * wdtpci_open: + * @inode: inode of device + * @file: file handle to device + * + * One of our two misc devices has been opened. The watchdog device is + * single open and on opening we load the counters. Counter zero is a + * 100Hz cascade, into counter 1 which downcounts to reboot. When the + * counter triggers counter 2 downcounts the length of the reset pulse + * which set set to be as long as possible. + */ + +static int wdtpci_open(struct inode *inode, struct file *file) +{ + switch(MINOR(inode->i_rdev)) + { + case WATCHDOG_MINOR: + if(wdt_is_open) + return -EBUSY; +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + /* + * Activate + */ + + wdt_is_open=1; + + inb_p(WDT_DC); /* Disable */ + + /* + * "pet" the watchdog, as Access says. + * This resets the clock outputs. + */ + + wdtpci_ctr_mode(2,0); + outb_p(0, WDT_DC); + + inb_p(WDT_DC); + + outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */ + inb_p(WDT_BUZZER); /* disable */ + inb_p(WDT_OPTONOTRST); /* disable */ + inb_p(WDT_OPTORST); /* disable */ + inb_p(WDT_PROGOUT); /* disable */ + wdtpci_ctr_mode(0,3); + wdtpci_ctr_mode(1,2); + wdtpci_ctr_mode(2,1); + wdtpci_ctr_load(0,20833); /* count at 100Hz */ + wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */ + /* DO NOT LOAD CTR2 on PCI card! -- JPN */ + outb_p(0, WDT_DC); /* Enable */ + return 0; + case TEMP_MINOR: + return 0; + default: + return -ENODEV; + } +} + +/** + * wdtpci_close: + * @inode: inode to board + * @file: file handle to board + * + * The watchdog has a configurable API. There is a religious dispute + * between people who want their watchdog to be able to shut down and + * those who want to be sure if the watchdog manager dies the machine + * reboots. In the former case we disable the counters, in the latter + * case you have to open it again very soon. + */ + +static int wdtpci_release(struct inode *inode, struct file *file) +{ + if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) + { + lock_kernel(); +#ifndef CONFIG_WATCHDOG_NOWAYOUT + inb_p(WDT_DC); /* Disable counters */ + wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ +#endif + wdt_is_open=0; + unlock_kernel(); + } + return 0; +} + +/** + * notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + * Our notifier is called on system shutdowns. We want to turn the card + * off at reboot otherwise the machine will reboot again during memory + * test or worse yet during the following fsck. This would suck, in fact + * trust me - if it happens it does suck. + */ + +static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + { + /* Turn the card off */ + inb_p(WDT_DC); + wdtpci_ctr_load(2,0); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + + +static struct file_operations wdtpci_fops = { + llseek: wdtpci_llseek, + read: wdtpci_read, + write: wdtpci_write, + ioctl: wdtpci_ioctl, + open: wdtpci_open, + release: wdtpci_release, +}; + +static struct miscdevice wdtpci_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &wdtpci_fops +}; + +#ifdef CONFIG_WDT_501 +static struct miscdevice temp_miscdev= +{ + TEMP_MINOR, + "temperature", + &wdtpci_fops +}; +#endif + +/* + * The WDT card needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdtpci_notifier= +{ + wdtpci_notify_sys, + NULL, + 0 +}; + + +static int __init wdtpci_init_one (struct pci_dev *dev) +{ + static int dev_count = 0; + + dev_count++; + if (dev_count > 1) { + printk (KERN_ERR PFX + "this driver only supports 1 device\n"); + return -ENODEV; + } + + irq = dev->irq; + io = dev->base_address[2]&PCI_BASE_ADDRESS_IO_MASK; + + printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " + "(Interrupt %d)\n", io, irq); + + request_region (io, 16, "wdt-pci"); + if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ, + "wdt-pci", &wdtpci_miscdev)) { + printk (KERN_ERR PFX "IRQ %d is not free.\n", irq); + goto err_out_free_res; + } + + misc_register (&wdtpci_miscdev); + +#ifdef CONFIG_WDT_501 + misc_register (&temp_miscdev); +#endif + + register_reboot_notifier (&wdtpci_notifier); + + return 0; + +err_out_free_res: + release_region (io, 16); + return -EIO; +} + + +static void __exit wdtpci_remove_one (struct pci_dev *pdev) +{ + /* here we assume only one device will ever have + * been picked up and registered by probe function */ + unregister_reboot_notifier(&wdtpci_notifier); +#ifdef CONFIG_WDT_501_PCI + misc_deregister(&temp_miscdev); +#endif + misc_deregister(&wdtpci_miscdev); + free_irq(irq, &wdtpci_miscdev); + release_region(io, 16); +} + +/** + * wdtpci_cleanup: + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 60 seconds or reboot. + */ + +static struct pci_dev *wdt_dev; + +static void __exit wdtpci_cleanup(void) +{ + if(wdt_dev) + wdtpci_remove_one(wdt_dev); + wdt_dev = NULL; +} + + +/** + * wdtpci_init: + * + * Set up the WDT watchdog board. All we have to do is grab the + * resources we require and bitch if anyone beat us to them. + * The open() function will actually kick the board off. + */ + +static int __init wdtpci_init(void) +{ + wdt_dev=pci_find_device(PCI_VENDOR_ID_ACCESSIO, PCI_DEVICE_ID_WDG_CSM, NULL); + if (wdt_dev ==NULL) + return -ENODEV; + if(wdtpci_init_one(wdt_dev)<0) + { + wdt_dev=NULL; + return -ENODEV; + } + return 0; +} + + +module_init(wdtpci_init); +module_exit(wdtpci_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c --- v2.2.17/drivers/isdn/act2000/module.c Fri Apr 21 12:46:07 2000 +++ linux/drivers/isdn/act2000/module.c Sun Oct 15 21:51:57 2000 @@ -279,9 +279,7 @@ act2000_receive(card); save_flags(flags); cli(); - del_timer(&card->ptimer); - card->ptimer.expires = jiffies + 3; - add_timer(&card->ptimer); + mod_timer(&card->ptimer, jiffies+3); restore_flags(flags); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/avmb1/avmcard.h linux/drivers/isdn/avmb1/avmcard.h --- v2.2.17/drivers/isdn/avmb1/avmcard.h Fri Apr 21 12:46:07 2000 +++ linux/drivers/isdn/avmb1/avmcard.h Sat Sep 30 18:28:27 2000 @@ -347,13 +347,13 @@ static inline void b1_reset(unsigned int base) { b1outp(base, B1_RESET, 0); - udelay(55 * 2 * 1000); /* 2 TIC's */ + mdelay(55 * 2); /* 2 TIC's */ b1outp(base, B1_RESET, 1); - udelay(55 * 2 * 1000); /* 2 TIC's */ + mdelay(55 * 2); /* 2 TIC's */ b1outp(base, B1_RESET, 0); - udelay(55 * 2 * 1000); /* 2 TIC's */ + mdelay(55 * 2); /* 2 TIC's */ } static inline unsigned char b1_disable_irq(unsigned int base) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.2.17/drivers/isdn/avmb1/b1dma.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Sat Sep 30 18:12:55 2000 @@ -230,14 +230,14 @@ restore_flags(flags); b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); - udelay(10 * 1000); + mdelay(10); b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ - udelay(10 * 1000); + mdelay(10); b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); if (card->cardtype == avm_t1pci) - udelay(42 * 1000); + mdelay(42); else - udelay(10 * 1000); + mdelay(10); } /* ------------------------------------------------------------- */ @@ -245,11 +245,11 @@ int b1dma_detect(avmcard *card) { b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); - udelay(10 * 1000); + mdelay(10); b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */ - udelay(10 * 1000); + mdelay(10); b1dmaoutmeml(card->mbase+AMCC_MCSR, 0); - udelay(42 * 1000); + mdelay(42); b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0); b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.2.17/drivers/isdn/avmb1/c4.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/isdn/avmb1/c4.c Sat Sep 30 18:13:09 2000 @@ -373,7 +373,7 @@ return 8; if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9; - udelay(1000); + mdelay(1); if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10; if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11; @@ -385,7 +385,7 @@ if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16; if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17; - udelay(1000); + mdelay(1); if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF)) return 18; @@ -863,7 +863,7 @@ c4outmeml(card->mbase+MBOX_UP_LEN, 0); c4outmeml(card->mbase+MBOX_DOWN_LEN, 0); c4outmeml(card->mbase+DOORBELL, DBELL_INIT); - udelay(1000); + mdelay(1); c4outmeml(card->mbase+DOORBELL, DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.2.17/drivers/isdn/avmb1/t1isa.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/isdn/avmb1/t1isa.c Sat Sep 30 18:13:46 2000 @@ -135,7 +135,7 @@ cli(); /* board reset */ t1outp(base, T1_RESETBOARD, 0xf); - udelay(100 * 1000); + mdelay(100); dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */ /* write config */ @@ -147,18 +147,18 @@ t1outp(base, ((base >> 4)) & 0x3, cregs[7]); restore_flags(flags); - udelay(100 * 1000); + mdelay(100); t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); - udelay(10 * 1000); + mdelay(10); t1outp(base, T1_FASTLINK+T1_RESETLINK, 1); t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1); - udelay(100 * 1000); + mdelay(100); t1outp(base, T1_FASTLINK+T1_RESETLINK, 0); t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0); - udelay(10 * 1000); + mdelay(10); t1outp(base, T1_FASTLINK+T1_ANALYSE, 0); - udelay(5 * 1000); + mdelay(5); t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0); if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/divert/divert_init.c linux/drivers/isdn/divert/divert_init.c --- v2.2.17/drivers/isdn/divert/divert_init.c Fri Apr 21 12:46:08 2000 +++ linux/drivers/isdn/divert/divert_init.c Sat Nov 18 17:58:10 2000 @@ -1,5 +1,5 @@ /* - * $Id: divert_init.c,v 1.4 1999/08/22 20:26:32 calle Exp $ + * $Id: divert_init.c,v 1.5 2000/11/13 22:51:47 kai Exp $ * * Module init for DSS1 diversion services for i4l. * @@ -18,22 +18,6 @@ * 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. - * - * $Log: divert_init.c,v $ - * Revision 1.4 1999/08/22 20:26:32 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.3 1999/07/05 20:21:39 werner - * changes to use diversion sources for all kernel versions. - * removed static device, only proc filesystem used - * - * Revision 1.2 1999/07/04 21:37:30 werner - * Ported from kernel version 2.0 - * - * * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c --- v2.2.17/drivers/isdn/divert/divert_procfs.c Fri Apr 21 12:46:08 2000 +++ linux/drivers/isdn/divert/divert_procfs.c Sat Nov 18 17:58:10 2000 @@ -1,5 +1,5 @@ /* - * $Id: divert_procfs.c,v 1.6 2000/02/14 19:23:03 werner Exp $ + * $Id: divert_procfs.c,v 1.10 2000/11/13 22:51:47 kai Exp $ * * Filesystem handling for the diversion supplementary services. * @@ -18,27 +18,6 @@ * 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. - * - * $Log: divert_procfs.c,v $ - * Revision 1.6 2000/02/14 19:23:03 werner - * - * Changed handling of proc filesystem tables to a more portable version - * - * Revision 1.5 1999/09/14 20:31:01 werner - * - * Removed obsoleted functions for proc fs and synced with new ones. - * - * Revision 1.4 1999/08/06 07:42:48 calle - * Added COMPAT_HAS_NEW_WAITQ for rd_queue for newer kernels. - * - * Revision 1.3 1999/07/05 20:21:41 werner - * changes to use diversion sources for all kernel versions. - * removed static device, only proc filesystem used - * - * Revision 1.2 1999/07/04 21:37:31 werner - * Ported from kernel version 2.0 - * - * * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.2.17/drivers/isdn/hisax/config.c Fri Apr 21 12:46:09 2000 +++ linux/drivers/isdn/hisax/config.c Sat Nov 18 18:15:21 2000 @@ -619,7 +619,7 @@ } i++; } - if (strlen(str)) { + if (str && *str) { strcpy(HiSaxID, str); HiSax_id = HiSaxID; } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.2.17/drivers/isdn/hisax/hfc_pci.c Fri Apr 21 12:46:10 2000 +++ linux/drivers/isdn/hisax/hfc_pci.c Mon Sep 11 17:06:28 2000 @@ -1761,6 +1761,7 @@ printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); return (0); } +#ifdef notdef if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) { printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n"); pcibios_write_config_word(cs->hw.hfcpci.pci_bus, @@ -1794,6 +1795,7 @@ } dev_hfcpci->base_address[1] = (int) cs->hw.hfcpci.pci_io; } +#endif if (!cs->hw.hfcpci.pci_io) { printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); return (0); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.2.17/drivers/isdn/icn/icn.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/icn/icn.c Sat Nov 18 00:56:47 2000 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.62 1999/09/06 07:29:35 fritz Exp $ +/* $Id: icn.c,v 1.65 2000/11/13 22:51:48 kai Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -18,220 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: icn.c,v $ - * Revision 1.62 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.61 1999/09/03 14:06:58 fritz - * Fixed a memory leak. - * - * Revision 1.60 1999/08/31 11:20:32 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.59 1999/08/28 22:10:55 keil - * __setup function should be static - * - * Revision 1.58 1999/08/25 16:44:17 keil - * Support for new __setup function - * - * Revision 1.57 1999/07/06 16:15:30 detabc - * remove unused messages - * - * Revision 1.56 1999/04/12 13:15:07 fritz - * Fixed a cast. - * - * Revision 1.55 1999/04/12 12:34:02 fritz - * Changes from 2.0 tree. - * - * Revision 1.54 1999/01/05 18:29:39 he - * merged remaining schedule_timeout() changes from 2.1.127 - * - * Revision 1.53 1998/06/17 19:51:28 he - * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) - * brute force fix to avoid Ugh's in isdn_tty_write() - * cleaned up some dead code - * - * Revision 1.52 1998/05/20 19:29:58 tsbogend - * fixed bug introduced by changes for new BSENT callback - * - * Revision 1.51 1998/03/07 22:29:55 fritz - * Adapted Detlef's chenges for 2.1. - * - * Revision 1.49 1998/02/13 11:14:15 keil - * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb() - * - * Revision 1.48 1997/10/10 15:56:14 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * - * Revision 1.47 1997/10/01 09:21:51 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.46 1997/08/21 22:38:33 fritz - * Fixed a typo. - * - * Revision 1.45 1997/06/21 10:42:06 fritz - * Added availability to select leased mode on only one channel. - * - * Revision 1.44 1997/03/30 16:51:26 calle - * changed calls to copy_from_user/copy_to_user and removed verify_area - * were possible. - * - * Revision 1.43 1997/03/21 18:27:04 fritz - * Corrected parsing of incoming setup. - * - * Revision 1.42 1997/03/05 21:13:18 fritz - * Bugfix: sndcount was not reset on hangup. - * - * Revision 1.41 1997/02/24 23:34:29 fritz - * Bugfix in Layer1 error-recovery. - * - * Revision 1.40 1997/02/23 23:34:45 fritz - * Minor bugfixes in debugging code. - * - * Revision 1.39 1997/02/23 16:21:56 fritz - * Bugfix: Check for NULL pointer in icn_parse_status(). - * - * Revision 1.38 1997/02/11 18:29:31 fritz - * Bugfix in D64S initialization. - * - * Revision 1.37 1997/02/10 22:43:20 fritz - * Added plan and screen elements on ISDN_STAT_ICALL - * - * Revision 1.36 1997/02/10 21:31:20 fritz - * Changed setup-interface (incoming and outgoing). - * - * Revision 1.35 1997/02/10 10:10:28 fritz - * Changes for Kernel 2.1.X compatibility. - * Enhanced initialization, can recover from - * misconfiguration by other autoprobing drivers. - * - * Revision 1.34 1997/01/29 22:34:44 fritz - * Cleanup, Corrected D64S setup of 2nd channel. - * - * Revision 1.33 1996/12/05 20:31:48 tsbogend - * added handling of L2: DATA LINK LOST messages - * - * Revision 1.32 1996/11/14 23:49:18 fritz - * Bugfix: copy_to_user/copy_from_user mismatch in debugging-ioctl. - * - * Revision 1.31 1996/11/13 02:36:25 fritz - * Fixed a race condition in writecmd. - * Some optimizations and cleanup. - * - * Revision 1.30 1996/10/22 23:14:09 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.29 1996/08/29 20:34:54 fritz - * Bugfix in send queue management: - * sndcount was not updated correctly. - * Minor Bugfixes. - * - * Revision 1.28 1996/06/28 17:02:53 fritz - * replaced memcpy_fromfs_toio. - * - * Revision 1.27 1996/06/25 18:38:59 fritz - * Fixed function name in error message. - * - * Revision 1.26 1996/06/24 17:20:35 fritz - * Bugfixes in pollbchan_send(): - * - Using lock field of skbuff breaks networking. - * - Added channel locking - * - changed dequeuing scheme. - * Eliminated misc. compiler warnings. - * - * Revision 1.25 1996/06/11 22:53:35 tsbogend - * fixed problem with large array on stack - * made the driver working on Linux/alpha - * - * Revision 1.24 1996/06/06 13:58:33 fritz - * Changed code to be architecture independent - * - * Revision 1.23 1996/06/03 19:59:00 fritz - * Fixed typos. - * - * Revision 1.22 1996/05/17 15:46:41 fritz - * Removed own queue management. - * Changed queue management to use sk_buffs. - * - * Revision 1.21 1996/05/02 04:01:20 fritz - * Bugfix: - * - icn_addcard() evaluated wrong driverId. - * - * Revision 1.20 1996/05/02 00:40:27 fritz - * Major rewrite to support more than one card - * with a single module. - * Support for new firmware. - * - * Revision 1.19 1996/04/21 17:43:32 fritz - * Changes for Support of new Firmware BRV3.02 - * - * Revision 1.18 1996/04/20 16:50:26 fritz - * Fixed status-buffer overrun. - * Misc. typos - * - * Revision 1.17 1996/02/11 02:39:04 fritz - * Increased Buffer for status-messages. - * Removed conditionals for HDLC-firmware. - * - * Revision 1.16 1996/01/22 05:01:55 fritz - * Revert to GPL. - * - * Revision 1.15 1996/01/10 20:57:39 fritz - * Bugfix: Loading firmware twice caused the device stop working. - * - * Revision 1.14 1995/12/18 18:23:37 fritz - * Support for ICN-2B Cards. - * Change for supporting user-settable service-octet. - * - * Revision 1.13 1995/10/29 21:41:07 fritz - * Added support for DriverId's, added Jan's patches for Kernel versions. - * - * Revision 1.12 1995/04/29 13:07:35 fritz - * Added support for new Euro-ISDN-firmware - * - * Revision 1.11 1995/04/23 13:40:45 fritz - * Added support for SPV's. - * Changed Dial-Command to support MSN's on DSS1-Lines. - * - * Revision 1.10 1995/03/25 23:23:24 fritz - * Changed configurable Ports, to allow settings for DIP-Switch Cardversions. - * - * Revision 1.9 1995/03/25 23:17:30 fritz - * Fixed race-condition in pollbchan_send - * - * Revision 1.8 1995/03/15 12:49:44 fritz - * Added support for SPV's - * Split pollbchan_work for calling send-routine directly - * - * Revision 1.7 1995/02/20 03:48:03 fritz - * Added support of new request_region-function. - * Minor bugfixes. - * - * Revision 1.6 1995/01/31 15:48:45 fritz - * Added Cause-Messages to be signaled to upper layers. - * Added Revision-Info on load. - * - * Revision 1.5 1995/01/29 23:34:59 fritz - * Added stopdriver() and appropriate calls. - * Changed printk-statements to support loglevels. - * - * Revision 1.4 1995/01/09 07:40:46 fritz - * Added GPL-Notice - * - * Revision 1.3 1995/01/04 05:15:18 fritz - * Added undocumented "bootload-finished"-command in download-code - * to satisfy some brain-damaged icn card-versions. - * - * Revision 1.2 1995/01/02 02:14:45 fritz - * Misc Bugfixes - * - * Revision 1.1 1994/12/14 17:56:06 fritz - * Initial revision - * */ #include "icn.h" @@ -247,7 +33,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.62 $"; +*revision = "$Revision: 1.65 $"; static int icn_addcard(int, char *, char *); @@ -602,9 +388,7 @@ /* schedule b-channel polling again */ save_flags(flags); cli(); - del_timer(&card->rb_timer); - card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; - add_timer(&card->rb_timer); + mod_timer(&card->rb_timer, jiffies+ICN_TIMER_BCREAD); card->flags |= ICN_FLAGS_RBTIMER; restore_flags(flags); } else @@ -905,9 +689,7 @@ /* schedule again */ save_flags(flags); cli(); - del_timer(&card->st_timer); - card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; - add_timer(&card->st_timer); + mod_timer(&card->st_timer, jiffies+ICN_TIMER_DCREAD); restore_flags(flags); } @@ -1869,7 +1651,7 @@ portbase = ints[1]; if (ints[0] > 1) membase = ints[2]; - if (strlen(str)) { + if (str && *str) { strcpy(sid, str); icn_id = sid; if ((p = strchr(sid, ','))) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.2.17/drivers/isdn/icn/icn.h Wed May 3 22:34:01 2000 +++ linux/drivers/isdn/icn/icn.h Sat Dec 9 21:35:59 2000 @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.29 1999/09/06 07:29:35 fritz Exp $ +/* $Id: icn.h,v 1.30 2000/11/13 22:51:48 kai Exp $ * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -17,110 +17,6 @@ * 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. - * - * $Log: icn.h,v $ - * Revision 1.29 1999/09/06 07:29:35 fritz - * Changed my mail-address. - * - * Revision 1.28 1997/10/10 15:56:18 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * - * Revision 1.27 1997/10/01 09:21:56 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.26 1997/02/14 12:23:16 fritz - * Added support for new insmod parameter handling. - * - * Revision 1.25 1997/02/10 10:10:31 fritz - * Changes for Kernel 2.1.X compatibility. - * Enhanced initialization, can recover from - * misconfiguration by other autoprobing drivers. - * - * Revision 1.24 1997/01/29 22:34:46 fritz - * Cleanup, Corrected D64S setup of 2nd channel. - * - * Revision 1.23 1996/12/17 18:47:55 tsbogend - * changed timeouts from absolute numbers to HZ based values - * - * Revision 1.22 1996/11/13 02:37:33 fritz - * Added delay include. - * - * Revision 1.21 1996/08/29 20:35:57 fritz - * Speed up B-Channel polling interval. - * - * Revision 1.20 1996/06/24 17:20:37 fritz - * Bugfixes in pollbchan_send(): - * - Using lock field of skbuff breaks networking. - * - Added channel locking - * - changed dequeuing scheme. - * Eliminated misc. compiler warnings. - * - * Revision 1.19 1996/06/06 13:58:35 fritz - * Changed code to be architecture independent - * - * Revision 1.18 1996/06/03 19:59:30 fritz - * Removed include of config.h - * - * Revision 1.17 1996/05/18 00:47:04 fritz - * Removed callback debug code. - * - * Revision 1.16 1996/05/17 15:46:43 fritz - * Removed own queue management. - * Changed queue management to use sk_buffs. - * - * Revision 1.15 1996/05/02 04:01:57 fritz - * Removed ICN_MAXCARDS - * - * Revision 1.14 1996/05/02 00:40:29 fritz - * Major rewrite to support more than one card - * with a single module. - * Support for new firmware. - * - * Revision 1.13 1996/04/20 16:51:41 fritz - * Increased status buffer. - * Misc. typos - * - * Revision 1.12 1996/01/22 05:01:22 fritz - * Revert to GPL. - * - * Revision 1.11 1995/12/18 18:25:00 fritz - * Support for ICN-2B Cards. - * Change for supporting user-settable service-octet. - * - * Revision 1.10 1995/10/29 21:43:10 fritz - * Added support for leased lines. - * - * Revision 1.9 1995/04/23 13:42:10 fritz - * Added some constants for distinguishing 1TR6 and DSS1 - * - * Revision 1.8 1995/03/25 23:18:55 fritz - * Changed ICN_PORTLEN to reflect correct number of ports. - * - * Revision 1.7 1995/03/15 12:52:06 fritz - * Some cleanup - * - * Revision 1.6 1995/02/20 03:49:22 fritz - * Fixed ICN_MAX_SQUEUE to correctly reflect outstanding bytes, not number - * of buffers. - * - * Revision 1.5 1995/01/29 23:36:50 fritz - * Minor cleanup. - * - * Revision 1.4 1995/01/09 07:41:20 fritz - * Added GPL-Notice - * - * Revision 1.3 1995/01/04 05:14:20 fritz - * removed include of linux/asm/string.h for compiling with Linux 1.1.76 - * - * Revision 1.2 1995/01/02 02:15:57 fritz - * Misc. Bugfixes - * - * Revision 1.1 1994/12/14 18:02:38 fritz - * Initial revision * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_audio.c linux/drivers/isdn/isdn_audio.c --- v2.2.17/drivers/isdn/isdn_audio.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_audio.c Sun Oct 15 21:51:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_audio.c,v 1.17 1999/08/17 11:10:52 paul Exp $ +/* $Id: isdn_audio.c,v 1.21 2000/06/20 18:01:55 keil Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * @@ -20,73 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_audio.c,v $ - * Revision 1.17 1999/08/17 11:10:52 paul - * don't try to use x86 assembler on non-x86! - * - * Revision 1.16 1999/08/06 12:47:35 calle - * Using __GNUC__ == 2 && __GNUC_MINOR__ < 95 how to define - * ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT - * - * Revision 1.15 1999/08/06 12:02:52 calle - * egcs 2.95 complain about invalid asm statement: - * "fixed or forbidden register 2 (cx) was spilled for class CREG." - * Using ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT and not - * define it at the moment. - * - * Revision 1.14 1999/07/11 17:14:06 armin - * Added new layer 2 and 3 protocols for Fax and DSP functions. - * Moved "Add CPN to RING message" to new register S23, - * "Display message" is now correct on register S13 bit 7. - * New audio command AT+VDD implemented (deactivate DTMF decoder and - * activate possible existing hardware/DSP decoder). - * Moved some tty defines to .h file. - * Made whitespace possible in AT command line. - * Some AT-emulator output bugfixes. - * First Fax G3 implementations. - * - * Revision 1.13 1999/04/12 12:33:09 fritz - * Changes from 2.0 tree. - * - * Revision 1.12 1998/07/26 18:48:43 armin - * Added silence detection in voice receive mode. - * - * Revision 1.11 1998/04/10 10:35:10 paul - * fixed (silly?) warnings from egcs on Alpha. - * - * Revision 1.10 1998/02/20 17:09:40 fritz - * Changes for recent kernels. - * - * Revision 1.9 1997/10/01 09:20:25 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.8 1997/03/02 14:29:16 fritz - * More ttyI related cleanup. - * - * Revision 1.7 1997/02/03 22:44:11 fritz - * Reformatted according CodingStyle - * - * Revision 1.6 1996/06/06 14:43:31 fritz - * Changed to support DTMF decoding on audio playback also. - * - * Revision 1.5 1996/06/05 02:24:08 fritz - * Added DTMF decoder for audio mode. - * - * Revision 1.4 1996/05/17 03:48:01 fritz - * Removed some test statements. - * Added revision string. - * - * Revision 1.3 1996/05/10 08:48:11 fritz - * Corrected adpcm bugs. - * - * Revision 1.2 1996/04/30 09:31:17 fritz - * General rewrite. - * - * Revision 1.1.1.1 1996/04/28 12:25:40 fritz - * Taken under CVS control - * */ #define __NO_VERSION__ @@ -95,7 +28,7 @@ #include "isdn_audio.h" #include "isdn_common.h" -char *isdn_audio_revision = "$Revision: 1.17 $"; +char *isdn_audio_revision = "$Revision: 1.21 $"; /* * Misc. lookup-tables. @@ -250,9 +183,9 @@ }; #define NCOEFF 16 /* number of frequencies to be analyzed */ -#define DTMF_TRESH 50000 /* above this is dtmf */ -#define SILENCE_TRESH 100 /* below this is silence */ -#define H2_TRESH 10000 /* 2nd harmonic */ +#define DTMF_TRESH 25000 /* above this is dtmf */ +#define SILENCE_TRESH 200 /* below this is silence */ +#define H2_TRESH 20000 /* 2nd harmonic */ #define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */ #define LOGRP 0 #define HIGRP 1 @@ -292,38 +225,25 @@ {'*', '0', '#', 'D'} }; - -/* - * egcs 2.95 complain about invalid asm statement: - * "fixed or forbidden register 2 (cx) was spilled for class CREG." - */ -#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__) -#if __GNUC__ == 2 && __GNUC_MINOR__ < 95 -#define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT -#endif -#endif - -#ifdef ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT static inline void -isdn_audio_tlookup(const void *table, void *buff, unsigned long n) +isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n) { - __asm__("cld\n" +#ifdef __i386__ + unsigned long d0, d1, d2, d3; + __asm__ __volatile__( + "cld\n" "1:\tlodsb\n\t" "xlatb\n\t" "stosb\n\t" "loop 1b\n\t" - : : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff) - : "bx", "cx", "di", "si", "ax"); -} - + : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3) + : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) + : "memory", "ax"); #else -static inline void -isdn_audio_tlookup(const char *table, char *buff, unsigned long n) -{ while (n--) *buff++ = table[*(unsigned char *)buff]; -} #endif +} void isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_audio.h linux/drivers/isdn/isdn_audio.h --- v2.2.17/drivers/isdn/isdn_audio.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_audio.h Sat Sep 23 13:15:35 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_audio.h,v 1.8 1999/07/11 17:14:07 armin Exp $ +/* $Id: isdn_audio.h,v 1.9 2000/05/11 22:29:20 kai Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * @@ -17,39 +17,6 @@ * 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. - * - * $Log: isdn_audio.h,v $ - * Revision 1.8 1999/07/11 17:14:07 armin - * Added new layer 2 and 3 protocols for Fax and DSP functions. - * Moved "Add CPN to RING message" to new register S23, - * "Display message" is now correct on register S13 bit 7. - * New audio command AT+VDD implemented (deactivate DTMF decoder and - * activate possible existing hardware/DSP decoder). - * Moved some tty defines to .h file. - * Made whitespace possible in AT command line. - * Some AT-emulator output bugfixes. - * First Fax G3 implementations. - * - * Revision 1.7 1999/04/12 12:33:11 fritz - * Changes from 2.0 tree. - * - * Revision 1.6 1998/07/26 18:48:44 armin - * Added silence detection in voice receive mode. - * - * Revision 1.5 1997/02/03 22:45:21 fritz - * Reformatted according CodingStyle - * - * Revision 1.4 1996/06/06 14:43:32 fritz - * Changed to support DTMF decoding on audio playback also. - * - * Revision 1.3 1996/06/05 02:24:09 fritz - * Added DTMF decoder for audio mode. - * - * Revision 1.2 1996/05/10 08:48:32 fritz - * Corrected adpcm bugs. - * - * Revision 1.1 1996/04/30 09:29:06 fritz - * Taken under CVS control. * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v2.2.17/drivers/isdn/isdn_cards.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/isdn/isdn_cards.c Sat Nov 18 17:58:58 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_cards.c,v 1.10 1999/07/20 06:41:28 calle Exp $ +/* $Id: isdn_cards.c,v 1.13 2000/10/28 23:03:38 kai Exp $ * Linux ISDN subsystem, initialization for non-modularized drivers. * @@ -18,38 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_cards.c,v $ - * Revision 1.10 1999/07/20 06:41:28 calle - * Bugfix: After the redesign of the AVM B1 driver, the driver didn't even - * compile, if not selected as modules. - * - * Revision 1.9 1999/04/12 12:33:11 fritz - * Changes from 2.0 tree. - * - * Revision 1.8 1999/03/29 11:13:23 armin - * Added eicon driver init. - * - * Revision 1.7 1998/02/20 17:24:28 fritz - * Added ACT2000 init. - * - * Revision 1.6 1997/04/23 18:56:03 fritz - * Old Teles driver removed, Changed doc and scripts accordingly. - * - * Revision 1.5 1997/03/30 17:10:36 calle - * added support for AVM-B1-PCI card. - * - * Revision 1.4 1997/03/04 21:59:44 calle - * Added AVM-B1-CAPI2.0 driver - * - * Revision 1.3 1997/02/03 23:31:14 fritz - * Reformatted according CodingStyle - * - * Revision 1.2 1996/10/13 19:52:17 keil - * HiSax support - * - * Revision 1.1 1996/04/20 16:04:36 fritz - * Initial revision - * */ #include @@ -75,7 +43,9 @@ extern void capi_init(void); extern void capidrv_init(void); #endif +#if CONFIG_ISDN_DRV_ACT2000 extern void act2000_init(void); +#endif void isdn_cards_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_cards.h linux/drivers/isdn/isdn_cards.h --- v2.2.17/drivers/isdn/isdn_cards.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_cards.h Sat Sep 23 13:15:35 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_cards.h,v 1.3 1999/04/12 12:33:13 fritz Exp $ +/* $Id: isdn_cards.h,v 1.4 2000/05/11 22:29:20 kai Exp $ * Linux ISDN subsystem, initialization for non-modularized drivers. * @@ -17,16 +17,6 @@ * 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. - * - * $Log: isdn_cards.h,v $ - * Revision 1.3 1999/04/12 12:33:13 fritz - * Changes from 2.0 tree. - * - * Revision 1.2 1997/02/03 23:31:55 fritz - * Reformatted according CodingStyle - * - * Revision 1.1 1996/04/20 16:04:03 fritz - * Initial revision * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.2.17/drivers/isdn/isdn_common.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/isdn/isdn_common.c Sat Nov 18 17:59:26 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.100 2000/03/03 16:37:11 kai Exp $ +/* $Id: isdn_common.c,v 1.113 2000/11/01 17:54:00 detabc Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -20,412 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_common.c,v $ - * Revision 1.100 2000/03/03 16:37:11 kai - * incorporated some cosmetic changes from the official kernel tree back - * into CVS - * - * Revision 1.99 2000/02/26 01:00:52 keil - * changes from 2.3.47 - * - * Revision 1.98 2000/02/16 14:56:27 paul - * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers - * - * Revision 1.97 2000/01/23 18:45:37 keil - * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) - * - * Revision 1.96 2000/01/20 19:55:33 keil - * Add FAX Class 1 support - * - * Revision 1.95 2000/01/09 20:43:13 detabc - * exand logical bind-group's for both call's (in and out). - * add first part of kernel-config-help for abc-extension. - * - * Revision 1.94 1999/11/20 22:14:13 detabc - * added channel dial-skip in case of external use - * (isdn phone or another isdn device) on the same NTBA. - * usefull with two or more card's connected the different NTBA's. - * global switchable in kernel-config and also per netinterface. - * - * add auto disable of netinterface's in case of: - * to many connection's in short time. - * config mistakes (wrong encapsulation, B2-protokoll or so on) on local - * or remote side. - * wrong password's or something else to a ISP (syncppp). - * - * possible encapsulations for this future are: - * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP, - * and ISDN_NET_ENCAP_CISCOHDLCK. - * - * Revision 1.93 1999/11/04 13:11:36 keil - * Reinit of v110 structs - * - * Revision 1.92 1999/10/31 15:59:50 he - * more skb headroom checks - * - * Revision 1.91 1999/10/28 22:48:45 armin - * Bugfix: isdn_free_channel() now frees the channel, - * even when the usage of the ttyI has changed. - * - * Revision 1.90 1999/10/27 21:21:17 detabc - * Added support for building logically-bind-group's per interface. - * usefull for outgoing call's with more then one isdn-card. - * - * Switchable support to dont reset the hangup-timeout for - * receive frames. Most part's of the timru-rules for receiving frames - * are now obsolete. If the input- or forwarding-firewall deny - * the frame, the line will be not hold open. - * - * Revision 1.89 1999/10/16 14:46:47 keil - * replace kmalloc with vmalloc for the big dev struct - * - * Revision 1.88 1999/10/02 00:39:26 he - * Fixed a 2.3.x wait queue initialization (was causing panics) - * - * Revision 1.87 1999/09/12 16:19:39 detabc - * added abc features - * low cost routing for net-interfaces (only the HL side). - * need more implementation in the isdnlog-utility - * udp info support (first part). - * different EAZ on outgoing call's. - * more checks on D-Channel callbacks (double use of channels). - * tested and running with kernel 2.3.17 - * - * Revision 1.86 1999/07/31 12:59:42 armin - * Added tty fax capabilities. - * - * Revision 1.85 1999/07/29 16:58:35 armin - * Bugfix: DLE handling in isdn_readbchan() - * - * Revision 1.84 1999/07/25 16:21:10 keil - * fix number matching - * - * Revision 1.83 1999/07/13 21:02:05 werner - * Added limit possibilty of driver b_channel resources (ISDN_STAT_DISCH) - * - * Revision 1.82 1999/07/12 21:06:50 werner - * Fixed problem when loading more than one driver temporary - * - * Revision 1.81 1999/07/11 17:14:09 armin - * Added new layer 2 and 3 protocols for Fax and DSP functions. - * Moved "Add CPN to RING message" to new register S23, - * "Display message" is now correct on register S13 bit 7. - * New audio command AT+VDD implemented (deactivate DTMF decoder and - * activate possible existing hardware/DSP decoder). - * Moved some tty defines to .h file. - * Made whitespace possible in AT command line. - * Some AT-emulator output bugfixes. - * First Fax G3 implementations. - * - * Revision 1.80 1999/07/07 10:14:00 detabc - * remove unused messages - * - * Revision 1.79 1999/07/05 23:51:30 werner - * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl - * hisaxctrl id 10 - * - * Revision 1.78 1999/07/05 20:21:15 werner - * changes to use diversion sources for all kernel versions. - * removed static device, only proc filesystem used - * - * Revision 1.77 1999/07/01 08:29:50 keil - * compatibility to 2.3 kernel - * - * Revision 1.76 1999/06/29 16:16:44 calle - * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again. - * Also right unlocking (ISDN_CMD_UNLOCK) is done now. - * isdnlog should check returncode of read(2) calls. - * - * Revision 1.75 1999/04/18 14:06:47 fritz - * Removed TIMRU stuff. - * - * Revision 1.74 1999/04/12 13:16:45 fritz - * Changes from 2.0 tree. - * - * Revision 1.73 1999/04/12 12:33:15 fritz - * Changes from 2.0 tree. - * - * Revision 1.72 1999/03/02 12:04:44 armin - * -added ISDN_STAT_ADDCH to increase supported channels after - * register_isdn(). - * -ttyI now goes on-hook on ATZ when B-Ch is connected. - * -added timer-function for register S7 (Wait for Carrier). - * -analog modem (ISDN_PROTO_L2_MODEM) implementations. - * -on L2_MODEM a string will be appended to the CONNECT-Message, - * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. - * -variable "dialing" used for ATA also, for interrupting call - * establishment and register S7. - * - * Revision 1.71 1999/01/28 09:10:43 armin - * Fixed bad while-loop in isdn_readbch(). - * - * Revision 1.70 1999/01/15 19:58:54 he - * removed compatibiltity macro - * - * Revision 1.69 1998/09/07 21:59:58 he - * flush method for 2.1.118 and above - * updated IIOCTLNETGPN - * - * Revision 1.68 1998/08/31 21:09:45 he - * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' - * peer phone number) - * - * Revision 1.67 1998/06/26 15:12:21 fritz - * Added handling of STAT_ICALL with incomplete CPN. - * Added AT&L for ttyI emulator. - * Added more locking stuff in tty_write. - * - * Revision 1.66 1998/06/17 19:50:41 he - * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) - * brute force fix to avoid Ugh's in isdn_tty_write() - * cleaned up some dead code - * - * - * Revision 1.62 1998/04/14 16:28:43 he - * Fixed user space access with interrupts off and remaining - * copy_{to,from}_user() -> -EFAULT return codes - * - * Revision 1.61 1998/03/22 18:50:46 hipp - * Added BSD Compression for syncPPP .. UNTESTED at the moment - * - * Revision 1.60 1998/03/19 13:18:18 keil - * Start of a CAPI like interface for supplementary Service - * first service: SUSPEND - * - * Revision 1.59 1998/03/09 17:46:23 he - * merged in 2.1.89 changes - * - * Revision 1.58 1998/03/07 22:35:24 fritz - * Starting generic module support (Nothing usable yet). - * - * Revision 1.57 1998/03/07 18:21:01 cal - * Dynamic Timeout-Rule-Handling vs. 971110 included - * - * Revision 1.56 1998/02/25 17:49:38 he - * Changed return codes caused be failing copy_{to,from}_user to -EFAULT - * - * Revision 1.55 1998/02/23 23:35:32 fritz - * Eliminated some compiler warnings. - * - * Revision 1.54 1998/02/22 19:44:19 fritz - * Bugfixes and improvements regarding V.110, V.110 now running. - * - * Revision 1.53 1998/02/20 17:18:05 fritz - * Changes for recent kernels. - * Added common stub for sending commands to lowlevel. - * Added V.110. - * - * Revision 1.52 1998/01/31 22:05:57 keil - * Lots of changes for X.25 support: - * Added generic support for connection-controlling encapsulation protocols - * Added support of BHUP status message - * Added support for additional p_encap X25IFACE - * Added support for kernels >= 2.1.72 - * - * Revision 1.51 1998/01/31 19:17:29 calle - * merged changes from and for 2.1.82 - * - * Revision 1.50 1997/12/12 06:12:11 calle - * moved EXPORT_SYMBOL(register_isdn) from isdn_syms.c to isdn_common.c - * - * Revision 1.49 1997/11/06 17:16:52 keil - * Sync to 2.1.62 changes - * - * Revision 1.48 1997/11/02 23:55:50 keil - * Andi Kleen's changes for 2.1.60 - * without it the isdninfo and isdnctrl devices won't work - * - * Revision 1.47 1997/10/09 21:28:46 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * New L1 error status (not yet in use). - * Cleaned up obsolete structures. - * Implemented Cisco-SLARP. - * Changed local net-interface data to be dynamically allocated. - * Removed old 2.0 compatibility stuff. - * - * Revision 1.46 1997/10/01 09:20:27 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.45 1997/08/21 23:11:41 fritz - * Added changes for kernels >= 2.1.45 - * - * Revision 1.44 1997/05/27 15:17:23 fritz - * Added changes for recent 2.1.x kernels: - * changed return type of isdn_close - * queue_task_* -> queue_task - * clear/set_bit -> test_and_... where apropriate. - * changed type of hard_header_cache parameter. - * - * Revision 1.43 1997/03/31 14:09:43 fritz - * Fixed memory leak in isdn_close(). - * - * Revision 1.42 1997/03/30 16:51:08 calle - * changed calls to copy_from_user/copy_to_user and removed verify_area - * were possible. - * - * Revision 1.41 1997/03/24 22:54:41 fritz - * Some small fixes in debug code. - * - * Revision 1.40 1997/03/08 08:13:51 fritz - * Bugfix: IIOCSETMAP (Set mapping) was broken. - * - * Revision 1.39 1997/03/07 01:32:54 fritz - * Added proper ifdef's for CONFIG_ISDN_AUDIO - * - * Revision 1.38 1997/03/05 21:15:02 fritz - * Fix: reduced stack usage of isdn_ioctl() and isdn_set_allcfg() - * - * Revision 1.37 1997/03/02 14:29:18 fritz - * More ttyI related cleanup. - * - * Revision 1.36 1997/02/28 02:32:40 fritz - * Cleanup: Moved some tty related stuff from isdn_common.c - * to isdn_tty.c - * Bugfix: Bisync protocol did not behave like documented. - * - * Revision 1.35 1997/02/21 13:01:19 fritz - * Changes CAUSE message output in kernel log. - * - * Revision 1.34 1997/02/10 20:12:43 fritz - * Changed interface for reporting incoming calls. - * - * Revision 1.33 1997/02/10 10:05:42 fritz - * More changes for Kernel 2.1.X - * Symbol information moved to isdn_syms.c - * - * Revision 1.32 1997/02/03 22:55:26 fritz - * Reformatted according CodingStyle. - * Changed isdn_writebuf_stub static. - * Slow down tty-RING counter. - * skb->free stuff replaced by macro. - * Bugfix in audio-skb locking. - * Bugfix in HL-driver locking. - * - * Revision 1.31 1997/01/17 01:19:18 fritz - * Applied chargeint patch. - * - * Revision 1.30 1997/01/14 01:27:47 fritz - * Changed audio receive not to rely on skb->users and skb->lock. - * Added ATI2 and related variables. - * Started adding full-duplex audio capability. - * - * Revision 1.29 1997/01/12 23:33:03 fritz - * Made isdn_all_eaz foolproof. - * - * Revision 1.28 1996/11/13 02:33:19 fritz - * Fixed a race condition. - * - * Revision 1.27 1996/10/27 22:02:41 keil - * return codes for ISDN_STAT_ICALL - * - * Revision 1.26 1996/10/23 11:59:40 fritz - * More compatibility changes. - * - * Revision 1.25 1996/10/22 23:13:54 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.24 1996/10/11 14:02:03 fritz - * Bugfix: call to isdn_ppp_timer_timeout() never compiled, because of - * typo in #ifdef. - * - * Revision 1.23 1996/06/25 18:35:38 fritz - * Fixed bogus memory access in isdn_set_allcfg(). - * - * Revision 1.22 1996/06/24 17:37:37 fritz - * Bugfix: isdn_timer_ctrl() did restart timer, even if it - * was already running. - * lowlevel driver locking did use wrong parameters. - * - * Revision 1.21 1996/06/15 14:58:20 fritz - * Added version signatures for data structures used - * by userlevel programs. - * - * Revision 1.20 1996/06/12 16:01:49 fritz - * Bugfix: Remote B-channel hangup sometimes did not result - * in a NO CARRIER on tty. - * - * Revision 1.19 1996/06/11 14:52:04 hipp - * minor bugfix in isdn_writebuf_skb_stub() - * - * Revision 1.18 1996/06/06 14:51:51 fritz - * Changed to support DTMF decoding on audio playback also. - * - * Revision 1.17 1996/06/05 02:24:10 fritz - * Added DTMF decoder for audio mode. - * - * Revision 1.16 1996/06/03 20:09:05 fritz - * Bugfix: called wrong function pointer for locking in - * isdn_get_free_channel(). - * - * Revision 1.15 1996/05/31 01:10:54 fritz - * Bugfixes: - * Lowlevel modules did not get locked correctly. - * Did show wrong revision when initializing. - * Minor fixes in ioctl code. - * sk_buff did not get freed, if error in writebuf_stub. - * - * Revision 1.14 1996/05/18 01:36:55 fritz - * Added spelling corrections and some minor changes - * to stay in sync with kernel. - * - * Revision 1.13 1996/05/17 15:43:30 fritz - * Bugfix: decrement of rcvcount in readbchan() corrected. - * - * Revision 1.12 1996/05/17 03:55:43 fritz - * Changed DLE handling for audio receive. - * Some cleanup. - * Added display of isdn_audio_revision. - * - * Revision 1.11 1996/05/11 21:51:32 fritz - * Changed queue management to use sk_buffs. - * - * Revision 1.10 1996/05/10 08:49:16 fritz - * Checkin before major changes of tty-code. - * - * Revision 1.9 1996/05/07 09:19:41 fritz - * Adapted to changes in isdn_tty.c - * - * Revision 1.8 1996/05/06 11:34:51 hipp - * fixed a few bugs - * - * Revision 1.7 1996/05/02 03:55:17 fritz - * Bugfixes: - * - B-channel connect message for modem devices - * sometimes did not result in a CONNECT-message. - * - register_isdn did not check for driverId-conflicts. - * - * Revision 1.6 1996/04/30 20:57:21 fritz - * Commit test - * - * Revision 1.5 1996/04/20 16:19:07 fritz - * Changed slow timer handlers to increase accuracy. - * Added statistic information for usage by xisdnload. - * Fixed behaviour of isdnctrl-device on non-blocked io. - * Fixed all io to go through generic writebuf-function without - * bypassing. Same for incoming data. - * Fixed bug: Last channel had been unusable. - * Fixed kfree of tty xmit_buf on ppp initialization failure. - * - * Revision 1.4 1996/02/11 02:33:26 fritz - * Fixed bug in main timer-dispatcher. - * Bugfix: Lot of tty-callbacks got called regardless of the events already - * been handled by network-devices. - * Changed ioctl-names. - * - * Revision 1.3 1996/01/22 05:16:11 fritz - * Changed ioctl-names. - * Fixed bugs in isdn_open and isdn_close regarding PPP_MINOR. - * - * Revision 1.2 1996/01/21 16:52:40 fritz - * Support for sk_buffs added, changed header-stuffing. - * - * Revision 1.1 1996/01/09 04:12:52 fritz - * Initial revision - * */ #include @@ -450,9 +44,9 @@ /* Debugflags */ #undef ISDN_DEBUG_STATCALLB -isdn_dev *dev = (isdn_dev *) 0; +isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.100 $"; +static char *isdn_revision = "$Revision: 1.113 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -469,12 +63,13 @@ extern char *isdn_v110_revision; #ifdef CONFIG_ISDN_DIVERSION -isdn_divert_if *divert_if = NULL; /* interface to diversion module */ +isdn_divert_if *divert_if; /* interface to diversion module */ #endif CONFIG_ISDN_DIVERSION static int isdn_writebuf_stub(int, int, const u_char *, int, int); static void set_global_features(void); +static int isdn_wildmat(char *s, char *p); void isdn_MOD_INC_USE_COUNT(void) @@ -556,7 +151,7 @@ * [^xyz] matches any single character not in the set of characters */ -int +static int isdn_wildmat(char *s, char *p) { register int last; @@ -602,6 +197,23 @@ return (*s == '\0')?0:nostar; } +int isdn_msncmp( const char * msn1, const char * msn2 ) +{ + char TmpMsn1[ ISDN_MSNLEN ]; + char TmpMsn2[ ISDN_MSNLEN ]; + char *p; + + for ( p = TmpMsn1; *msn1 && *msn1 != ':'; ) // Strip off a SPID + *p++ = *msn1++; + *p = '\0'; + + for ( p = TmpMsn2; *msn2 && *msn2 != ':'; ) // Strip off a SPID + *p++ = *msn2++; + *p = '\0'; + + return isdn_wildmat( TmpMsn1, TmpMsn2 ); +} + static void isdn_free_queue(struct sk_buff_head *queue) { @@ -673,9 +285,7 @@ save_flags(flags); cli(); - del_timer(&dev->timer); - dev->timer.expires = jiffies + ISDN_TIMER_RES; - add_timer(&dev->timer); + mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES); restore_flags(flags); } } @@ -696,11 +306,8 @@ dev->tflags |= tf; else dev->tflags &= ~tf; - if (dev->tflags) { - if (!del_timer(&dev->timer)) /* del_timer is 1, when active */ - dev->timer.expires = jiffies + ISDN_TIMER_RES; - add_timer(&dev->timer); - } + if (dev->tflags) + mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES); restore_flags(flags); } @@ -878,7 +485,7 @@ return 0; } /* Try to find a network-interface which will accept incoming call */ - r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, c->parm.setup)); + r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup)); switch (r) { case 0: /* No network-device replies. @@ -887,7 +494,7 @@ * 3 on eventually match, if CID is longer. */ if (c->command == ISDN_STAT_ICALL) - if ((retval = isdn_tty_find_icall(di, c->arg, c->parm.setup))) return(retval); + if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval); #ifdef CONFIG_ISDN_DIVERSION if (divert_if) if ((retval = divert_if->stat_callback(c))) @@ -1433,7 +1040,7 @@ } static loff_t -isdn_lseek(struct file *file, loff_t offset, int orig) +isdn_llseek(struct file *file, loff_t offset, int orig) { return -ESPIPE; } @@ -2067,7 +1674,7 @@ static struct file_operations isdn_fops = { - llseek: isdn_lseek, + llseek: isdn_llseek, read: isdn_read, write: isdn_write, poll: isdn_poll, @@ -2252,7 +1859,6 @@ skb_pull(nskb, sizeof(int)); if (!nskb->len) { dev_kfree_skb(nskb); - dev_kfree_skb(skb); return v110_ret; } /* V.110 must always be acknowledged */ @@ -2291,9 +1897,10 @@ atomic_inc(&dev->v110use[idx]); dev->v110[idx]->skbuser++; atomic_dec(&dev->v110use[idx]); - dev_kfree_skb(skb); /* For V.110 return unencoded data length */ ret = v110_ret; + /* if the complete frame was send we free the skb; + if not upper function will requeue the skb */ if (ret == skb->len) dev_kfree_skb(skb); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h --- v2.2.17/drivers/isdn/isdn_common.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_common.h Sun Oct 15 21:51:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.h,v 1.18 2000/01/23 18:45:37 keil Exp $ +/* $Id: isdn_common.h,v 1.20 2000/06/16 13:00:27 keil Exp $ * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel). * @@ -20,90 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_common.h,v $ - * Revision 1.18 2000/01/23 18:45:37 keil - * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) - * - * Revision 1.17 1999/10/27 21:21:17 detabc - * Added support for building logically-bind-group's per interface. - * usefull for outgoing call's with more then one isdn-card. - * - * Switchable support to dont reset the hangup-timeout for - * receive frames. Most part's of the timru-rules for receiving frames - * are now obsolete. If the input- or forwarding-firewall deny - * the frame, the line will be not hold open. - * - * Revision 1.16 1999/07/01 08:29:54 keil - * compatibility to 2.3 kernel - * - * Revision 1.15 1999/04/18 14:06:50 fritz - * Removed TIMRU stuff. - * - * Revision 1.14 1999/04/12 12:33:18 fritz - * Changes from 2.0 tree. - * - * Revision 1.13 1999/03/02 12:04:47 armin - * -added ISDN_STAT_ADDCH to increase supported channels after - * register_isdn(). - * -ttyI now goes on-hook on ATZ when B-Ch is connected. - * -added timer-function for register S7 (Wait for Carrier). - * -analog modem (ISDN_PROTO_L2_MODEM) implementations. - * -on L2_MODEM a string will be appended to the CONNECT-Message, - * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. - * -variable "dialing" used for ATA also, for interrupting call - * establishment and register S7. - * - * Revision 1.12 1998/06/26 15:12:27 fritz - * Added handling of STAT_ICALL with incomplete CPN. - * Added AT&L for ttyI emulator. - * Added more locking stuff in tty_write. - * - * Revision 1.11 1998/04/14 16:28:47 he - * Fixed user space access with interrupts off and remaining - * copy_{to,from}_user() -> -EFAULT return codes - * - * Revision 1.10 1998/03/07 18:21:03 cal - * Dynamic Timeout-Rule-Handling vs. 971110 included - * - * Revision 1.9 1998/02/20 17:19:01 fritz - * Added common stub for sending commands to lowlevel. - * - * Revision 1.8 1997/10/09 21:28:49 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * New L1 error status (not yet in use). - * Cleaned up obsolete structures. - * Implemented Cisco-SLARP. - * Changed local net-interface data to be dynamically allocated. - * Removed old 2.0 compatibility stuff. - * - * Revision 1.7 1997/10/01 09:20:30 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.6 1997/02/28 02:32:44 fritz - * Cleanup: Moved some tty related stuff from isdn_common.c - * to isdn_tty.c - * Bugfix: Bisync protocol did not behave like documented. - * - * Revision 1.5 1997/02/10 10:05:45 fritz - * More changes for Kernel 2.1.X - * Symbol information moved to isdn_syms.c - * - * Revision 1.4 1997/02/03 22:56:50 fritz - * Removed isdn_writebuf_stub prototype. - * - * Revision 1.3 1996/05/19 00:13:05 fritz - * Removed debug flag. - * - * Revision 1.2 1996/04/20 16:20:40 fritz - * Misc. typos. - * - * Revision 1.1 1996/01/10 21:37:19 fritz - * Initial revision - * */ #undef ISDN_DEBUG_MODEM_OPEN @@ -134,7 +50,7 @@ extern int isdn_get_free_channel(int, int, int, int, int, char *); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); -extern int isdn_wildmat(char *, char *); +extern int isdn_msncmp( const char *, const char *); extern int isdn_add_channels(driver *, int, int, int); #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) extern void isdn_dumppkt(char *, u_char *, int, int); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_concap.c linux/drivers/isdn/isdn_concap.c --- v2.2.17/drivers/isdn/isdn_concap.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_concap.c Sat Sep 23 13:15:35 2000 @@ -1,32 +1,26 @@ -/* $Id: isdn_concap.c,v 1.6 1999/08/22 20:26:01 calle Exp $ +/* $Id: isdn_concap.c,v 1.8 2000/05/11 22:29:20 kai Exp $ - * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific + * Linux ISDN subsystem, protocol encapsulation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific * stuff goes here. Stuff that depends only on the concap protocol goes to * another -- protocol specific -- source file. - * - * $Log: isdn_concap.c,v $ - * Revision 1.6 1999/08/22 20:26:01 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.5 1998/10/30 18:44:48 he - * pass return value from isdn_net_dial_req for dialmode change - * - * Revision 1.4 1998/10/30 17:55:24 he - * dialmode for x25iface and multulink ppp - * - * Revision 1.3 1998/05/26 22:39:22 he - * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) - * concap typo - * cleared dev.tbusy in isdn_net BCONN status callback - * - * Revision 1.2 1998/01/31 22:49:21 keil - * correct comments - * - * Revision 1.1 1998/01/31 22:27:57 keil - * New files from Henner Eisen for X.25 support * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_concap.h linux/drivers/isdn/isdn_concap.h --- v2.2.17/drivers/isdn/isdn_concap.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_concap.h Sat Sep 23 13:15:35 2000 @@ -1,5 +1,23 @@ -/* $Id: isdn_concap.h,v 1.2 1998/01/31 22:49:21 keil Exp $ +/* $Id: isdn_concap.h,v 1.3 2000/05/11 22:29:20 kai Exp $ + * + * Linux ISDN subsystem, protocol encapsulation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * */ + extern struct concap_device_ops isdn_concap_reliable_dl_dops; extern struct concap_device_ops isdn_concap_demand_dial_dops; extern struct concap_proto * isdn_concap_new( int ); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.2.17/drivers/isdn/isdn_net.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/isdn/isdn_net.c Sun Oct 15 21:51:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.114 2000/03/16 16:37:41 kai Exp $ +/* $Id: isdn_net.c,v 1.137 2000/09/12 19:43:47 kai Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -20,443 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_net.c,v $ - * Revision 1.114 2000/03/16 16:37:41 kai - * Allow phone numbers starting with "*" as outgoing numbers for - * networking interface. Some PBX's need this to allow dialing internal - * numbers (mine, for example ;-) - * - * Revision 1.113 2000/03/16 15:46:37 kai - * a little bugfix and cosmetic changes - * - * Revision 1.112 2000/03/04 16:20:42 detabc - * copy frames before rewriting frame's saddr - * - * Revision 1.111 2000/02/28 22:28:24 he - * moved tx_timeout warning messages in old (2.2.x) branch where it really only - * indicates problems. - * - * Revision 1.110 2000/02/26 01:00:53 keil - * changes from 2.3.47 - * - * Revision 1.109 2000/02/25 11:29:17 paul - * changed chargetime to ulong from int (after about 20 days the "chargetime of - * ipppX is now 1234" message displays a negative number on alpha). - * - * Revision 1.108 2000/02/15 12:54:01 kai - * set TX timeout back to 2 secs for 2.2.x, just to be safe - * - * Revision 1.107 2000/02/13 09:52:05 kai - * increased TX_TIMEOUT to 20sec - * - * Revision 1.106 2000/02/12 19:26:55 kai - * adopted to latest 2.3 softnet changes. - * - * tested with PPP and MPPP, it works here. - * can somebody check raw-ip? - * - * also changed std2kern, stddiff for bash-1 compatibility, - * hope this doesn't break anything. - * - * Revision 1.105 2000/02/12 11:43:26 he - * SOFTNET related changes, first try. Compatible with linux 2.2.x, but - * not tested for kernels with softnet (>= 2.3.43) yet. - * - * Revision 1.104 2000/02/06 21:49:59 detabc - * add rewriting of socket's and frame's saddr for udp-ipv4 dynip-connections. - * Include checksum-recompute of ip- and udp-header's. - * - * Revision 1.103 2000/01/23 18:45:37 keil - * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) - * - * Revision 1.102 2000/01/09 20:43:14 detabc - * exand logical bind-group's for both call's (in and out). - * add first part of kernel-config-help for abc-extension. - * - * Revision 1.101 1999/12/05 16:06:08 detabc - * add resethandling for rawip-compression. - * at now all B2-Protocols are usable with rawip-compression - * - * Revision 1.100 1999/12/04 15:05:25 detabc - * bugfix abc-rawip-bsdcompress with channel-bundeling - * - * Revision 1.99 1999/11/30 11:29:06 detabc - * add a on the fly frame-counter and limit - * - * Revision 1.98 1999/11/28 14:49:07 detabc - * In case of rawip-compress adjust dev[x]->ibytes/obytes to reflect the - * uncompressed size. - * - * Revision 1.97 1999/11/26 15:54:59 detabc - * added compression (isdn_bsdcompress) for rawip interfaces with x75i B2-protocol. - * - * Revision 1.96 1999/11/20 22:14:13 detabc - * added channel dial-skip in case of external use - * (isdn phone or another isdn device) on the same NTBA. - * usefull with two or more card's connected the different NTBA's. - * global switchable in kernel-config and also per netinterface. - * - * add auto disable of netinterface's in case of: - * to many connection's in short time. - * config mistakes (wrong encapsulation, B2-protokoll or so on) on local - * or remote side. - * wrong password's or something else to a ISP (syncppp). - * - * possible encapsulations for this future are: - * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP, - * and ISDN_NET_ENCAP_CISCOHDLCK. - * - * Revision 1.95 1999/10/27 21:21:17 detabc - * Added support for building logically-bind-group's per interface. - * usefull for outgoing call's with more then one isdn-card. - * - * Switchable support to dont reset the hangup-timeout for - * receive frames. Most part's of the timru-rules for receiving frames - * are now obsolete. If the input- or forwarding-firewall deny - * the frame, the line will be not hold open. - * - * Revision 1.94 1999/10/02 11:07:02 he - * Changed tbusy logic in indn_net.c - * - * Revision 1.93 1999/09/23 22:22:41 detabc - * added tcp-keepalive-detect with local response (ipv4 only) - * added host-only-interface support - * (source ipaddr == interface ipaddr) (ipv4 only) - * ok with kernel 2.3.18 and 2.2.12 - * - * Revision 1.92 1999/09/13 23:25:17 he - * serialized xmitting frames from isdn_ppp and BSENT statcallb - * - * Revision 1.91 1999/09/12 16:19:39 detabc - * added abc features - * low cost routing for net-interfaces (only the HL side). - * need more implementation in the isdnlog-utility - * udp info support (first part). - * different EAZ on outgoing call's. - * more checks on D-Channel callbacks (double use of channels). - * tested and running with kernel 2.3.17 - * - * Revision 1.90 1999/09/04 22:21:39 detabc - * - * Revision 1.89 1999/08/22 20:26:03 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.88 1999/07/07 10:13:31 detabc - * remove unused messages - * - * Revision 1.87 1999/07/06 07:53:53 calle - * calls to dev_alloc_skb waste 16 bytes of memory, if we calculate the - * right header space for the lowlevel driver. using alloc_skb instead. - * - * Revision 1.86 1999/06/09 10:12:05 paul - * thinko in previous patch - * - * Revision 1.85 1999/06/07 19:42:39 paul - * isdn_net_getpeer() fixed to return correct `outgoing' flag - * - * Revision 1.84 1999/04/18 14:06:55 fritz - * Removed TIMRU stuff. - * - * Revision 1.83 1999/04/12 12:33:23 fritz - * Changes from 2.0 tree. - * - * Revision 1.82 1999/01/17 00:55:58 he - * added mark_bh in BCONN statcallb and cleaned up some dead code - * - * Revision 1.81 1999/01/15 16:36:52 he - * replaced icmp_send() by dst_link_failure() - * - * Revision 1.80 1998/12/01 13:06:22 paul - * Also huptimeout with dialmode == manual - * - * Revision 1.79 1998/10/30 17:55:27 he - * dialmode for x25iface and multulink ppp - * - * Revision 1.78 1998/10/26 18:20:46 he - * re-inserted p=p->next in isdn_net_find_icall() (fixes kernel lock up - * on incoming call not matching the first interface) - * - * Revision 1.77 1998/10/23 10:18:44 paul - * Implementation of "dialmode" (successor of "status") - * You also need current isdnctrl for this! - * - * Revision 1.76 1998/09/07 22:00:05 he - * flush method for 2.1.118 and above - * updated IIOCTLNETGPN - * - * Revision 1.75 1998/08/31 21:09:50 he - * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' - * peer phone number) - * - * Revision 1.74 1998/07/30 11:28:32 paul - * printk message only appeared when status is off and interface is rawIP, - * which is confusing for people who don't know about "isdnctrl status on". - * - * Revision 1.73 1998/06/26 22:01:37 keil - * tx_queue_len = 5 was too small - * - * Revision 1.72 1998/06/26 15:12:31 fritz - * Added handling of STAT_ICALL with incomplete CPN. - * Added AT&L for ttyI emulator. - * Added more locking stuff in tty_write. - * - * Revision 1.71 1998/06/18 22:43:08 fritz - * Bugfix: Setting ndev->do_ioctl had beed accidetly removed at cleanup. - * - * Revision 1.70 1998/06/17 19:50:49 he - * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) - * brute force fix to avoid Ugh's in isdn_tty_write() - * cleaned up some dead code - * - * Revision 1.69 1998/06/09 12:27:37 cal - * Changed default of local netdev flags: ISDN_NET_STOPPED is default now, - * so autodial is suppressed for that device until it is switched on using - * 'isdnctrl status dev-name on'. - * - * - * - * Revision 1.66 1998/05/26 22:39:24 he - * sync'ed with 2.1.102 where appropriate (CAPABILITY changes) - * concap typo - * cleared dev.tbusy in isdn_net BCONN status callback - * - * Revision 1.61 1998/04/16 19:19:42 keil - * Fix from vger (tx max qlength) - * - * Revision 1.60 1998/04/14 16:28:49 he - * Fixed user space access with interrupts off and remaining - * copy_{to,from}_user() -> -EFAULT return codes - * - * Revision 1.59 1998/03/07 22:37:33 fritz - * Bugfix: restore_flags missing. - * - * Revision 1.58 1998/03/07 18:21:05 cal - * Dynamic Timeout-Rule-Handling vs. 971110 included - * - * Revision 1.57 1998/02/25 18:31:13 fritz - * Added debugging output in adjust_header. - * - * Revision 1.56 1998/02/25 17:49:42 he - * Changed return codes caused be failing copy_{to,from}_user to -EFAULT - * - * Revision 1.55 1998/02/23 19:38:22 fritz - * Corrected check for modified feature-flags. - * - * Revision 1.54 1998/02/20 17:15:07 fritz - * Changes for recent kernels. - * Ugly workaround for adjusting Ethernet frames with recent kernels. - * replaced direct calls to lowlevel-driver command by common hook. - * - * Revision 1.53 1998/01/31 22:05:54 keil - * Lots of changes for X.25 support: - * Added generic support for connection-controlling encapsulation protocols - * Added support of BHUP status message - * Added support for additional p_encap X25IFACE - * Added support for kernels >= 2.1.72 - * - * Revision 1.52 1998/01/31 19:29:51 calle - * Merged changes from and for 2.1.82, not tested only compiled ... - * - * Revision 1.51 1997/10/09 21:28:50 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * New L1 error status (not yet in use). - * Cleaned up obsolete structures. - * Implemented Cisco-SLARP. - * Changed local net-interface data to be dynamically allocated. - * Removed old 2.0 compatibility stuff. - * - * Revision 1.50 1997/10/01 09:20:32 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.49 1997/08/21 14:38:13 fritz - * Bugfix: Did not compile without SyncPPP. - * - * Revision 1.48 1997/06/22 11:57:15 fritz - * Added ability to adjust slave triggerlevel. - * - * Revision 1.47 1997/06/21 10:52:05 fritz - * Removed wrong SET_SKB_FREE in isdn_net_send_skb() - * - * Revision 1.46 1997/06/17 13:05:24 hipp - * Applied Eric's underflow-patches (slightly modified) - * - * Revision 1.45 1997/06/10 16:24:22 hipp - * hard_header changes for syncPPP (now behaves like RAWIP) - * - * Revision 1.44 1997/05/27 15:17:26 fritz - * Added changes for recent 2.1.x kernels: - * changed return type of isdn_close - * queue_task_* -> queue_task - * clear/set_bit -> test_and_... where apropriate. - * changed type of hard_header_cache parameter. - * - * Revision 1.43 1997/03/30 16:51:13 calle - * changed calls to copy_from_user/copy_to_user and removed verify_area - * were possible. - * - * Revision 1.42 1997/03/11 08:43:51 fritz - * Perform a hangup if number is deleted while dialing. - * - * Revision 1.41 1997/03/08 08:16:31 fritz - * Bugfix: Deleting a phone number during dial gave unpredictable results. - * - * Revision 1.40 1997/03/05 21:16:08 fritz - * Fix: did not compile with 2.1.27 - * - * Revision 1.39 1997/03/04 21:36:52 fritz - * Added sending ICMP messages when no connetion is possible. - * - * Revision 1.38 1997/02/23 23:41:14 fritz - * Bugfix: Slave interfaces have to be hung up before master. - * - * Revision 1.37 1997/02/11 18:32:51 fritz - * Bugfix in isdn_ppp_free_mpqueue(). - * - * Revision 1.36 1997/02/10 21:31:11 fritz - * Changed setup-interface (incoming and outgoing). - * - * Revision 1.35 1997/02/10 20:12:45 fritz - * Changed interface for reporting incoming calls. - * - * Revision 1.34 1997/02/03 23:15:07 fritz - * Reformatted according CodingStyle. - * replaced arp_find prototype by proper include. - * made dev_purge_queues static. - * Bugfix in bogocps calculation. - * removed isdn_net_receive_callback - was never used ;-) - * Misc. fixes for Kernel 2.1.X comaptibility. - * - * Revision 1.33 1997/01/17 01:19:25 fritz - * Applied chargeint patch. - * - * Revision 1.32 1997/01/14 01:29:31 fritz - * Bugfix: isdn_net_hangup() did not reset ISDN_NET_CONNECTED. - * - * Revision 1.31 1997/01/11 23:30:42 fritz - * Speed up dial statemachine. - * - * Revision 1.30 1996/11/25 17:20:50 hipp - * fixed pppbind bug in isdn_net_find_icall() - * - * Revision 1.29 1996/11/13 02:31:38 fritz - * Minor cleanup. - * - * Revision 1.28 1996/10/27 20:49:06 keil - * bugfix to compile without MPP - * - * Revision 1.27 1996/10/25 18:46:01 fritz - * Another bugfix in isdn_net_autohup() - * - * Revision 1.26 1996/10/23 23:05:36 fritz - * Bugfix: Divide by zero in isdn_net_autohup() - * - * Revision 1.25 1996/10/22 23:13:58 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.24 1996/10/11 13:57:40 fritz - * Bugfix: Error in BogoCPS calculation. - * - * Revision 1.23 1996/09/23 01:58:08 fritz - * Fix: With syncPPP encapsulation, discard LCP packets - * when calculating hangup timeout. - * - * Revision 1.22 1996/09/23 00:03:37 fritz - * Fix: did not compile without CONFIG_ISDN_PPP - * - * Revision 1.21 1996/09/07 12:44:50 hipp - * (hopefully) fixed callback problem with syncPPP - * syncPPP network devices now show PPP link encap - * - * Revision 1.20 1996/08/29 20:06:03 fritz - * Bugfix: Transmission timeout had been much to low. - * - * Revision 1.19 1996/08/12 16:24:32 hipp - * removed some (now) obsolete functions for syncPPP in rebuild_header etc. - * - * Revision 1.18 1996/07/03 13:48:51 hipp - * bugfix: Call dev_purge_queues() only for master device - * - * Revision 1.17 1996/06/25 18:37:37 fritz - * Fixed return count for empty return string in isdn_net_getphones(). - * - * Revision 1.16 1996/06/24 17:48:08 fritz - * Bugfixes: - * - Did not free channel on unbinding. - * - ioctl returned wrong callback settings. - * - * Revision 1.15 1996/06/16 17:42:54 tsbogend - * fixed problem with IP addresses on Linux/Alpha (long is 8 byte there) - * - * Revision 1.14 1996/06/11 14:54:08 hipp - * minor bugfix in isdn_net_send_skb - * changes in BSENT callback handler for syncPPP - * added lp->sav_skb stuff - * - * Revision 1.13 1996/06/06 14:25:44 fritz - * Changed loglevel of "incoming ... without OAD" message, since - * with audio support this is quite normal. - * - * Revision 1.12 1996/06/05 02:36:45 fritz - * Minor bugfixes by M. Hipp. - * - * Revision 1.11 1996/05/18 01:36:59 fritz - * Added spelling corrections and some minor changes - * to stay in sync with kernel. - * - * Revision 1.10 1996/05/17 03:49:01 fritz - * Some cleanup. - * - * Revision 1.9 1996/05/06 11:34:57 hipp - * fixed a few bugs - * - * Revision 1.8 1996/04/30 21:04:40 fritz - * Test commit - * - * Revision 1.7 1996/04/30 11:10:42 fritz - * Added Michael's ippp-bind patch. - * - * Revision 1.6 1996/04/30 09:34:35 fritz - * Removed compatibility-macros. - * - * Revision 1.5 1996/04/20 16:28:38 fritz - * Made more parameters of the dial statemachine user-configurable and - * added hangup after dial for more reliability using callback. - * Changed all io going through generic routines in isdn_common.c - * Added missing call to dev_free_skb on failed dialing. - * Added uihdlc encapsulation. - * Fixed isdn_net_setcfg not to destroy interface-flags anymore. - * Misc. typos. - * - * Revision 1.4 1996/02/19 15:23:38 fritz - * Bugfix: Sync-PPP packets got compressed twice, when resent due to - * send-queue-full reject. - * - * Revision 1.3 1996/02/11 02:22:28 fritz - * Changed status- receive-callbacks to use pointer-arrays for finding - * a corresponding interface instead of looping over all interfaces. - * Activate Auto-hangup-timer only when interface is online. - * Some bugfixes in the dialing-statemachine. - * Lot of bugfixes in sk_buff'ized encapsulation handling. - * For speedup connection-setup after dialing, remember sk_buf that triggered - * dialing. - * Fixed isdn_net_log_packet according to different encapsulations. - * Correct ARP-handling for ETHERNET-encapsulation. - * - * Revision 1.2 1996/01/22 05:05:12 fritz - * Changed returncode-logic for isdn_net_start_xmit() and its - * helper-functions. - * Changed handling of buildheader for RAWIP and ETHERNET-encapsulation. - * - * Revision 1.1 1996/01/09 04:12:34 fritz - * Initial revision - * */ #include @@ -2220,7 +1783,7 @@ * would eventually match if CID was longer. */ int -isdn_net_find_icall(int di, int ch, int idx, setup_parm setup) +isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) { char *eaz; int si1; @@ -2236,19 +1799,19 @@ /* Search name in netdev-chain */ save_flags(flags); cli(); - if (!setup.phone[0]) { + if (!setup->phone[0]) { nr[0] = '0'; nr[1] = '\0'; printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); } else - strcpy(nr, setup.phone); - si1 = (int) setup.si1; - si2 = (int) setup.si2; - if (!setup.eazmsn[0]) { + strcpy(nr, setup->phone); + si1 = (int) setup->si1; + si2 = (int) setup->si2; + if (!setup->eazmsn[0]) { printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n"); eaz = "0"; } else - eaz = setup.eazmsn; + eaz = setup->eazmsn; if (dev->net_verbose > 1) printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz); /* Accept only calls with Si1 = 7 (Data-Transmission) */ @@ -2279,7 +1842,7 @@ break; } swapped = 0; - if (!(matchret = isdn_wildmat(eaz, isdn_map_eaz2msn(lp->msn, di)))) + if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di)))) ematch = 1; /* Remember if more numbers eventually can match */ if (matchret > wret) @@ -2371,7 +1934,7 @@ n = lp->phone[0]; if (lp->flags & ISDN_NET_SECURE) { while (n) { - if (!isdn_wildmat(nr, n->num)) + if (!isdn_msncmp(nr, n->num)) break; n = (isdn_net_phone *) n->next; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v2.2.17/drivers/isdn/isdn_net.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_net.h Sun Oct 15 21:51:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.h,v 1.10 1999/08/22 20:26:06 calle Exp $ +/* $Id: isdn_net.h,v 1.19 2000/06/21 09:54:29 keil Exp $ * header for Linux ISDN subsystem, network related functions (linklevel). * @@ -20,48 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_net.h,v $ - * Revision 1.10 1999/08/22 20:26:06 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.9 1999/04/12 12:33:27 fritz - * Changes from 2.0 tree. - * - * Revision 1.8 1998/10/30 17:55:33 he - * dialmode for x25iface and multulink ppp - * - * Revision 1.7 1998/08/31 21:09:55 he - * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface' - * peer phone number) - * - * Revision 1.6 1997/10/09 21:28:54 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * New L1 error status (not yet in use). - * Cleaned up obsolete structures. - * Implemented Cisco-SLARP. - * Changed local net-interface data to be dynamically allocated. - * Removed old 2.0 compatibility stuff. - * - * Revision 1.5 1997/02/10 20:12:47 fritz - * Changed interface for reporting incoming calls. - * - * Revision 1.4 1997/02/03 23:16:48 fritz - * Removed isdn_net_receive_callback prototype. - * - * Revision 1.3 1997/01/17 01:19:30 fritz - * Applied chargeint patch. - * - * Revision 1.2 1996/04/20 16:29:43 fritz - * Misc. typos - * - * Revision 1.1 1996/02/11 02:35:13 fritz - * Initial revision - * */ /* Definitions for hupflags: */ @@ -117,7 +75,7 @@ extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *); extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *); extern int isdn_net_delphone(isdn_net_ioctl_phone *); -extern int isdn_net_find_icall(int, int, int, setup_parm); +extern int isdn_net_find_icall(int, int, int, setup_parm *); extern void isdn_net_hangup(struct device *); extern void isdn_net_dial(void); extern void isdn_net_autohup(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.2.17/drivers/isdn/isdn_ppp.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/isdn/isdn_ppp.c Wed Nov 1 17:04:36 2000 @@ -18,256 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_ppp.c,v $ - * Revision 1.63 2000/03/16 15:46:37 kai - * a little bugfix and cosmetic changes - * - * Revision 1.62 2000/02/12 19:26:55 kai - * adopted to latest 2.3 softnet changes. - * - * tested with PPP and MPPP, it works here. - * can somebody check raw-ip? - * - * also changed std2kern, stddiff for bash-1 compatibility, - * hope this doesn't break anything. - * - * Revision 1.61 1999/11/20 22:14:14 detabc - * added channel dial-skip in case of external use - * (isdn phone or another isdn device) on the same NTBA. - * usefull with two or more card's connected the different NTBA's. - * global switchable in kernel-config and also per netinterface. - * - * add auto disable of netinterface's in case of: - * to many connection's in short time. - * config mistakes (wrong encapsulation, B2-protokoll or so on) on local - * or remote side. - * wrong password's or something else to a ISP (syncppp). - * - * possible encapsulations for this future are: - * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP, - * and ISDN_NET_ENCAP_CISCOHDLCK. - * - * Revision 1.60 1999/11/04 20:29:55 he - * applied Andre Beck's reset_free fix - * - * Revision 1.59 1999/10/31 15:59:50 he - * more skb headroom checks - * - * Revision 1.58 1999/10/30 13:13:01 keil - * Henners isdn_ppp_skb_push:under fix - * - * Revision 1.57 1999/10/05 22:47:17 he - * Removed dead ISDN_SYNCPPP_READDRESS code (obsoleted by sysctl_ip_dynaddr - * and network address translation) - * - * Revision 1.56 1999/09/29 16:01:06 he - * replaced dev_alloc_skb() for downstream skbs by equivalent alloc_skb() - * - * Revision 1.55 1999/09/23 22:07:51 detabc - * - * make ipc_head common usable (for use compressor with raw-ip) - * add function before netif_rx(). needed for ipv4-tcp-keepalive-detect. - * ~ - * - * Revision 1.54 1999/09/13 23:25:17 he - * serialized xmitting frames from isdn_ppp and BSENT statcallb - * - * Revision 1.53 1999/08/31 11:18:14 paul - * various spelling corrections (new checksums may be needed, Karsten!) - * - * Revision 1.52 1999/08/22 20:26:07 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.51 1999/08/18 16:19:17 hipp - * applied MPPP-resize-headroom patch - * - * Revision 1.50 1999/08/16 07:11:41 hipp - * Additional VJ decomp-buffer-size increased from 40 to 128 - * - * Revision 1.49 1999/07/06 07:47:11 calle - * bugfix: dev_alloc_skb only reserve 16 bytes. We need to look at the - * hdrlen the driver want. So I changed dev_alloc_skb calls - * to alloc_skb and skb_reserve. - * - * Revision 1.48 1999/07/01 08:29:56 keil - * compatibility to 2.3 kernel - * - * Revision 1.47 1999/04/18 14:06:59 fritz - * Removed TIMRU stuff. - * - * Revision 1.46 1999/04/12 12:33:35 fritz - * Changes from 2.0 tree. - * - * Revision 1.45 1998/12/30 17:48:24 paul - * fixed syncPPP callback out - * - * Revision 1.44 1998/10/30 17:55:34 he - * dialmode for x25iface and multulink ppp - * - * Revision 1.43 1998/10/29 17:23:54 hipp - * Minor MPPP fixes, verboser logging. - * - * Revision 1.42 1998/07/20 11:30:07 hipp - * Readded compression check - * - * Revision 1.41 1998/07/08 16:50:57 hipp - * Compression changes - * - * Revision 1.40 1998/04/06 19:07:27 hipp - * added check, whether compression is enabled. - * - * Revision 1.39 1998/03/25 22:46:53 hipp - * Some additional CCP changes. - * - * Revision 1.38 1998/03/24 16:33:06 hipp - * More CCP changes. BSD compression now "works" on a local loopback link. - * Moved some isdn_ppp stuff from isdn.h to isdn_ppp.h - * - * Revision 1.37 1998/03/22 18:50:49 hipp - * Added BSD Compression for syncPPP .. UNTESTED at the moment - * - * Revision 1.36 1998/03/09 17:46:30 he - * merged in 2.1.89 changes - * - * Revision 1.35 1998/03/07 18:21:11 cal - * Dynamic Timeout-Rule-Handling vs. 971110 included - * - * Revision 1.34 1998/02/25 17:49:48 he - * Changed return codes caused be failing copy_{to,from}_user to -EFAULT - * - * Revision 1.33 1998/02/20 17:11:54 fritz - * Changes for recent kernels. - * - * Revision 1.32 1998/01/31 19:29:55 calle - * Merged changes from and for 2.1.82, not tested only compiled ... - * - * Revision 1.31 1997/10/09 21:29:01 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * New L1 error status (not yet in use). - * Cleaned up obsolete structures. - * Implemented Cisco-SLARP. - * Changed local net-interface data to be dynamically allocated. - * Removed old 2.0 compatibility stuff. - * - * Revision 1.30 1997/10/01 09:20:38 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.29 1997/08/21 23:11:44 fritz - * Added changes for kernels >= 2.1.45 - * - * Revision 1.28 1997/06/17 13:05:57 hipp - * Applied Eric's underflow-patches (slightly modified) - * more compression changes (but disabled at the moment) - * changed one copy_to_user() to run with enabled IRQs - * a few MP changes - * changed 'proto' handling in the isdn_ppp receive code - * - * Revision 1.27 1997/03/30 16:51:17 calle - * changed calls to copy_from_user/copy_to_user and removed verify_area - * were possible. - * - * Revision 1.26 1997/02/23 16:53:44 hipp - * minor cleanup - * some initial changes for future PPP compresion - * added AC,PC compression for outgoing frames - * - * Revision 1.25 1997/02/12 20:37:35 hipp - * New ioctl() PPPIOCGCALLINFO, minor cleanup - * - * Revision 1.24 1997/02/11 18:32:56 fritz - * Bugfix in isdn_ppp_free_mpqueue(). - * - * Revision 1.23 1997/02/10 11:12:19 fritz - * More changes for Kernel 2.1.X compatibility. - * - * Revision 1.22 1997/02/06 15:03:51 hipp - * changed GFP_KERNEL kmalloc to GFP_ATOMIC in isdn_ppp_fill_mpqueue() - * - * Revision 1.21 1997/02/03 23:29:38 fritz - * Reformatted according CodingStyle - * Bugfix: removed isdn_ppp_skb_destructor, used by upper layers. - * Misc changes for Kernel 2.1.X compatibility. - * - * Revision 1.20 1996/10/30 12:21:58 fritz - * Cosmetic fix: Compiler warning when compiling without MPP. - * - * Revision 1.19 1996/10/25 19:03:21 hipp - * changed/added some defines to (re)allow compilation without MP/VJ - * - * Revision 1.18 1996/10/22 23:14:00 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.17 1996/10/22 09:39:49 hipp - * a few MP changes and bugfixes - * - * Revision 1.16 1996/09/23 01:58:10 fritz - * Fix: With syncPPP encapsulation, discard LCP packets - * when calculating hangup timeout. - * - * Revision 1.15 1996/09/07 12:50:12 hipp - * bugfixes (unknown device after failed dial attempt, minor bugs) - * - * Revision 1.14 1996/08/12 16:26:47 hipp - * code cleanup - * changed connection management from minors to slots - * - * Revision 1.13 1996/07/01 19:47:24 hipp - * Fixed memory leak in VJ handling and more VJ changes - * - * Revision 1.12 1996/06/24 17:42:03 fritz - * Minor bugfixes. - * - * Revision 1.11 1996/06/16 17:46:05 tsbogend - * changed unsigned long to u32 to make Alpha people happy - * - * Revision 1.10 1996/06/11 14:50:29 hipp - * Lot of changes and bugfixes. - * New scheme to resend packets to busy LL devices. - * - * Revision 1.9 1996/05/18 01:37:01 fritz - * Added spelling corrections and some minor changes - * to stay in sync with kernel. - * - * Revision 1.8 1996/05/06 11:34:55 hipp - * fixed a few bugs - * - * Revision 1.7 1996/04/30 11:07:42 fritz - * Added Michael's ippp-bind patch. - * - * Revision 1.6 1996/04/30 09:33:09 fritz - * Removed compatibility-macros. - * - * Revision 1.5 1996/04/20 16:32:32 fritz - * Changed ippp_table to an array of pointers, allocating each part - * separately. - * - * Revision 1.4 1996/02/19 15:25:50 fritz - * Bugfix: Sync-PPP packets got compressed twice, when resent due to - * send-queue-full reject. - * - * Revision 1.3 1996/02/11 02:27:12 fritz - * Lot of Bugfixes my Michael. - * Moved calls to skb_push() into isdn_net_header() - * Fixed a possible race-condition in isdn_ppp_timer_timeout(). - * - * Revision 1.2 1996/01/22 05:08:06 fritz - * Merged in Michael's patches for MP. - * Minor changes in isdn_ppp_xmit. - * - * Revision 1.1 1996/01/09 04:11:29 fritz - * Initial revision - * */ -/* TODO: right tbusy handling when using MP */ - #define CONFIG_ISDN_CCP 1 #include @@ -1206,12 +958,18 @@ if(is->debug & 0x10) printk(KERN_DEBUG "received single link compressed frame\n"); skb = isdn_ppp_decompress(skb,is,NULL,proto); - if(!skb) + if(!skb) { + printk(KERN_DEBUG "ippp: dropping LINK_COMP frame!\n"); return; + } proto = isdn_ppp_strip_proto(skb); + } else { + skb = isdn_ppp_decompress(skb,is,NULL,proto); + if(!skb) { + printk(KERN_DEBUG "ippp: dropping uncompressed frame!\n"); + return; + } } - else - isdn_ppp_decompress(skb,is,NULL,proto); } if (proto == PPP_MP) { @@ -1249,11 +1007,11 @@ } if(proto == PPP_COMP) { - if(!lp->master) + if(!lp->master) { skb = isdn_ppp_decompress(skb,is,is,proto); - else + } else { skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); - + } if(!skb) { printk(KERN_DEBUG "ippp: compressed frame discarded!\n"); return; @@ -1265,11 +1023,17 @@ isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } } - else if(is->compflags & SC_DECOMP_ON) { /* If decomp is ON */ - if(!lp->master) - isdn_ppp_decompress(skb,is,is,proto); - else - isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); + else if (is->compflags & SC_DECOMP_ON) { /* If decomp is ON */ + if(!lp->master) { + skb = isdn_ppp_decompress(skb,is,is,proto); + } else { + skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto); + } + + if(!skb) { + printk(KERN_DEBUG "ippp: compressed frame discarded!\n"); + return; + } } switch (proto) { @@ -2619,14 +2383,12 @@ * single link decompression */ if(!is->link_decompressor) { - printk(KERN_ERR "ippp: no link decompressor defined!\n"); - dev_kfree_skb(skb); - return NULL; + printk(KERN_DEBUG "ippp: no link decompressor defined!\n"); + return skb; } if(!is->link_decomp_stat) { printk(KERN_DEBUG "ippp: no link decompressor data allocated\n"); - dev_kfree_skb(skb); - return NULL; + return skb; } stat = is->link_decomp_stat; ipc = is->link_decompressor; @@ -2637,14 +2399,12 @@ * 'normal' or bundle-compression */ if(!master->decompressor) { - printk(KERN_ERR "ippp: no decompressor defined!\n"); - dev_kfree_skb(skb); - return NULL; + printk(KERN_DEBUG "ippp: no decompressor defined!\n"); + return skb; } if(!master->decomp_stat) { printk(KERN_DEBUG "ippp: no decompressor data allocated\n"); - dev_kfree_skb(skb); - return NULL; + return skb; } stat = master->decomp_stat; ipc = master->decompressor; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h --- v2.2.17/drivers/isdn/isdn_ppp.h Sat Sep 9 18:42:38 2000 +++ linux/drivers/isdn/isdn_ppp.h Sat Nov 18 20:13:15 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.14 1999/08/22 20:26:10 calle Exp $ +/* $Id: isdn_ppp.h,v 1.17 2000/08/10 22:52:46 kai Exp $ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -18,65 +18,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_ppp.h,v $ - * Revision 1.14 1999/08/22 20:26:10 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.13 1998/03/22 18:50:50 hipp - * Added BSD Compression for syncPPP .. UNTESTED at the moment - * - * Revision 1.12 1998/01/31 22:07:48 keil - * changes for newer kernels - * - * Revision 1.11 1997/10/01 09:20:44 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.10 1997/06/17 13:06:00 hipp - * Applied Eric's underflow-patches (slightly modified) - * more compression changes (but disabled at the moment) - * changed one copy_to_user() to run with enabled IRQs - * a few MP changes - * changed 'proto' handling in the isdn_ppp receive code - * - * Revision 1.9 1997/02/11 18:32:59 fritz - * Bugfix in isdn_ppp_free_mpqueue(). - * - * Revision 1.8 1997/02/10 10:11:33 fritz - * More changes for Kernel 2.1.X compatibility. - * - * Revision 1.7 1997/02/03 23:18:57 fritz - * Removed isdn_ppp_free_sqqueue prototype - * and ippp_table (both static in isdn_ppp.c). - * - * Revision 1.6 1996/09/23 01:58:11 fritz - * Fix: With syncPPP encapsulation, discard LCP packets - * when calculating hangup timeout. - * - * Revision 1.5 1996/09/07 12:51:34 hipp - * *** empty log message *** - * - * Revision 1.4 1996/05/06 11:34:56 hipp - * fixed a few bugs - * - * Revision 1.3 1996/04/30 09:33:10 fritz - * Removed compatibility-macros. - * - * Revision 1.2 1996/04/20 16:35:11 fritz - * Changed isdn_ppp_receive to use sk_buff as parameter. - * Added definition of isdn_ppp_dial_slave and ippp_table. - * - * Revision 1.1 1996/01/10 21:39:10 fritz - * Initial revision - * */ #include /* for PPP_PROTOCOL */ -#include +#include /* for isdn_ppp info */ extern int isdn_ppp_read(int, struct file *, char *, int); extern int isdn_ppp_write(int, struct file *, const char *, int); extern int isdn_ppp_open(int, struct file *); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.2.17/drivers/isdn/isdn_tty.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_tty.c Sun Oct 15 21:51:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.84 2000/02/16 15:10:14 paul Exp $ +/* $Id: isdn_tty.c,v 1.93 2000/08/05 09:58:26 armin Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -19,334 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_tty.c,v $ - * Revision 1.84 2000/02/16 15:10:14 paul - * If a ttyI has no open FDs, don't connect incoming calls to it. - * (Hangup on close of last FD is still to be done.) - * - * Revision 1.83 2000/02/16 14:59:33 paul - * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; - * used defines for result codes; - * fixed RING ... RUNG problem (no empty lines in between). - * - * Revision 1.82 2000/01/23 18:45:37 keil - * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) - * - * Revision 1.81 2000/01/20 19:55:33 keil - * Add FAX Class 1 support - * - * Revision 1.80 1999/11/07 13:34:30 armin - * Fixed AT command line editor - * - * Revision 1.79 1999/10/29 18:35:08 armin - * Check number len in isdn_get_msnstr() to avoid buffer overflow. - * - * Revision 1.78 1999/10/28 23:03:51 armin - * Bugfix: now freeing channel on modem_hup() even when - * usage on ttyI has changed and error-report for - * AT-commands on wrong channel-state. - * - * Revision 1.77 1999/10/26 21:13:14 armin - * using define for checking phone number len in isdn_tty_getdial() - * - * Revision 1.76 1999/10/11 22:16:26 keil - * Suspend/Resume is possible without explicit ID too - * - * Revision 1.75 1999/10/08 18:59:32 armin - * Bugfix of too small MSN buffer and checking phone number - * in isdn_tty_getdial() - * - * Revision 1.74 1999/09/04 06:20:04 keil - * Changes from kernel set_current_state() - * - * Revision 1.73 1999/08/28 21:56:27 keil - * misplaced #endif caused ttyI crash in 2.3.X - * - * Revision 1.72 1999/07/31 12:59:45 armin - * Added tty fax capabilities. - * - * Revision 1.71 1999/07/27 10:34:34 armin - * Fixed last change. Did not compile with AUDIO support off. - * - * Revision 1.70 1999/07/25 16:17:58 keil - * Fix Suspend/Resume - * - * Revision 1.69 1999/07/25 12:56:15 armin - * isdn_tty_at_cout() now queues the message if online and - * data is in queue or flip buffer is full. - * needed for fax connections. - * - * Revision 1.68 1999/07/11 17:51:51 armin - * Bugfix, "-" was missing for AT&L settings. - * - * Revision 1.67 1999/07/11 17:14:12 armin - * Added new layer 2 and 3 protocols for Fax and DSP functions. - * Moved "Add CPN to RING message" to new register S23, - * "Display message" is now correct on register S13 bit 7. - * New audio command AT+VDD implemented (deactivate DTMF decoder and - * activate possible existing hardware/DSP decoder). - * Moved some tty defines to .h file. - * Made whitespace possible in AT command line. - * Some AT-emulator output bugfixes. - * First Fax G3 implementations. - * - * Revision 1.66 1999/07/07 10:13:46 detabc - * remove unused messages - * - * Revision 1.65 1999/07/04 21:01:59 werner - * Added support for keypad and display (ported from 2.0) - * - * Revision 1.64 1999/07/01 08:30:00 keil - * compatibility to 2.3 kernel - * - * Revision 1.63 1999/04/12 12:33:39 fritz - * Changes from 2.0 tree. - * - * Revision 1.62 1999/03/02 12:04:48 armin - * -added ISDN_STAT_ADDCH to increase supported channels after - * register_isdn(). - * -ttyI now goes on-hook on ATZ when B-Ch is connected. - * -added timer-function for register S7 (Wait for Carrier). - * -analog modem (ISDN_PROTO_L2_MODEM) implementations. - * -on L2_MODEM a string will be appended to the CONNECT-Message, - * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. - * -variable "dialing" used for ATA also, for interrupting call - * establishment and register S7. - * - * Revision 1.61 1999/01/27 22:53:11 he - * minor updates (spellings, jiffies wrap around in isdn_tty) - * - * Revision 1.60 1998/11/15 23:57:32 keil - * changes for 2.1.127 - * - * Revision 1.59 1998/08/20 13:50:15 keil - * More support for hybrid modem (not working yet) - * - * Revision 1.58 1998/07/26 18:48:45 armin - * Added silence detection in voice receive mode. - * - * Revision 1.57 1998/06/26 15:12:36 fritz - * Added handling of STAT_ICALL with incomplete CPN. - * Added AT&L for ttyI emulator. - * Added more locking stuff in tty_write. - * - * Revision 1.56 1998/06/18 23:31:51 fritz - * Replaced cli()/restore_flags() in isdn_tty_write() by locking. - * Removed direct-senddown feature in isdn_tty_write because it will - * never succeed with locking and is useless anyway. - * - * Revision 1.55 1998/06/17 19:50:55 he - * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) - * brute force fix to avoid Ugh's in isdn_tty_write() - * cleaned up some dead code - * - * - * - * Revision 1.52 1998/03/19 13:18:21 keil - * Start of a CAPI like interface for supplementary Service - * first service: SUSPEND - * - * - * Revision 1.49 1998/03/08 00:01:59 fritz - * Bugfix: Lowlevel module usage and channel usage were not - * reset on NO DCHANNEL. - * - * Revision 1.48 1998/03/07 12:28:15 tsbogend - * fixed kernel unaligned traps on Linux/Alpha - * - * Revision 1.47 1998/02/22 19:44:14 fritz - * Bugfixes and improvements regarding V.110, V.110 now running. - * - * Revision 1.46 1998/02/20 17:23:08 fritz - * Changes for recent kernels. - * Merged in contributions by Thomas Pfeiffer (V.110 T.70+ Extended FAX stuff) - * Added symbolic constants for Modem-Registers. - * - * Revision 1.45 1998/01/31 22:07:49 keil - * changes for newer kernels - * - * Revision 1.44 1998/01/31 19:30:02 calle - * Merged changes from and for 2.1.82, not tested only compiled ... - * - * Revision 1.43 1997/10/09 21:29:04 fritz - * New HL<->LL interface: - * New BSENT callback with nr. of bytes included. - * Sending without ACK. - * New L1 error status (not yet in use). - * Cleaned up obsolete structures. - * Implemented Cisco-SLARP. - * Changed local net-interface data to be dynamically allocated. - * Removed old 2.0 compatibility stuff. - * - * Revision 1.42 1997/10/01 09:20:49 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.41 1997/05/27 15:17:31 fritz - * Added changes for recent 2.1.x kernels: - * changed return type of isdn_close - * queue_task_* -> queue_task - * clear/set_bit -> test_and_... where apropriate. - * changed type of hard_header_cache parameter. - * - * Revision 1.40 1997/03/24 22:55:27 fritz - * Added debug code for status callbacks. - * - * Revision 1.39 1997/03/21 18:25:56 fritz - * Corrected CTS handling. - * - * Revision 1.38 1997/03/07 12:13:35 fritz - * Bugfix: Send audio in adpcm format was broken. - * Bugfix: CTS handling was wrong. - * - * Revision 1.37 1997/03/07 01:37:34 fritz - * Bugfix: Did not compile with CONFIG_ISDN_AUDIO disabled. - * Bugfix: isdn_tty_tint() did not handle lowlevel errors correctly. - * Bugfix: conversion was wrong when sending ulaw audio. - * Added proper ifdef's for CONFIG_ISDN_AUDIO - * - * Revision 1.36 1997/03/04 21:41:55 fritz - * Fix: Excessive stack usage of isdn_tty_senddown() - * and isdn_tty_end_vrx() could lead to problems. - * - * Revision 1.35 1997/03/02 19:05:52 fritz - * Bugfix: Avoid recursion. - * - * Revision 1.34 1997/03/02 14:29:22 fritz - * More ttyI related cleanup. - * - * Revision 1.33 1997/02/28 02:32:45 fritz - * Cleanup: Moved some tty related stuff from isdn_common.c - * to isdn_tty.c - * Bugfix: Bisync protocol did not behave like documented. - * - * Revision 1.32 1997/02/23 15:43:03 fritz - * Small change in handling of incoming calls - * documented in newest version of ttyI.4 - * - * Revision 1.31 1997/02/21 13:05:57 fritz - * Bugfix: Remote hangup did not set location-info on ttyI's - * - * Revision 1.30 1997/02/18 09:41:05 fritz - * Added support for bitwise access to modem registers (ATSx.y=n, ATSx.y?). - * Beautified output of AT&V. - * - * Revision 1.29 1997/02/16 12:11:51 fritz - * Added S13,Bit4 option. - * - * Revision 1.28 1997/02/10 22:07:08 fritz - * Added 2 modem registers for numbering plan and screening info. - * - * Revision 1.27 1997/02/10 21:31:14 fritz - * Changed setup-interface (incoming and outgoing). - * - * Revision 1.26 1997/02/10 20:12:48 fritz - * Changed interface for reporting incoming calls. - * - * Revision 1.25 1997/02/03 23:04:30 fritz - * Reformatted according CodingStyle. - * skb->free stuff replaced by macro. - * Finished full-duplex audio. - * - * Revision 1.24 1997/01/14 01:32:42 fritz - * Changed audio receive not to rely on skb->users and skb->lock. - * Added ATI2 and related variables. - * Started adding full-duplex audio capability. - * - * Revision 1.23 1996/10/22 23:14:02 fritz - * Changes for compatibility to 2.0.X and 2.1.X kernels. - * - * Revision 1.22 1996/10/19 18:56:43 fritz - * ATZ did not change the xmitbuf size. - * - * Revision 1.21 1996/06/24 17:40:28 fritz - * Bugfix: Did not compile without CONFIG_ISDN_AUDIO - * - * Revision 1.20 1996/06/15 14:59:39 fritz - * Fixed isdn_tty_tint() to handle partially sent - * sk_buffs. - * - * Revision 1.19 1996/06/12 15:53:56 fritz - * Bugfix: AT+VTX and AT+VRX could be executed without - * having a connection. - * Missing check for NULL tty in isdn_tty_flush_buffer(). - * - * Revision 1.18 1996/06/07 11:17:33 tsbogend - * added missing #ifdef CONFIG_ISDN_AUDIO to make compiling without - * audio support possible - * - * Revision 1.17 1996/06/06 14:55:47 fritz - * Changed to support DTMF decoding on audio playback also. - * Bugfix: Added check for invalid info->isdn_driver in - * isdn_tty_senddown(). - * Clear ncarrier flag on last close() of a tty. - * - * Revision 1.16 1996/06/05 02:24:12 fritz - * Added DTMF decoder for audio mode. - * - * Revision 1.15 1996/06/03 20:35:01 fritz - * Fixed typos. - * - * Revision 1.14 1996/06/03 20:12:19 fritz - * Fixed typos. - * Added call to write_wakeup via isdn_tty_flush_buffer() - * in isdn_tty_modem_hup(). - * - * Revision 1.13 1996/05/31 01:33:29 fritz - * Changed buffering due to bad performance with mgetty. - * Now sk_buff is delayed allocated in isdn_tty_senddown - * using xmit_buff like in standard serial driver. - * Fixed module locking. - * Added DLE-DC4 handling in voice mode. - * - * Revision 1.12 1996/05/19 01:34:40 fritz - * Bugfix: ATS returned error. - * Register 20 made readonly. - * - * Revision 1.11 1996/05/18 01:37:03 fritz - * Added spelling corrections and some minor changes - * to stay in sync with kernel. - * - * Revision 1.10 1996/05/17 03:51:49 fritz - * Changed DLE handling for audio receive. - * - * Revision 1.9 1996/05/11 21:52:07 fritz - * Changed queue management to use sk_buffs. - * - * Revision 1.8 1996/05/10 08:49:43 fritz - * Checkin before major changes of tty-code. - * - * Revision 1.7 1996/05/07 09:15:09 fritz - * Reorganized and general cleanup. - * Bugfixes: - * - Audio-transmit working now. - * - "NO CARRIER" now reported, when hanging up with DTR low. - * - Corrected CTS handling. - * - * Revision 1.6 1996/05/02 03:59:25 fritz - * Bugfixes: - * - On dialout, layer-2 setup had been incomplete - * when using new auto-layer2 feature. - * - On hangup, "NO CARRIER" message sometimes missing. - * - * Revision 1.5 1996/04/30 21:05:25 fritz - * Test commit - * - * Revision 1.4 1996/04/20 16:39:54 fritz - * Changed all io to go through generic routines in isdn_common.c - * Fixed a real ugly bug in modem-emulator: 'ATA' had been accepted - * even when a call has been cancelled from the remote machine. - * - * Revision 1.3 1996/02/11 02:12:32 fritz - * Bugfixes according to similar fixes in standard serial.c of kernel. - * - * Revision 1.2 1996/01/22 05:12:25 fritz - * replaced my_atoi by simple_strtoul - * - * Revision 1.1 1996/01/09 04:13:18 fritz - * Initial revision - * */ #undef ISDN_TTY_STAT_DEBUG @@ -2480,7 +2152,7 @@ while (1) { if ((q = strchr(p, ';'))) *q = '\0'; - if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret) + if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret) ret = tmp; #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n", @@ -2499,7 +2171,7 @@ return ret; } else { int tmp; - tmp = isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di)); + tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di)); #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n", isdn_map_eaz2msn(emu->msn, di), tmp); @@ -2520,7 +2192,7 @@ * CID is longer. */ int -isdn_tty_find_icall(int di, int ch, setup_parm setup) +isdn_tty_find_icall(int di, int ch, setup_parm *setup) { char *eaz; int i; @@ -2531,18 +2203,18 @@ char *nr; ulong flags; - if (!setup.phone[0]) { + if (!setup->phone[0]) { nr = "0"; printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else - nr = setup.phone; - si1 = (int) setup.si1; - si2 = (int) setup.si2; - if (!setup.eazmsn[0]) { + nr = setup->phone; + si1 = (int) setup->si1; + si2 = (int) setup->si2; + if (!setup->eazmsn[0]) { printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n"); eaz = "0"; } else - eaz = setup.eazmsn; + eaz = setup->eazmsn; #ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); #endif @@ -2584,8 +2256,8 @@ strcpy(dev->num[idx], nr); strcpy(info->emu.cpn, eaz); info->emu.mdmreg[REG_SI1I] = si2bit[si1]; - info->emu.mdmreg[REG_PLAN] = setup.plan; - info->emu.mdmreg[REG_SCREEN] = setup.screen; + info->emu.mdmreg[REG_PLAN] = setup->plan; + info->emu.mdmreg[REG_SCREEN] = setup->screen; isdn_info_update(); restore_flags(flags); printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h --- v2.2.17/drivers/isdn/isdn_tty.h Fri Apr 21 23:22:17 2000 +++ linux/drivers/isdn/isdn_tty.h Sun Oct 15 21:51:57 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.19 2000/02/16 14:59:33 paul Exp $ +/* $Id: isdn_tty.h,v 1.22 2000/06/21 09:54:29 keil Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -19,89 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_tty.h,v $ - * Revision 1.19 2000/02/16 14:59:33 paul - * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; - * used defines for result codes; - * fixed RING ... RUNG problem (no empty lines in between). - * - * Revision 1.18 2000/01/20 19:55:33 keil - * Add FAX Class 1 support - * - * Revision 1.17 1999/09/21 19:00:35 armin - * Extended FCON message with added CPN - * can now be activated with Bit 1 of Reg 23. - * - * Revision 1.16 1999/08/22 20:26:10 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.15 1999/07/31 12:59:48 armin - * Added tty fax capabilities. - * - * Revision 1.14 1999/07/11 17:14:15 armin - * Added new layer 2 and 3 protocols for Fax and DSP functions. - * Moved "Add CPN to RING message" to new register S23, - * "Display message" is now correct on register S13 bit 7. - * New audio command AT+VDD implemented (deactivate DTMF decoder and - * activate possible existing hardware/DSP decoder). - * Moved some tty defines to .h file. - * Made whitespace possible in AT command line. - * Some AT-emulator output bugfixes. - * First Fax G3 implementations. - * - * Revision 1.13 1999/04/12 12:33:46 fritz - * Changes from 2.0 tree. - * - * Revision 1.12 1999/03/02 12:04:51 armin - * -added ISDN_STAT_ADDCH to increase supported channels after - * register_isdn(). - * -ttyI now goes on-hook on ATZ when B-Ch is connected. - * -added timer-function for register S7 (Wait for Carrier). - * -analog modem (ISDN_PROTO_L2_MODEM) implementations. - * -on L2_MODEM a string will be appended to the CONNECT-Message, - * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN. - * -variable "dialing" used for ATA also, for interrupting call - * establishment and register S7. - * - * Revision 1.11 1998/03/19 13:18:27 keil - * Start of a CAPI like interface for supplementary Service - * first service: SUSPEND - * - * Revision 1.10 1997/03/02 14:29:26 fritz - * More ttyI related cleanup. - * - * Revision 1.9 1997/02/28 02:32:49 fritz - * Cleanup: Moved some tty related stuff from isdn_common.c - * to isdn_tty.c - * Bugfix: Bisync protocol did not behave like documented. - * - * Revision 1.8 1997/02/10 20:12:50 fritz - * Changed interface for reporting incoming calls. - * - * Revision 1.7 1997/02/03 23:06:10 fritz - * Reformatted according CodingStyle - * - * Revision 1.6 1997/01/14 01:35:19 fritz - * Changed prototype of isdn_tty_modem_hup. - * - * Revision 1.5 1996/05/17 03:52:31 fritz - * Changed DLE handling for audio receive. - * - * Revision 1.4 1996/05/11 21:52:34 fritz - * Changed queue management to use sk_buffs. - * - * Revision 1.3 1996/05/07 09:16:34 fritz - * Changed isdn_try_read parameter. - * - * Revision 1.2 1996/04/30 21:05:27 fritz - * Test commit - * - * Revision 1.1 1996/01/10 21:39:22 fritz - * Initial revision - * */ #include @@ -196,7 +113,7 @@ extern void isdn_tty_modem_xmit(void); extern int isdn_tty_modem_init(void); extern void isdn_tty_readmodem(void); -extern int isdn_tty_find_icall(int, int, setup_parm); +extern int isdn_tty_find_icall(int, int, setup_parm *); extern void isdn_tty_cleanup_xmit(modem_info *); extern int isdn_tty_stat_callback(int, isdn_ctrl *); extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_ttyfax.c linux/drivers/isdn/isdn_ttyfax.c --- v2.2.17/drivers/isdn/isdn_ttyfax.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_ttyfax.c Sat Sep 23 13:15:35 2000 @@ -1,4 +1,5 @@ -/* $Id: isdn_ttyfax.c,v 1.6 2000/01/26 00:41:13 keil Exp $ +/* $Id: isdn_ttyfax.c,v 1.7 2000/05/11 22:29:21 kai Exp $ + * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). * * Copyright 1999 by Armin Schindler (mac@melware.de) @@ -19,30 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_ttyfax.c,v $ - * Revision 1.6 2000/01/26 00:41:13 keil - * add "00" as dummy msn in isdn_get_free_channel call - * - * Revision 1.5 2000/01/20 19:55:33 keil - * Add FAX Class 1 support - * - * Revision 1.4 1999/09/21 19:00:35 armin - * Extended FCON message with added CPN - * can now be activated with Bit 1 of Reg 23. - * - * Revision 1.3 1999/08/22 20:26:12 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.2 1999/08/05 10:36:10 armin - * Bugfix: kernel oops on getting revision. - * - * Revision 1.1 1999/07/31 12:59:50 armin - * Added tty fax capabilities. - * - * */ #undef ISDN_TTY_FAX_STAT_DEBUG @@ -56,7 +33,7 @@ #include "isdn_ttyfax.h" -static char *isdn_tty_fax_revision = "$Revision: 1.6 $"; +static char *isdn_tty_fax_revision = "$Revision: 1.7 $"; #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_ttyfax.h linux/drivers/isdn/isdn_ttyfax.h --- v2.2.17/drivers/isdn/isdn_ttyfax.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_ttyfax.h Sat Sep 23 13:15:36 2000 @@ -1,4 +1,5 @@ -/* $Id: isdn_ttyfax.h,v 1.1 1999/07/31 12:59:51 armin Exp $ +/* $Id: isdn_ttyfax.h,v 1.2 2000/05/11 22:29:21 kai Exp $ + * header for Linux ISDN subsystem, tty_fax related functions (linklevel). * * Copyright 1999 by Armin Schindler (mac@melware.de) @@ -18,11 +19,6 @@ * 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. - * - * $Log: isdn_ttyfax.h,v $ - * Revision 1.1 1999/07/31 12:59:51 armin - * Added tty fax capabilities. - * * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_v110.c linux/drivers/isdn/isdn_v110.c --- v2.2.17/drivers/isdn/isdn_v110.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_v110.c Sat Sep 23 13:15:36 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_v110.c,v 1.4 2000/03/16 16:34:12 kai Exp $ +/* $Id: isdn_v110.c,v 1.5 2000/05/11 22:29:21 kai Exp $ * Linux ISDN subsystem, V.110 related functions (linklevel). * @@ -18,22 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdn_v110.c,v $ - * Revision 1.4 2000/03/16 16:34:12 kai - * some translation work - * - * there shouldn't be any German comments lurking around anymore ;-) - * - * Revision 1.3 1999/10/30 09:49:28 keil - * Reinit of v110 structs - * - * Revision 1.2 1998/02/22 19:44:25 fritz - * Bugfixes and improvements regarding V.110, V.110 now running. - * - * Revision 1.1 1998/02/20 17:32:09 fritz - * First checkin (not yet completely functionable). - * */ + #include #include #include @@ -44,7 +30,7 @@ #undef ISDN_V110_DEBUG -char *isdn_v110_revision = "$Revision: 1.4 $"; +char *isdn_v110_revision = "$Revision: 1.5 $"; #define V110_38400 255 #define V110_19200 15 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_v110.h linux/drivers/isdn/isdn_v110.h --- v2.2.17/drivers/isdn/isdn_v110.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_v110.h Sat Sep 23 13:15:36 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_v110.h,v 1.3 2000/03/16 16:34:12 kai Exp $ +/* $Id: isdn_v110.h,v 1.4 2000/05/11 22:29:21 kai Exp $ * Linux ISDN subsystem, V.110 related functions (linklevel). * @@ -17,18 +17,6 @@ * 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. - * - * $Log: isdn_v110.h,v $ - * Revision 1.3 2000/03/16 16:34:12 kai - * some translation work - * - * there shouldn't be any German comments lurking around anymore ;-) - * - * Revision 1.2 1999/10/30 09:49:28 keil - * Reinit of v110 structs - * - * Revision 1.1 1998/02/20 17:32:11 fritz - * First checkin (not yet completely functionable). * */ #ifndef _isdn_v110_h_ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_x25iface.c linux/drivers/isdn/isdn_x25iface.c --- v2.2.17/drivers/isdn/isdn_x25iface.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdn_x25iface.c Sat Sep 23 13:15:36 2000 @@ -1,4 +1,23 @@ -/* $Id: isdn_x25iface.c,v 1.7 1999/08/22 20:26:13 calle Exp $ +/* $Id: isdn_x25iface.c,v 1.9 2000/05/16 20:52:10 keil Exp $ + + * + * Linux ISDN subsystem, X.25 related functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * * stuff needed to support the Linux X.25 PLP code on top of devices that * can provide a lab_b service using the concap_proto mechanism. * This module supports a network interface wich provides lapb_sematics @@ -8,33 +27,6 @@ * * Only protocol specific stuff goes here. Device specific stuff * goes to another -- device related -- concap_proto support source file. - * - * $Log: isdn_x25iface.c,v $ - * Revision 1.7 1999/08/22 20:26:13 calle - * backported changes from kernel 2.3.14: - * - several #include "config.h" gone, others come. - * - "struct device" changed to "struct net_device" in 2.3.14, added a - * define in isdn_compat.h for older kernel versions. - * - * Revision 1.6 1999/01/27 22:53:19 he - * minor updates (spellings, jiffies wrap around in isdn_tty) - * - * Revision 1.5 1998/10/30 17:55:39 he - * dialmode for x25iface and multulink ppp - * - * Revision 1.4 1998/06/17 19:51:00 he - * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) - * brute force fix to avoid Ugh's in isdn_tty_write() - * cleaned up some dead code - * - * Revision 1.3 1998/02/20 17:25:20 fritz - * Changes for recent kernels. - * - * Revision 1.2 1998/01/31 22:49:22 keil - * correct comments - * - * Revision 1.1 1998/01/31 22:27:58 keil - * New files from Henner Eisen for X.25 support * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdn_x25iface.h linux/drivers/isdn/isdn_x25iface.h --- v2.2.17/drivers/isdn/isdn_x25iface.h Wed May 3 22:33:38 2000 +++ linux/drivers/isdn/isdn_x25iface.h Sat Dec 9 21:35:36 2000 @@ -1,5 +1,23 @@ -/* $Id: isdn_x25iface.h,v 1.2 1998/01/31 22:49:23 keil Exp $ +/* $Id: isdn_x25iface.h,v 1.3 2000/05/11 22:29:21 kai Exp $ + + * header for Linux ISDN subsystem, x.25 related functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * */ + #ifndef _LINUX_ISDN_X25IFACE_H #define _LINUX_ISDN_X25IFACE_H diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c --- v2.2.17/drivers/isdn/isdnloop/isdnloop.c Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdnloop/isdnloop.c Sat Nov 18 00:59:52 2000 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.c,v 1.9 1999/09/06 07:29:36 fritz Exp $ +/* $Id: isdnloop.c,v 1.11 2000/11/13 22:51:50 kai Exp $ * ISDN low-level module implementing a dummy loop driver. * @@ -18,48 +18,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Log: isdnloop.c,v $ - * Revision 1.9 1999/09/06 07:29:36 fritz - * Changed my mail-address. - * - * Revision 1.8 1998/11/18 18:59:43 armin - * changes for 2.1.127 - * - * Revision 1.7 1998/10/30 18:58:03 he - * typecast to suppress a compiler warning - * - * Revision 1.6 1998/06/17 19:51:37 he - * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay()) - * brute force fix to avoid Ugh's in isdn_tty_write() - * cleaned up some dead code - * - * Revision 1.5 1998/04/14 20:59:32 he - * merged 2.1.94 changes - * - * Revision 1.4 1998/02/24 21:39:05 he - * L2_PROT_X25DTE / DCE - * additional state 17 and new internal signal messages "BCON_I" - * (for reliable connect confirmation primitive as needed by x.25 upper layer) - * Changes for new LL-HL interface - * - * Revision 1.3 1998/02/20 17:33:30 fritz - * Changes for recent kernels. - * - * Revision 1.2 1997/10/01 09:22:03 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/24 23:02:04 fritz - * Added isdnloop driver. - * */ #include #include "isdnloop.h" static char -*revision = "$Revision: 1.9 $"; +*revision = "$Revision: 1.11 $"; static int isdnloop_addcard(char *); @@ -865,6 +830,7 @@ if (card->rcard[ch - 1]) { isdnloop_fake(card->rcard[ch - 1], "BCON_I", card->rch[ch - 1] + 1); + isdnloop_fake(card, "BCON_C", ch); } break; case 17: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h --- v2.2.17/drivers/isdn/isdnloop/isdnloop.h Fri Apr 21 12:46:12 2000 +++ linux/drivers/isdn/isdnloop/isdnloop.h Sat Nov 18 00:59:52 2000 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.h,v 1.4 1999/09/06 07:29:36 fritz Exp $ +/* $Id: isdnloop.h,v 1.5 2000/11/13 22:51:50 kai Exp $ * Loopback lowlevel module for testing of linklevel. * @@ -17,21 +17,6 @@ * 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. - * - * $Log: isdnloop.h,v $ - * Revision 1.4 1999/09/06 07:29:36 fritz - * Changed my mail-address. - * - * Revision 1.3 1998/04/14 20:59:35 he - * merged 2.1.94 changes - * - * Revision 1.2 1997/10/01 09:22:07 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/24 23:02:05 fritz - * Added isdnloop driver. * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile --- v2.2.17/drivers/macintosh/Makefile Sat Sep 9 18:42:38 2000 +++ linux/drivers/macintosh/Makefile Wed Nov 8 23:00:34 2000 @@ -12,16 +12,16 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -L_TARGET := macintosh.a +O_TARGET := macintosh.o M_OBJS := ifndef CONFIG_MBX -L_OBJS := via-cuda.o macio-adb.o via-pmu.o mediabay.o -LX_OBJS := adb.o +O_OBJS := via-cuda.o macio-adb.o via-pmu.o mediabay.o +OX_OBJS := adb.o endif ifeq ($(CONFIG_MAC_SERIAL),y) - L_OBJS += macserial.o + O_OBJS += macserial.o else ifeq ($(CONFIG_MAC_SERIAL),m) M_OBJS += macserial.o @@ -29,7 +29,7 @@ endif ifeq ($(CONFIG_NVRAM),y) - L_OBJS += nvram.o + O_OBJS += nvram.o else ifeq ($(CONFIG_NVRAM),m) M_OBJS += nvram.o @@ -37,7 +37,7 @@ endif ifeq ($(CONFIG_PPC_RTC),y) - L_OBJS += rtc.o + O_OBJS += rtc.o else ifeq ($(CONFIG_PPC_RTC),m) M_OBJS += rtc.o @@ -45,7 +45,13 @@ endif ifdef CONFIG_MAC_KEYBOARD -L_OBJS += mac_keyb.o + O_OBJS += mac_keyb.o +endif +ifdef CONFIG_INPUT_ADBHID + O_OBJS += adbhid.o +endif +ifdef CONFIG_MAC_HID + O_OBJS += mac_hid.o endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c --- v2.2.17/drivers/macintosh/adb.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/macintosh/adb.c Wed Nov 8 23:00:34 2000 @@ -25,13 +25,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include EXPORT_SYMBOL(adb_controller); EXPORT_SYMBOL(adb_client_list); @@ -390,7 +390,7 @@ #define ADB_MAJOR 56 /* major number for /dev/adb */ -extern void adbdev_init(void); +extern int adbdev_init(void); struct adbdev_state { spinlock_t lock; @@ -601,10 +601,19 @@ adb_release }; -void adbdev_init() +static int __init adbdev_init(void) { - if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + if (adb_controller == NULL) + return 0; if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); + return 0; } + +static void adbdev_cleanup(void) +{ + unregister_chrdev(ADB_MAJOR, "adb"); +} + +module_init(adbdev_init); +module_exit(adbdev_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/adbhid.c linux/drivers/macintosh/adbhid.c --- v2.2.17/drivers/macintosh/adbhid.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/macintosh/adbhid.c Wed Nov 8 23:00:34 2000 @@ -0,0 +1,875 @@ +/* + * drivers/input/adbhid.c + * + * ADB HID driver for Power Macintosh computers. + * + * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl + * (see that file for its authors and contributors). + * + * Copyright (C) 2000 Franz Sirl. + * + * Adapted to ADB changes and support for more devices by + * Benjamin Herrenschmidt. Adapted from code in MkLinux + * and reworked. + * + * Supported devices: + * + * - Standard 1 button mouse + * - All standard Apple Extended protocol (handler ID 4) + * - mouseman and trackman mice & trackballs + * - PowerBook Trackpad (default setup: enable tapping) + * - MicroSpeed mouse & trackball (needs testing) + * - CH Products Trackball Pro (needs testing) + * - Contour Design (Contour Mouse) + * - Hunter digital (NoHandsMouse) + * - Kensignton TurboMouse 5 (needs testing) + * - Mouse Systems A3 mice and trackballs + * - MacAlly 2-buttons mouse (needs testing) + * + * To do: + * + * Improve Kensington support. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + +MODULE_AUTHOR("Franz Sirl "); + +#define KEYB_KEYREG 0 /* register # for key up/down data */ +#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ +#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ + +static int adb_message_handler(struct notifier_block *, unsigned long, void *); +static struct notifier_block adbhid_adb_notifier = { + notifier_call: adb_message_handler, +}; + +unsigned char adb_to_linux_keycodes[128] = { + 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19, + 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24, + 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52, + 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0, + 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, + 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124, + 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88, + 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116 +}; + +struct adbhid { + struct input_dev input; + int id; + int default_id; + int original_handler_id; + int current_handler_id; + int mouse_kind; + unsigned char *keycode; + char name[64]; +}; + +static struct adbhid *adbhid[16] = { 0 }; + +static void adbhid_probe(void); + +static void adbhid_input_keycode(int, int, int); +static void leds_done(struct adb_request *); + +static void init_trackpad(int id); +static void init_trackball(int id); +static void init_turbomouse(int id); +static void init_microspeed(int id); +static void init_ms_a3(int id); + +static struct adb_ids keyboard_ids; +static struct adb_ids mouse_ids; +static struct adb_ids buttons_ids; + +/* Kind of keyboard, see Apple technote 1152 */ +#define ADB_KEYBOARD_UNKNOWN 0 +#define ADB_KEYBOARD_ANSI 0x0100 +#define ADB_KEYBOARD_ISO 0x0200 +#define ADB_KEYBOARD_JIS 0x0300 + +/* Kind of mouse */ +#define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */ +#define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */ +#define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */ +#define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */ +#define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */ +#define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */ +#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */ +#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */ +#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */ +#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */ + +static void +adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n", + id, data[0], data[1], data[2], data[3]); + return; + } + + /* first check this is from register 0 */ + if (nb != 3 || (data[0] & 3) != KEYB_KEYREG) + return; /* ignore it */ + kbd_pt_regs = regs; + adbhid_input_keycode(id, data[1], 0); + if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f))) + adbhid_input_keycode(id, data[2], 0); +} + +static void +adbhid_input_keycode(int id, int keycode, int repeat) +{ + int up_flag; + + up_flag = (keycode & 0x80); + keycode &= 0x7f; + + switch (keycode) { + case 0x39: /* Generate down/up events for CapsLock everytime. */ + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1); + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0); + return; + case 0x3f: /* ignore Powerbook Fn key */ + return; + } + + if (adbhid[id]->keycode[keycode]) + input_report_key(&adbhid[id]->input, + adbhid[id]->keycode[keycode], !up_flag); + else + printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, + up_flag ? "released" : "pressed"); +} + +static void +adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + /* + Handler 1 -- 100cpi original Apple mouse protocol. + Handler 2 -- 200cpi original Apple mouse protocol. + + For Apple's standard one-button mouse protocol the data array will + contain the following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx First button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + + Handler 4 -- Apple Extended mouse protocol. + + For Apple's 3-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + data[3] = byyy bxxx Third button and fourth button. Y is additional + high bits of y-axis motion. XY is additional + high bits of x-axis motion. + + MacAlly 2-button mouse protocol. + + For MacAlly 2-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Right button and y-axis motion. + data[3] = ???? ???? unknown + data[4] = ???? ???? unknown + + */ + + /* If it's a trackpad, we alias the second button to the first. + NOTE: Apple sends an ADB flush command to the trackpad when + the first (the real) button is released. We could do + this here using async flush requests. + */ + switch (adbhid[id]->mouse_kind) + { + case ADBMOUSE_TRACKPAD: + data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80); + data[2] = data[2] | 0x80; + break; + case ADBMOUSE_MICROSPEED: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5) + | (data[3] & 0x08); + break; + case ADBMOUSE_TRACKBALLPRO: + data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5) + & ((data[3] & 0x08) << 4)); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7); + data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); + break; + case ADBMOUSE_MS_A3: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = ((data[3] & 0x04) << 5); + break; + case ADBMOUSE_MACALLY2: + data[3] = (data[2] & 0x80) ? 0x80 : 0x00; + data[2] |= 0x80; /* Right button is mapped as button 3 */ + nb=4; + break; + } + + input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); + input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); + + if (nb >= 4) + input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); + + input_report_rel(&adbhid[id]->input, REL_X, + ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); + input_report_rel(&adbhid[id]->input, REL_Y, + ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); +} + +static void +adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + switch (adbhid[id]->original_handler_id) { + default: + case 0x02: /* Adjustable keyboard button device */ + printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); + break; + case 0x1f: /* Powerbook button device */ + { +#ifdef CONFIG_PMAC_BACKLIGHT + int backlight = get_backlight_level(); + + /* + * XXX: Where is the contrast control for the passive? + * -- Cort + */ + + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) + break; + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) + break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; + } +#endif /* CONFIG_PMAC_BACKLIGHT */ + } + break; + } +} + +static struct adb_request led_request; +static int leds_pending[16]; +static int pending_devs[16]; +static int pending_led_start=0; +static int pending_led_end=0; + +static void real_leds(unsigned char leds, int device) +{ + if (led_request.complete) { + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, + ~leds); + } else { + if (!(leds_pending[device] & 0x100)) { + pending_devs[pending_led_end] = device; + pending_led_end++; + pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + } + leds_pending[device] = leds | 0x100; + } +} + +/* + * Event callback from the input module. Events that change the state of + * the hardware are processed here. + */ +static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct adbhid *adbhid = dev->private; + unsigned char leds; + + switch (type) { + case EV_LED: + leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) + | (test_bit(LED_NUML, dev->led) ? 1 : 0) + | (test_bit(LED_CAPSL, dev->led) ? 2 : 0); + real_leds(leds, adbhid->id); + return 0; + } + + return -1; +} + +static void leds_done(struct adb_request *req) +{ + int leds,device; + + if (pending_led_start != pending_led_end) { + device = pending_devs[pending_led_start]; + leds = leds_pending[device] & 0xff; + leds_pending[device] = 0; + pending_led_start++; + pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + real_leds(leds,device); + } + +} + +static int +adb_message_handler(struct notifier_block *this, unsigned long code, void *x) +{ + unsigned long flags; + + switch (code) { + case ADB_MSG_PRE_RESET: + case ADB_MSG_POWERDOWN: + /* Stop the repeat timer. Autopoll is already off at this point */ + save_flags(flags); + cli(); + { + int i; + for (i = 1; i < 16; i++) { + if (adbhid[i]) + del_timer(&adbhid[i]->input.timer); + } + } + restore_flags(flags); + + /* Stop pending led requests */ + while(!led_request.complete) + adb_poll(); + break; + + case ADB_MSG_POST_RESET: + adbhid_probe(); + break; + } + return NOTIFY_DONE; +} + +static void +adbhid_input_register(int id, int default_id, int original_handler_id, + int current_handler_id, int mouse_kind) +{ + int i; + + if (adbhid[id]) { + printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id); + return; + } + + if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL))) + return; + + memset(adbhid[id], 0, sizeof(struct adbhid)); + + adbhid[id]->id = default_id; + adbhid[id]->original_handler_id = original_handler_id; + adbhid[id]->current_handler_id = current_handler_id; + adbhid[id]->mouse_kind = mouse_kind; + adbhid[id]->input.private = adbhid[id]; + adbhid[id]->input.name = adbhid[id]->name; + adbhid[id]->input.idbus = BUS_ADB; + adbhid[id]->input.idvendor = 0x0001; + adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id; + adbhid[id]->input.idversion = 0x0100; + + switch (default_id) { + case ADB_KEYBOARD: + if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) { + kfree(adbhid[id]); + return; + } + + sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x", + id, default_id, original_handler_id); + + memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); + + printk(KERN_INFO "Detected ADB keyboard, type "); + switch (original_handler_id) { + default: + printk(".\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN; + break; + + case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: + case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: + case 0xC0: case 0xC3: case 0xC6: + printk("ANSI.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI; + break; + + case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: + case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: + case 0xC4: case 0xC7: + printk("ISO, swapping keys.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ISO; + i = adbhid[id]->keycode[10]; + adbhid[id]->keycode[10] = adbhid[id]->keycode[50]; + adbhid[id]->keycode[50] = i; + break; + + case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: + case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: + printk("JIS.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_JIS; + break; + } + + for (i = 0; i < 128; i++) + if (adbhid[id]->keycode[i]) + set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); + adbhid[id]->input.event = adbhid_kbd_event; + adbhid[id]->input.keycodemax = 127; + adbhid[id]->input.keycodesize = 1; + break; + + case ADB_MOUSE: + sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x", + id, default_id, original_handler_id); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y); + break; + + case ADB_MISC: + switch (original_handler_id) { + case 0x02: /* Adjustable keyboard button device */ + sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + case 0x1f: /* Powerbook button device */ + sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + } + if (adbhid[id]->name[0]) + break; + /* else fall through */ + + default: + printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n"); + kfree(adbhid[id]); + return; + } + + adbhid[id]->input.keycode = adbhid[id]->keycode; + + input_register_device(&adbhid[id]->input); + + printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n", + adbhid[id]->input.number, id, default_id, original_handler_id); + + if (default_id == ADB_KEYBOARD) { + /* HACK WARNING!! This should go away as soon there is an utility + * to control that for event devices. + */ + adbhid[id]->input.rep[REP_DELAY] = HZ/2; /* input layer default: HZ/4 */ + adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */ + } +} + +static void adbhid_input_unregister(int id) +{ + input_unregister_device(&adbhid[id]->input); + if (adbhid[id]->keycode) + kfree(adbhid[id]->keycode); + kfree(adbhid[id]); + adbhid[id] = 0; +} + + +static void +adbhid_probe(void) +{ + struct adb_request req; + int i, default_id, org_handler_id, cur_handler_id; + + for (i = 1; i < 16; i++) { + if (adbhid[i]) + adbhid_input_unregister(i); + } + + adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input); + adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input); + adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input); + + for (i = 0; i < keyboard_ids.nids; i++) { + int id = keyboard_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + + /* turn off all leds */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff); + + /* Enable full feature set of the keyboard + ->get it to send separate codes for left and right shift, + control, option keys */ +#if 0 /* handler 5 doesn't send separate codes for R modifiers */ + if (adb_try_handler_change(id, 5)) + printk("ADB keyboard at %d, handler set to 5\n", id); + else +#endif + if (adb_try_handler_change(id, 3)) + printk("ADB keyboard at %d, handler set to 3\n", id); + else + printk("ADB keyboard at %d, handler 1\n", id); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0); + } + + for (i = 0; i < buttons_ids.nids; i++) { + int id = buttons_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0); + } + + /* Try to switch all mice to handler 4, or 2 for three-button + mode and full resolution. */ + for (i = 0; i < mouse_ids.nids; i++) { + int id = mouse_ids.id[i]; + int mouse_kind; + + adb_get_infos(id, &default_id, &org_handler_id); + + if (adb_try_handler_change(id, 4)) { + printk("ADB mouse at %d, handler set to 4", id); + mouse_kind = ADBMOUSE_EXTENDED; + } + else if (adb_try_handler_change(id, 0x2F)) { + printk("ADB mouse at %d, handler set to 0x2F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x42)) { + printk("ADB mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_TRACKBALLPRO; + } + else if (adb_try_handler_change(id, 0x66)) { + printk("ADB mouse at %d, handler set to 0x66", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x5F)) { + printk("ADB mouse at %d, handler set to 0x5F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 3)) { + printk("ADB mouse at %d, handler set to 3", id); + mouse_kind = ADBMOUSE_MS_A3; + } + else if (adb_try_handler_change(id, 2)) { + printk("ADB mouse at %d, handler set to 2", id); + mouse_kind = ADBMOUSE_STANDARD_200; + } + else { + printk("ADB mouse at %d, handler 1", id); + mouse_kind = ADBMOUSE_STANDARD_100; + } + + if ((mouse_kind == ADBMOUSE_TRACKBALLPRO) + || (mouse_kind == ADBMOUSE_MICROSPEED)) { + init_microspeed(id); + } else if (mouse_kind == ADBMOUSE_MS_A3) { + init_ms_a3(id); + } else if (mouse_kind == ADBMOUSE_EXTENDED) { + /* + * Register 1 is usually used for device + * identification. Here, we try to identify + * a known device and call the appropriate + * init function. + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id, 1)); + + if ((req.reply_len) && + (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) + || (req.reply[2] == 0x20))) { + mouse_kind = ADBMOUSE_TRACKBALL; + init_trackball(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && + (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) { + mouse_kind = ADBMOUSE_TRACKPAD; + init_trackpad(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) && + (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) { + mouse_kind = ADBMOUSE_TURBOMOUSE5; + init_turbomouse(id); + } + else if ((req.reply_len == 9) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) && + (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) { + if (adb_try_handler_change(id, 0x42)) { + printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_MACALLY2; + } + } + } + printk("\n"); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mouse_kind); + } +} + +static void +init_trackpad(int id) +{ + struct adb_request req; + unsigned char r1_buffer[8]; + + printk(" (trackpad)"); + + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id,1)); + if (req.reply_len < 8) + printk("bad length for reg. 1\n"); + else + { + memcpy(r1_buffer, &req.reply[1], 8); + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x0d, /*r1_buffer[6],*/ + r1_buffer[7]); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,2), + 0x99, + 0x94, + 0x19, + 0xff, + 0xb2, + 0x8a, + 0x1b, + 0x50); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x03, /*r1_buffer[6],*/ + r1_buffer[7]); + } +} + +static void +init_trackball(int id) +{ + struct adb_request req; + + printk(" (trackman/mouseman)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); +} + +static void +init_turbomouse(int id) +{ + struct adb_request req; + + printk(" (TurboMouse 5)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xe7, + 0x8c, + 0, + 0, + 0, + 0xff, + 0xff, + 0x94); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xa5, + 0x14, + 0, + 0, + 0x69, + 0xff, + 0xff, + 0x27); +} + +static void +init_microspeed(int id) +{ + struct adb_request req; + + printk(" (Microspeed/MacPoint or compatible)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + /* This will initialize mice using the Microspeed, MacPoint and + other compatible firmware. Bit 12 enables extended protocol. + + Register 1 Listen (4 Bytes) + 0 - 3 Button is mouse (set also for double clicking!!!) + 4 - 7 Button is locking (affects change speed also) + 8 - 11 Button changes speed + 12 1 = Extended mouse mode, 0 = normal mouse mode + 13 - 15 unused 0 + 16 - 23 normal speed + 24 - 31 changed speed + + Register 1 talk holds version and product identification information. + Register 1 Talk (4 Bytes): + 0 - 7 Product code + 8 - 23 undefined, reserved + 24 - 31 Version number + + Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max. + */ + adb_request(&req, NULL, ADBREQ_SYNC, 5, + ADB_WRITEREG(id,1), + 0x20, /* alt speed = 0x20 (rather slow) */ + 0x00, /* norm speed = 0x00 (fastest) */ + 0x10, /* extended protocol, no speed change */ + 0x07); /* all buttons enabled as mouse buttons, no locking */ + + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static void +init_ms_a3(int id) +{ + struct adb_request req; + + printk(" (Mouse Systems A3 Mouse, or compatible)"); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, 0x2), + 0x00, + 0x07); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static int __init adbhid_init(void) +{ + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return 0; + + led_request.complete = 1; + + adbhid_probe(); + + notifier_chain_register(&adb_client_list, &adbhid_adb_notifier); + + return 0; +} + +static void adbhid_exit(void) +{ +} + +module_init(adbhid_init); +module_exit(adbhid_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/mac_hid.c linux/drivers/macintosh/mac_hid.c --- v2.2.17/drivers/macintosh/mac_hid.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/macintosh/mac_hid.c Wed Nov 8 23:00:34 2000 @@ -0,0 +1,492 @@ +/* + * drivers/macintosh/mac_hid.c + * + * HID support stuff for Macintosh computers. + * + * Copyright (C) 2000 Franz Sirl. + * + * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all + * major distributions are using the Linux keycodes. + * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_MAC_ADBKEYCODES +#include +#include +#include +#endif + +#ifdef CONFIG_MAC_ADBKEYCODES +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char mac_hid_kbd_sysrq_xlate[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80o]" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\000\033\000\000\000\000\000\000\000\000\000\000" + /* 0x30 - 0x3f */ + "\000\000\000*\000+\000\000\000\000\000/\r\000-\000" + /* 0x40 - 0x4f */ + "\000\0000123456789\000\000\000" /* 0x50 - 0x5f */ + "\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214"; + /* 0x60 - 0x6f */ +extern unsigned char pckbd_sysrq_xlate[128]; +#endif + +static u_short macplain_map[NR_KEYS] = { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macaltgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c, +}; + +static u_short macalt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = { + macplain_map, macshift_map, macaltgr_map, 0, + macctrl_map, macshift_ctrl_map, 0, 0, + macalt_map, 0, 0, 0, + macctrl_alt_map, 0 +}; + +static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS]; + +int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); +static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp); +char mac_hid_kbd_unexpected_up(unsigned char keycode); + +static int keyboard_lock_keycodes = 0; +int keyboard_sends_linux_keycodes = 0; +#else +int keyboard_sends_linux_keycodes = 1; +#endif /* CONFIG_MAC_ADBKEYCODES */ + + +static unsigned char e0_keys[128] = { + 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */ + KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */ + KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */ + KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +#ifdef CONFIG_MAC_EMUMOUSEBTN +static struct input_dev emumousebtn; +static void emumousebtn_input_register(void); +static int mouse_emulate_buttons = 0; +static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ +static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ +static int mouse_last_keycode = 0; +#endif + +extern void pckbd_init_hw(void); + +#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) +/* file(s) in /proc/sys/dev/mac_hid */ +ctl_table mac_hid_files[] = +{ +#ifdef CONFIG_MAC_ADBKEYCODES + { + DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES, + "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int), + 0644, NULL, &mac_hid_sysctl_keycodes + }, + { + DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES, + "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif +#ifdef CONFIG_MAC_EMUMOUSEBTN + { + DEV_MAC_HID_MOUSE_BUTTON_EMULATION, + "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE, + "mouse_button2_keycode", &mouse_button2_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE, + "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif + { 0 } +}; + +/* dir in /proc/sys/dev */ +ctl_table mac_hid_dir[] = +{ + { DEV_MAC_HID, "mac_hid", NULL, 0, 0555, mac_hid_files }, + { 0 } +}; + +/* /proc/sys/dev itself, in case that is not there yet */ +ctl_table mac_hid_root_dir[] = +{ + { CTL_DEV, "dev", NULL, 0, 0555, mac_hid_dir }, + { 0 } +}; + +static struct ctl_table_header *mac_hid_sysctl_header; + +#ifdef CONFIG_MAC_ADBKEYCODES +static +int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int val = keyboard_sends_linux_keycodes; + int ret = 0; + + if (!write + || (write && !keyboard_lock_keycodes)) + ret = proc_dointvec(ctl, write, filp, buffer, lenp); + + if (write + && keyboard_sends_linux_keycodes != val) { + if (!keyboard_sends_linux_keycodes) { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); + } else { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; +#endif + memcpy(mac_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, pc_key_maps_save, sizeof(key_maps)); + } + } + + return ret; +} +#endif +#endif /* endif CONFIG_SYSCTL */ + +int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + if (!raw_mode) { + /* + * Convert R-shift/control/option to L version. + */ + switch (scancode) { + case 0x7b: scancode = 0x38; break; /* R-shift */ + case 0x7c: scancode = 0x3a; break; /* R-option */ + case 0x7d: scancode = 0x36; break; /* R-control */ + } + } + *keycode = scancode; + return 1; + } else +#endif + { + /* This code was copied from char/pc_keyb.c and will be + * superflous when the input layer is fully integrated. + * We don't need the high_keys handling, so this part + * has been removed. + */ + static int prev_scancode = 0; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + scancode &= 0x7f; + + if (prev_scancode) { + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = KEY_PAUSE; + prev_scancode = 0; + } else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + if (scancode == 0x2a || scancode == 0x36) + return 0; + } + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); + return 0; + } + } else { + switch (scancode) { + case 91: scancode = KEY_LINEFEED; break; + case 92: scancode = KEY_KPEQUAL; break; + case 125: scancode = KEY_INTL1; break; + } + *keycode = scancode; + } + return 1; + } +} + +char mac_hid_kbd_unexpected_up(unsigned char keycode) +{ + if (keyboard_sends_linux_keycodes && keycode == KEY_F13) + return 0; + else + return 0x80; +} + +#ifdef CONFIG_MAC_ADBKEYCODES +int mac_hid_keyboard_sends_linux_keycodes(void) +{ + return keyboard_sends_linux_keycodes; +} + +static int __init mac_hid_setup(char *str) +{ + int ints[11]; + + str = get_options(str, ints); + if (ints[0] == 1) { + keyboard_sends_linux_keycodes = ints[1] != 0; + keyboard_lock_keycodes = 1; + } + return 1; +} + +__setup("keyboard_sends_linux_keycodes=", mac_hid_setup); + +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN +int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) +{ + switch (caller) { + case 1: + /* Called from keybdev.c */ + if (mouse_emulate_buttons + && (keycode == mouse_button2_keycode + || keycode == mouse_button3_keycode)) { + if (mouse_emulate_buttons == 1) { + input_report_key(&emumousebtn, + keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, + down); + return 1; + } + mouse_last_keycode = down ? keycode : 0; + } + break; + case 2: + /* Called from mousedev.c */ + if (mouse_emulate_buttons == 2 && keycode == 0) { + if (mouse_last_keycode == mouse_button2_keycode) + return 1; /* map to middle button */ + if (mouse_last_keycode == mouse_button3_keycode) + return 2; /* map to right button */ + } + return keycode; /* keep button */ + } + return 0; +} + +static void emumousebtn_input_register(void) +{ + emumousebtn.name = "Macintosh mouse button emulation"; + + emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y); + + emumousebtn.idbus = BUS_ADB; + emumousebtn.idvendor = 0x0001; + emumousebtn.idproduct = 0x0001; + emumousebtn.idversion = 0x0100; + + input_register_device(&emumousebtn); + + printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number); +} +#endif + +void __init mac_hid_init_hw(void) +{ + +#ifdef CONFIG_MAC_ADBKEYCODES + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + + if (!keyboard_sends_linux_keycodes) + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN + emumousebtn_input_register(); +#endif + +#if CONFIG_PPC + if (_machine != _MACH_Pmac) + pckbd_init_hw(); +#endif + +#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) + mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); +#endif /* CONFIG_SYSCTL */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.2.17/drivers/macintosh/mac_keyb.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/macintosh/mac_keyb.c Wed Nov 8 23:00:34 2000 @@ -16,7 +16,7 @@ * * - Standard 1 button mouse * - All standard Apple Extended protocol (handler ID 4) - * - mouseman and trackman mice & trackballs + * - mouseman and trackman mice & trackballs * - PowerBook Trackpad (default setup: enable tapping) * - MicroSpeed mouse & trackball (needs testing) * - CH Products Trackball Pro (needs testing) @@ -48,10 +48,16 @@ #include #include #include +#include +#include #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #define KEYB_KEYREG 0 /* register # for key up/down data */ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ @@ -226,7 +232,7 @@ static void kbd_repeat(unsigned long); -static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; +static struct timer_list repeat_timer = { function: kbd_repeat }; static int last_keycode; static void mackeyb_probe(void); @@ -347,7 +353,7 @@ #ifdef CONFIG_ADBMOUSE /* * XXX: Add mouse button 2+3 fake codes here if mouse open. - * Keep track of 'button' states here as we only send + * Keep track of 'button' states here as we only send * single up/down events! * Really messy; might need to check if keyboard is in * VC_RAW mode. @@ -587,61 +593,47 @@ } #endif /* CONFIG_ADBMOUSE */ -/* XXX Needs to get rid of this, see comments in pmu.c */ -extern int backlight_level; - static void buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { + int backlight = get_backlight_level(); + /* * XXX: Where is the contrast control for the passive? * -- Cort */ - + /* Ignore data from register other than 0 */ - if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2)) + if ((data[0] & 0x3) || (nb < 2)) return; - switch (data[1]&0xf ) - { - /* mute */ - case 0x8: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast decrease */ - case 0x7: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast increase */ - case 0x6: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* brightness decrease */ - case 0xa: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level > 2) - pmu_set_brightness(backlight_level-2); - else - pmu_set_brightness(0); - } + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) break; - /* brightness increase */ - case 0x9: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level < 0x1e) - pmu_set_brightness(backlight_level+2); - else - pmu_set_brightness(0x1f); - } + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; } } @@ -702,10 +694,10 @@ } -__initfunc(void mackbd_init_hw(void)) +void __init mackbd_init_hw(void) { if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + return; /* setup key map */ memcpy(key_maps[0], macplain_map, sizeof(plain_map)); @@ -736,7 +728,7 @@ switch (code) { case ADB_MSG_PRE_RESET: case ADB_MSG_POWERDOWN: - /* Stop the repeat timer. Autopoll is already off at this point */ + /* Stop the repeat timer. Autopoll is already off at this point */ save_flags(flags); cli(); del_timer(&repeat_timer); @@ -842,7 +834,7 @@ if ((req.reply_len) && (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) - || (req.reply[2] == 0x20))) + || (req.reply[2] == 0x20))) init_trackball(id); else if ((req.reply_len >= 4) && (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && @@ -865,7 +857,7 @@ } } -static void +static void init_trackpad(int id) { struct adb_request req; @@ -895,15 +887,15 @@ adb_request(&req, NULL, ADBREQ_SYNC, 9, ADB_WRITEREG(id,2), - 0x99, - 0x94, - 0x19, - 0xff, - 0xb2, - 0x8a, - 0x1b, - 0x50); - + 0x99, + 0x94, + 0x19, + 0xff, + 0xb2, + 0x8a, + 0x1b, + 0x50); + adb_request(&req, NULL, ADBREQ_SYNC, 9, ADB_WRITEREG(id,1), r1_buffer[0], @@ -917,7 +909,7 @@ } } -static void +static void init_trackball(int id) { struct adb_request req; @@ -1000,7 +992,7 @@ /* This will initialize mice using the Microspeed, MacPoint and other compatible firmware. Bit 12 enables extended protocol. - + Register 1 Listen (4 Bytes) 0 - 3 Button is mouse (set also for double clicking!!!) 4 - 7 Button is locking (affects change speed also) @@ -1015,7 +1007,7 @@ 0 - 7 Product code 8 - 23 undefined, reserved 24 - 31 Version number - + Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max. */ adb_request(&req, NULL, ADBREQ_SYNC, 5, @@ -1039,7 +1031,7 @@ ADB_WRITEREG(id, 0x2), 0x00, 0x07); - + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.2.17/drivers/macintosh/macserial.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/macintosh/macserial.c Wed Nov 8 23:00:34 2000 @@ -953,6 +953,67 @@ info->dma_initted = 1; } +/* + * FixZeroBug....Works around a bug in the SCC receving channel. + * Taken from Darwin code, 15 Sept. 2000 -DanM + * + * The following sequence prevents a problem that is seen with O'Hare ASICs + * (most versions -- also with some Heathrow and Hydra ASICs) where a zero + * at the input to the receiver becomes 'stuck' and locks up the receiver. + * This problem can occur as a result of a zero bit at the receiver input + * coincident with any of the following events: + * + * The SCC is initialized (hardware or software). + * A framing error is detected. + * The clocking option changes from synchronous or X1 asynchronous + * clocking to X16, X32, or X64 asynchronous clocking. + * The decoding mode is changed among NRZ, NRZI, FM0, or FM1. + * + * This workaround attempts to recover from the lockup condition by placing + * the SCC in synchronous loopback mode with a fast clock before programming + * any of the asynchronous modes. + */ +static void fix_zero_bug_scc(struct mac_serial * info) +{ + write_zsreg(info->zs_channel, 9, + (info->zs_channel == info->zs_chan_a? CHRA: CHRB)); + udelay(10); + write_zsreg(info->zs_channel, 9, + ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV)); + + write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC)); + + /* I think this is wrong....but, I just copying code.... + */ + write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE)); + + write_zsreg(info->zs_channel, 5, (8 & ~TxENAB)); + write_zsreg(info->zs_channel, 9, NV); /* Didn't we already do this? */ + write_zsreg(info->zs_channel, 11, (RCBR | TCBR)); + write_zsreg(info->zs_channel, 12, 0); + write_zsreg(info->zs_channel, 13, 0); + write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR)); + write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL)); + write_zsreg(info->zs_channel, 3, (8 | RxENABLE)); + write_zsreg(info->zs_channel, 0, RES_EXT_INT); + write_zsreg(info->zs_channel, 0, RES_EXT_INT); /* to kill some time */ + + /* The channel should be OK now, but it is probably receiving + * loopback garbage. + * Switch to asynchronous mode, disable the receiver, + * and discard everything in the receive buffer. + */ + write_zsreg(info->zs_channel, 9, NV); + write_zsreg(info->zs_channel, 4, PAR_ENA); + write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE)); + + while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) { + (void)read_zsreg(info->zs_channel, 8); + write_zsreg(info->zs_channel, 0, RES_EXT_INT); + write_zsreg(info->zs_channel, 0, ERR_RES); + } +} + static int setup_scc(struct mac_serial * info) { unsigned long flags; @@ -961,6 +1022,9 @@ save_flags(flags); cli(); /* Disable interrupts */ + /* Nice buggy HW ... */ + fix_zero_bug_scc(info); + /* * Reset the chip. */ @@ -1081,7 +1145,7 @@ info->curregs[5] &= ~TxENAB; if (!info->tty || C_HUPCL(info->tty)) - info->curregs[5] &= ~(DTR | RTS); + info->curregs[5] &= ~DTR; info->pendregs[5] = info->curregs[5]; write_zsreg(info->zs_channel, 5, info->curregs[5]); @@ -1253,7 +1317,7 @@ /* assert DTR, wait 30ms, talk to the chip */ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR); - udelay(30000); + mdelay(30); while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) read_zsdata(info->zs_channel); @@ -1592,17 +1656,35 @@ if (C_CRTSCTS(tty)) { /* * Here we want to turn off the RTS line. On Macintoshes, - * we only get the DTR line, which goes to both DTR and - * RTS on the modem. RTS doesn't go out to the serial - * port socket. So you should make sure your modem is - * set to ignore DTR if you're using CRTSCTS. + * the external serial ports using a DIN-8 or DIN-9 + * connector only have the DTR line (which is usually + * wired to both RTS and DTR on an external modem in + * the cable). RTS doesn't go out to the serial port + * socket, it acts as an output enable for the transmit + * data line. So in this case we don't drop RTS. + * + * Macs with internal modems generally do have both RTS + * and DTR wired to the modem, so in that case we do + * drop RTS. */ + if (info->is_internal_modem) { + save_flags(flags); cli(); + info->curregs[5] &= ~RTS; + info->pendregs[5] &= ~RTS; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + restore_flags(flags); + } + } + +#ifdef CDTRCTS + if (tty->termios->c_cflag & CDTRCTS) { save_flags(flags); cli(); - info->curregs[5] &= ~(DTR | RTS); - info->pendregs[5] &= ~(DTR | RTS); + info->curregs[5] &= ~DTR; + info->pendregs[5] &= ~DTR; write_zsreg(info->zs_channel, 5, info->curregs[5]); restore_flags(flags); } +#endif /* CDTRCTS */ } static void rs_unthrottle(struct tty_struct * tty) @@ -1629,14 +1711,25 @@ restore_flags(flags); } - if (C_CRTSCTS(tty)) { - /* Assert RTS and DTR lines */ + if (C_CRTSCTS(tty) && info->is_internal_modem) { + /* Assert RTS line */ save_flags(flags); cli(); - info->curregs[5] |= DTR | RTS; - info->pendregs[5] |= DTR | RTS; + info->curregs[5] |= RTS; + info->pendregs[5] |= RTS; write_zsreg(info->zs_channel, 5, info->curregs[5]); restore_flags(flags); } + +#ifdef CDTRCTS + if (tty->termios->c_cflag & CDTRCTS) { + /* Assert DTR line */ + save_flags(flags); cli(); + info->curregs[5] |= DTR; + info->pendregs[5] |= DTR; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + restore_flags(flags); + } +#endif } /* @@ -2311,6 +2404,7 @@ /* setup misc varariables */ zss->kgdb_channel = 0; zss->is_cobalt_modem = device_is_compatible(ch, "cobalt"); + zss->is_internal_modem = zss->is_cobalt_modem; /* XXX tested only with wallstreet PowerBook, should do no harm anyway */ @@ -2318,8 +2412,12 @@ zss->is_irda = conn && (strcmp(conn, "infrared") == 0); /* 1999 Powerbook G3 has slot-names property instead */ slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len); - if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0) - zss->is_irda = 1; + if (slots && slots->count > 0) { + if (strcmp(slots->name, "IrDA") == 0) + zss->is_irda = 1; + else if (strcmp(slots->name, "Modem") == 0) + zss->is_internal_modem = 1; + } if (zss->has_dma) { zss->dma_priv = NULL; @@ -2560,6 +2658,8 @@ printk(", port = %s", connector); if (info->is_cobalt_modem) printk(" (cobalt modem)"); + else if (info->is_internal_modem) + printk(" (internal modem)"); if (info->is_irda) printk(" (IrDA)"); printk("\n"); @@ -2898,7 +2998,7 @@ /* * Register console. */ -__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +__initfunc (long mac_scc_console_init(long kmem_start, long kmem_end)) { register_console(&sercons); return kmem_start; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h --- v2.2.17/drivers/macintosh/macserial.h Sat Sep 9 18:42:38 2000 +++ linux/drivers/macintosh/macserial.h Wed Nov 8 23:00:34 2000 @@ -110,6 +110,7 @@ char break_abort; /* Is serial console in, so process brk/abrt */ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ + char is_internal_modem; /* is connected to an internal modem */ char is_cobalt_modem; /* is a gatwick-based cobalt modem */ char is_irda; /* is connected to an IrDA codec */ unsigned char tx_active; /* character is being xmitted */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c --- v2.2.17/drivers/macintosh/mediabay.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/macintosh/mediabay.c Wed Nov 8 23:00:34 2000 @@ -474,8 +474,11 @@ } else if (MB_IDE_READY(i)) { bay->timer = 0; bay->state = mb_up; - if (bay->cd_index < 0) + if (bay->cd_index < 0) { + pmu_suspend(); bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); + pmu_resume(); + } if (bay->cd_index == -1) { /* We eventually do a retry */ bay->cd_retry++; @@ -582,7 +585,7 @@ #ifdef CONFIG_PMAC_PBOOK /* - * notify clients before sleep and reset bus afterwards + * notify ents before sleep and reset bus afterwards */ int mb_notify_sleep(struct pmu_sleep_notifier *self, int when) @@ -611,7 +614,9 @@ they seem to help the 3400 get it right. */ feature_set(bay->dev_node, FEATURE_IOBUS_enable); - mdelay(MB_STABLE_DELAY); + /* Force MB power to 0 */ + set_mb_power(i, 0); + mdelay(MB_POWER_DELAY); if (!bay->pismo) out_8(&bay->addr->contents, 0x70); mdelay(MB_STABLE_DELAY); @@ -621,7 +626,9 @@ bay->last_value = bay->content_id; bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); bay->timer = MS_TO_HZ(MB_POWER_DELAY); +#ifdef CONFIG_BLK_DEV_IDE bay->cd_retry = 0; +#endif do { mdelay(1000/HZ); media_bay_step(i); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c --- v2.2.17/drivers/macintosh/nvram.c Fri Apr 21 12:46:14 2000 +++ linux/drivers/macintosh/nvram.c Wed Nov 8 23:00:34 2000 @@ -14,6 +14,7 @@ #include #include #include +#include #define NVRAM_SIZE 8192 @@ -76,6 +77,30 @@ return p - buf; } +static int nvram_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case PMAC_NVRAM_GET_OFFSET: + { + int part, offset; + if (copy_from_user(&part,(void*)arg,sizeof(part))!=0) + return -EFAULT; + if (part < pmac_nvram_OF || part > pmac_nvram_NR) + return -EINVAL; + offset = pmac_get_partition(part); + if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0) + return -EFAULT; + break; + } + + default: + return -EINVAL; + } + + return 0; +} + static int nvram_open(struct inode *inode, struct file *file) { MOD_INC_USE_COUNT; @@ -94,7 +119,7 @@ write_nvram, NULL, /* nvram_readdir */ NULL, /* nvram_select */ - NULL, /* nvram_ioctl */ + nvram_ioctl, NULL, /* nvram_mmap */ nvram_open, NULL, /* flush */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c --- v2.2.17/drivers/macintosh/via-pmu.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/macintosh/via-pmu.c Wed Nov 8 23:00:34 2000 @@ -3,19 +3,17 @@ * * The VIA (versatile interface adapter) interfaces to the PMU, * a 6805 microprocessor core whose primary function is to control - * battery charging and system power on the PowerBook 3400 and 2400. - * The PMU also controls the ADB (Apple Desktop Bus) which connects + * battery charging and system power on the PowerBooks and new + * "Core99" Apple machines. + * The PMU may also controls the ADB (Apple Desktop Bus) which connects * to the keyboard and mouse, as well as the non-volatile RAM * and the RTC (real time clock) chip. * - * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. - * - * todo: - Check this driver for smp safety (new Core99 motherboards). - * - Cleanup synchro between VIA interrupt and GPIO-based PMU - * interrupt. - * - * + * Copyright (C) 1998 Paul Mackerras, Fabio Riccardi + * and Benjamin Herrenschmidt + * */ + #include #include #include @@ -40,6 +38,10 @@ #include #include #include +#include + +#define DEBUG_SLEEP +#define PMU_CORE99_SLEEP /* Doesn't work yet (almost there...) */ /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -103,9 +105,11 @@ static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; -static int pmu_has_adb, pmu_has_backlight; +static int pmu_has_adb; static unsigned char *gpio_reg = NULL; static int gpio_irq = -1; +static int pmu_suspended = 0; +static spinlock_t pmu_lock; int asleep; @@ -124,6 +128,8 @@ struct pt_regs *regs); static void set_volume(int level); static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +static int pmu_set_backlight_level(int level, void* data); +static int pmu_set_backlight_enable(int on, int level, void* data); #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); #endif @@ -137,8 +143,10 @@ }; extern void low_sleep_handler(void); -extern void sleep_save_intrs(int); -extern void sleep_restore_intrs(void); +extern void pmac_sleep_save_intrs(int); +extern void pmac_sleep_restore_intrs(void); +extern void openpic_sleep_save_intrs(void); +extern void openpic_sleep_restore_intrs(void); extern int grackle_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val); @@ -146,12 +154,18 @@ extern int grackle_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val); +#ifdef DEBUG_SLEEP +int pmu_polled_request(struct adb_request *req); +int pmu_wink(struct adb_request *req); +#endif + + /* * This table indicates for each PMU opcode: * - the number of data bytes to be sent with the command, or -1 * if a length byte should be sent, * - the number of response bytes which the PMU will return, or - * -1 if it will send a length byte. + * -1 if it will send a length byte */ static s8 pmu_data_len[256][2] __openfirmwaredata = { /* 0 1 2 3 4 5 6 7 */ @@ -197,6 +211,11 @@ "Core99" }; +static struct backlight_controller pmu_backlight_controller = { + pmu_set_backlight_enable, + pmu_set_backlight_level +}; + int __openfirmware find_via_pmu() { @@ -226,8 +245,9 @@ return 0; } + spin_lock_init(&pmu_lock); + pmu_has_adb = 1; - pmu_has_backlight = 1; if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) || device_is_compatible(vias->parent, "ohare"))) @@ -241,7 +261,6 @@ pmu_kind = PMU_KEYLARGO_BASED; pmu_has_adb = (find_type_devices("adb") != NULL); - pmu_has_backlight = 0; /* Not driven by PMU */ gpiop = find_devices("gpio"); if (gpiop && gpiop->n_addrs) { @@ -301,7 +320,7 @@ pmu_fully_inited = 1; /* Enable backlight */ - pmu_enable_backlight(1); + register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); /* Make sure PMU settle down before continuing */ do { @@ -318,7 +337,7 @@ out_8(&via[B], via[B] | TREQ); /* negate TREQ */ out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); timeout = 100000; while (!req.complete) { if (--timeout < 0) { @@ -349,7 +368,7 @@ while (!req.complete) pmu_poll(); } - + return 1; } @@ -553,8 +572,8 @@ req->next = 0; req->sent = 0; req->complete = 0; - save_flags(flags); cli(); + spin_lock_irqsave(&pmu_lock, flags); if (current_req != 0) { last_req->next = req; last_req = req; @@ -565,7 +584,7 @@ pmu_start(); } - restore_flags(flags); + spin_unlock_irqrestore(&pmu_lock, flags); return 0; } @@ -639,35 +658,90 @@ void __openfirmware pmu_poll() { - int ie; - + if (!via) + return; if (disable_poll) return; - ie = _disable_interrupts(); - if ((via[IFR] & (SR_INT | CB1_INT)) || - (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)) + /* Kicks ADB read when PMU is suspended */ + if (pmu_suspended) + adb_int_pending = 1; + do { via_pmu_interrupt(0, 0, 0); - _enable_interrupts(ie); + } while (pmu_suspended && (adb_int_pending || pmu_state != idle + || req_awaiting_reply)); } -/* This function loops until the PMU is idle, to avoid spurrious shutdowns - * when prom.c scrollscreen or xmon spends too much time without interupts - * while some PMU communication is going on +/* This function loops until the PMU is idle and prevents it from + * anwsering to ADB interrupts. pmu_request can still be called. + * This is done to avoid spurrious shutdowns when we know we'll have + * interrupts switched off for a long time */ void __openfirmware -pmu_safe_poll(void) +pmu_suspend(void) { - int ie; +#ifdef SUSPEND_USES_PMU + struct adb_request *req; +#endif + unsigned long flags; - if (!via || disable_poll) + if (!via) return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended++; + if (pmu_suspended != 1) { + spin_unlock_irqrestore(&pmu_lock, flags); + return; + } + do { - ie = _disable_interrupts(); - if ((via[IFR] & (SR_INT | CB1_INT)) || - (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)) - via_pmu_interrupt(0, 0, 0); - _enable_interrupts(ie); - } while (adb_int_pending || pmu_state != idle); + spin_unlock(&pmu_lock); + via_pmu_interrupt(0, 0, 0); + spin_lock(&pmu_lock); + if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + disable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_CLR); + spin_unlock_irqrestore(&pmu_lock, flags); +#endif /* SUSPEND_USES_PMU */ + break; + } + } while (1); +} + +void __openfirmware +pmu_resume(void) +{ + unsigned long flags; + + if (!via || pmu_suspended < 1) + return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended--; + if (pmu_suspended > 0) { + spin_unlock_irqrestore(&pmu_lock, flags); + return; + } + adb_int_pending = 1; +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + enable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_SET); + spin_unlock_irqrestore(&pmu_lock, flags); + pmu_poll(); +#endif /* SUSPEND_USES_PMU */ } static void __openfirmware @@ -680,8 +754,9 @@ /* Currently, we use brute-force cli() for syncing with GPIO * interrupt. I'll make this smarter later, along with some * spinlocks for SMP */ - save_flags(flags);cli(); + spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; + while ((intr = in_8(&via[IFR])) != 0) { if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " @@ -699,9 +774,15 @@ out_8(&via[IFR], intr); } } + /* This is not necessary except if synchronous ADB requests are done + * with interrupts off, which should not happen. Since I'm not sure + * this "wiring" will remain, I'm commenting it out for now. Please do + * not remove. -- BenH. + */ +#if 0 if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0) adb_int_pending = 1; - +#endif if (pmu_state == idle) { if (adb_int_pending) { pmu_state = intack; @@ -713,16 +794,17 @@ } } --disable_poll; - restore_flags(flags); + spin_unlock_irqrestore(&pmu_lock, flags); } static void __openfirmware gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { + adb_int_pending = 1; via_pmu_interrupt(0, 0, 0); } - + static void __openfirmware pmu_sr_intr(struct pt_regs *regs) { @@ -749,7 +831,7 @@ /* if reading grab the byte, and reset the interrupt */ if (pmu_state == reading || pmu_state == reading_intr) bite = in_8(&via[SR]); - + out_8(&via[IFR], SR_INT); switch (pmu_state) { @@ -771,8 +853,11 @@ current_req = req->next; if (req->reply_expected) req_awaiting_reply = req; - else + else { + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); + } } else { pmu_state = reading; data_index = 0; @@ -797,7 +882,8 @@ printk(KERN_ERR "PMU: bad reply len %d\n", bite); } else { - reply_ptr[data_index++] = bite; + if (data_index < 32) + reply_ptr[data_index++] = bite; } if (data_index < data_len) { recv_byte(); @@ -810,7 +896,9 @@ req = current_req; current_req = req->next; req->reply_len += data_index; + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); } pmu_state = idle; @@ -877,7 +965,7 @@ } } else if (data[0] == 0x08 && len == 3) { /* sound/brightness buttons pressed */ - pmu_set_brightness(data[1] >> 3); + set_backlight_level(data[1] >> 4); set_volume(data[2]); } else { #ifdef CONFIG_PMAC_PBOOK @@ -886,53 +974,22 @@ } } -int backlight_level = -1; -int backlight_enabled = 0; - -#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1)) - -void __openfirmware -pmu_enable_backlight(int on) +static int backlight_to_bright[] = { + 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, + 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e +}; + +static int __openfirmware +pmu_set_backlight_enable(int on, int level, void* data) { struct adb_request req; + + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return; - - /* first call: get current backlight value */ - if (on && backlight_level < 0) { - switch (pmu_kind) { - case PMU_OHARE_BASED: - pmu_request(&req, NULL, 2, 0xd9, 0); - while (!req.complete) - pmu_poll(); - backlight_level = req.reply[1] >> 3; - break; - case PMU_HEATHROW_BASED: - /* We cannot use nvram_read_byte here (not yet initialized) */ - pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); - while (!req.complete) - pmu_poll(); - backlight_level = req.reply[1]; - printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level); - break; - case PMU_PADDINGTON_BASED: - case PMU_KEYLARGO_BASED: - /* the G3 PB 1999 has a backlight node - and chrp-structured nvram */ - /* XXX should read macos's "blkt" property in nvram - for this node. For now this ensures that the - backlight doesn't go off as soon as linux boots. */ - backlight_level = 20; - break; - default: - backlight_enabled = 0; - return; - } - } if (on) { pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - LEVEL_TO_BRIGHT(backlight_level)); + backlight_to_bright[level]); while (!req.complete) pmu_poll(); } @@ -940,34 +997,26 @@ PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); while (!req.complete) pmu_poll(); - backlight_enabled = on; + + return 0; } -void __openfirmware -pmu_set_brightness(int level) +static int __openfirmware +pmu_set_backlight_level(int level, void* data) { - int bright; + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return ; + if (!bright_req_1.complete) + return -EAGAIN; + pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + backlight_to_bright[level]); + if (!bright_req_2.complete) + return -EAGAIN; + pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT + | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF)); - backlight_level = level; - bright = LEVEL_TO_BRIGHT(level); - if (!backlight_enabled) - return; - if (bright_req_1.complete) - pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, - bright); - if (bright_req_2.complete) - pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF)); - - /* XXX nvram address is hard-coded and looks ok on wallstreet, please - test on your machine. Note that newer MacOS system software may break - the nvram layout. */ - if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete) - pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM, - 0x14, 0xe, level); + return 0; } void __openfirmware @@ -1083,7 +1132,7 @@ when, current, current->notifier_call); for (; list != &sleep_notifiers; list = list->next) { current = list_entry(list, struct pmu_sleep_notifier, list); - current->notifier_call(current, fallback); + current->notifier_call(current, fallback); } return ret; } @@ -1178,21 +1227,40 @@ } } -#if 0 +#ifdef DEBUG_SLEEP /* N.B. This doesn't work on the 3400 */ -void pmu_blink(int n) +void +pmu_blink(int n) { struct adb_request req; + memset(&req, 0, sizeof(req)); + for (; n > 0; --n) { - pmu_request(&req, NULL, 4, 0xee, 4, 0, 1); - while (!req.complete) pmu_poll(); - udelay(50000); - pmu_request(&req, NULL, 4, 0xee, 4, 0, 0); - while (!req.complete) pmu_poll(); - udelay(50000); + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 1; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 0; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); } - udelay(50000); + mdelay(50); } #endif @@ -1200,7 +1268,33 @@ * Put the powerbook to sleep. */ -#define FEATURE_CTRL(base) ((unsigned int *)(base + 0x38)) +static u32 save_via[8]; +static void save_via_state(void) +{ + save_via[0] = in_8(&via[ANH]); + save_via[1] = in_8(&via[DIRA]); + save_via[2] = in_8(&via[B]); + save_via[3] = in_8(&via[DIRB]); + save_via[4] = in_8(&via[PCR]); + save_via[5] = in_8(&via[ACR]); + save_via[6] = in_8(&via[T1CL]); + save_via[7] = in_8(&via[T1CH]); +} +static void restore_via_state(void) +{ + out_8(&via[ANH], save_via[0]); + out_8(&via[DIRA], save_via[1]); + out_8(&via[B], save_via[2]); + out_8(&via[DIRB], save_via[3]); + out_8(&via[PCR], save_via[4]); + out_8(&via[ACR], save_via[5]); + out_8(&via[T1CL], save_via[6]); + out_8(&via[T1CH], save_via[7]); + out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ + out_8(&via[IFR], 0x7f); /* clear IFR */ + out_8(&via[IER], IER_SET | SR_INT | CB1_INT); +} + #define GRACKLE_PM (1<<7) #define GRACKLE_DOZE (1<<5) #define GRACKLE_NAP (1<<4) @@ -1208,20 +1302,12 @@ int __openfirmware powerbook_sleep_G3(void) { - int ret; unsigned long save_l2cr; - unsigned long save_fcr; unsigned long wait; unsigned short pmcr1; - struct adb_request sleep_req; - struct device_node *macio; - unsigned long macio_base = 0; - - macio = find_devices("mac-io"); - if (macio != 0 && macio->n_addrs > 0) - macio_base = (unsigned long) - ioremap(macio->addrs[0].address, 0x40); - + struct adb_request req; + int ret, timeout; + /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); if (ret != PBOOK_SLEEP_OK) { @@ -1245,31 +1331,57 @@ } /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + for (wait = jiffies + HZ; time_before(jiffies, wait); ) mb(); - /* Disable all interrupts except pmu */ - sleep_save_intrs(vias->intrs[0].line); + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete) + pmu_poll(); + + /* Turn off various things. Darwin does some retry tests here... */ + pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY); + while (!req.complete) + pmu_poll(); + + /* Disable all interrupts */ + pmac_sleep_save_intrs(-1); + + /* Make sure the PMU is idle */ + while (pmu_state != idle) + pmu_poll(); /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); -#if 0 - /* Save the state of PCI config space for some slots */ - pbook_pci_save(); -#endif + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* Giveup the FPU */ + if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0) + giveup_fpu(current); + + /* We can now disable MSR_EE */ + cli(); + /* For 750, save backside cache setting and disable it */ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ if (save_l2cr) _set_L2CR(0); - if (macio_base != 0) { - save_fcr = in_le32(FEATURE_CTRL(macio_base)); - /* Check if this is still valid on older powerbooks */ - out_le32(FEATURE_CTRL(macio_base), save_fcr & ~(0x00000140UL)); - } + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) + pmu_poll(); - if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0) - giveup_fpu(current); + /* The VIA is supposed not to be restored correctly*/ + save_via_state(); + /* We shut down some HW */ + feature_prepare_for_sleep(); grackle_pcibios_read_config_word(0,0,0x70,&pmcr1); /* Apparently, MacOS uses NAP mode for Grackle ??? */ @@ -1277,15 +1389,6 @@ pmcr1 |= GRACKLE_PM|GRACKLE_NAP; grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); - /* Ask the PMU to put us to sleep */ - pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!sleep_req.complete) - mb(); - - cli(); - while (pmu_state != idle) - pmu_poll(); - /* Call low-level ASM sleep handler */ low_sleep_handler(); @@ -1293,26 +1396,201 @@ grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1); pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); + + /* Restore things */ + feature_wake_up(); + restore_via_state(); + + /* Restore L2 cache */ + if (save_l2cr) + _set_L2CR(save_l2cr); + + /* Restore userland MMU context */ + set_context(current->mm->context); + + /* Re-enable DEC interrupts and kick DEC */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + sti(); + asm volatile("mtdec %0" : : "r" (0x10000000)); + + /* Power things up */ + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, + PMU_POW0_ON|PMU_POW0_HARD_DRIVE); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY); + while (!req.complete) + pmu_poll(); + + /* ack all pending interrupts */ + timeout = 100000; + interrupt_data[0] = 1; + while (interrupt_data[0] || pmu_state != idle) { + if (--timeout < 0) + break; + if (pmu_state == idle) + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + udelay(10); + } + + /* reenable interrupt controller */ + pmac_sleep_restore_intrs(); + + /* Leave some time for HW to settle down */ + mdelay(100); + + /* Notify drivers */ + broadcast_wake(); + + return 0; +} + +#ifdef PMU_CORE99_SLEEP + +/* Not finished yet */ +int __openfirmware powerbook_sleep_Core99(void) +{ + unsigned long save_l2cr; + unsigned long wait; + struct adb_request req; + int ret, timeout; + + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep rejected\n"); + return -EBUSY; + } + + /* Sync the disks. */ + /* XXX It would be nice to have some way to ensure that + * nobody is dirtying any new buffers while we wait. + * BenH: Moved to _after_ sleep request and changed video + * drivers to vmalloc() during sleep request. This way, all + * vmalloc's are done before actual sleep of block drivers */ + fsync_dev(0); + + /* Sleep can fail now. May not be very robust but useful for debugging */ + ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep failed\n"); + return -EBUSY; + } + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + HZ; time_before(jiffies, wait); ) + mb(); + + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete) + pmu_poll(); + + /* Tell PMU what events will wake us up */ + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, + 0xff, 0xff); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, + 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); + while (!req.complete) + pmu_poll(); + + /* Save & disable all interrupts */ + openpic_sleep_save_intrs(); /* Make sure the PMU is idle */ while (pmu_state != idle) pmu_poll(); - sti(); -#if 0 - /* According to someone from Apple, this should not be needed, - at least not for all devices. Let's keep it for now until we - have something that works. */ - pbook_pci_restore(); -#endif - set_context(current->mm->context); + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* Giveup the FPU */ + if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0) + giveup_fpu(current); + + /* We can now disable MSR_EE */ + cli(); + + /* For 750, save backside cache setting and disable it */ + save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ + if (save_l2cr) + _set_L2CR(0); + + /* Save the state of PCI config space for some slots */ + // pbook_pci_save(); + + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) + pmu_poll(); + + /* The VIA is supposed not to be restored correctly*/ + save_via_state(); + + /* Shut down various ASICs. There's a chance that we can no longer + * talk to the PMU after this, so I moved it to _after_ sending the + * sleep command to it. Still need to be checked. + */ + feature_prepare_for_sleep(); + + /* Call low-level ASM sleep handler */ + low_sleep_handler(); + /* Restore things */ + feature_wake_up(); + + // Don't restore PCI for now, it crashes. Maybe unnecessary on pbook + // pbook_pci_restore(); + + restore_via_state(); + /* Restore L2 cache */ if (save_l2cr) - _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ + _set_L2CR(save_l2cr); + + /* Restore userland MMU context */ + set_context(current->mm->context); - /* reenable interrupts */ - sleep_restore_intrs(); + /* Re-enable DEC interrupts and kick DEC */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + sti(); + asm volatile("mtdec %0" : : "r" (0x10000000)); + + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + while (!req.complete) + pmu_poll(); + + /* ack all pending interrupts */ + timeout = 100000; + interrupt_data[0] = 1; + while (interrupt_data[0] || pmu_state != idle) { + if (--timeout < 0) + break; + if (pmu_state == idle) + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + udelay(10); + } + + /* reenable interrupt controller */ + openpic_sleep_restore_intrs(); + + /* Leave some time for HW to settle down */ + mdelay(100); /* Notify drivers */ broadcast_wake(); @@ -1320,6 +1598,8 @@ return 0; } +#endif + #define PB3400_MEM_CTRL ((unsigned int *)0xf8000070) int __openfirmware powerbook_sleep_3400(void) @@ -1328,7 +1608,7 @@ unsigned long msr; unsigned int hid0; unsigned long p, wait; - struct adb_request sleep_req; + struct adb_request req; /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); @@ -1356,8 +1636,12 @@ for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) mb(); + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete) + pmu_poll(); + /* Disable all interrupts except pmu */ - sleep_save_intrs(vias->intrs[0].line); + pmac_sleep_save_intrs(vias->intrs[0].line); /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); @@ -1377,8 +1661,8 @@ } /* Ask the PMU to put us to sleep */ - pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!sleep_req.complete) + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) mb(); /* displacement-flush the L2 cache - necessary? */ @@ -1387,9 +1671,9 @@ asleep = 1; /* Put the CPU into sleep mode */ - asm volatile("mfspr %0,1008" : "=r" (hid0) :); + hid0 = _get_HID0(); hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; - asm volatile("mtspr 1008,%0" : : "r" (hid0)); + _set_HID0(hid0); save_flags(msr); msr |= MSR_POW | MSR_EE; restore_flags(msr); @@ -1404,7 +1688,7 @@ mb(); /* reenable interrupts */ - sleep_restore_intrs(); + pmac_sleep_restore_intrs(); /* Notify drivers */ broadcast_wake(); @@ -1576,20 +1860,24 @@ case PMU_PADDINGTON_BASED: error = powerbook_sleep_G3(); break; +#ifdef PMU_CORE99_SLEEP + case PMU_KEYLARGO_BASED: + error = powerbook_sleep_Core99(); + break; +#endif default: error = -ENOSYS; } return error; case PMU_IOC_GET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; - return put_user(backlight_level, (__u32 *)arg); + error = get_backlight_level(); + if (error < 0) + return error; + return put_user(error, (__u32 *)arg); case PMU_IOC_SET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; error = get_user(value, (__u32 *)arg); if (!error) - pmu_set_brightness(value); + error = set_backlight_level(value); return error; case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); @@ -1623,7 +1911,7 @@ } #endif /* CONFIG_PMAC_PBOOK */ -#if 0 +#ifdef DEBUG_SLEEP static inline void polled_handshake(volatile unsigned char *via) { via[B] &= ~TREQ; eieio(); @@ -1689,4 +1977,4 @@ restore_flags(flags); return 0; } -#endif /* 0 */ +#endif /* DEBUG_SLEEP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.2.17/drivers/misc/parport_pc.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/misc/parport_pc.c Mon Oct 2 10:09:14 2000 @@ -617,7 +617,7 @@ sti(); irqs = probe_irq_on(); - + parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */ parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */ @@ -902,11 +902,13 @@ { { 0, -1 }, } }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1, { { 0, -1 }, } }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR, 1, + { { 0, -1 }, } }, { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, 1, { { 0, 1 }, } }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, 1, - { { 2, -1 }, } }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_4008A, 1, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP, 1, + { { 0, -1 }, } }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840, 1, { { 0, 1 }, } }, { 0, } }; @@ -946,6 +948,7 @@ } } +#ifdef CONFIG_PCI /* Look for parallel controllers that we don't know about. */ for (pcidev = pci_devices; pcidev; pcidev = pcidev->next) { const int class_noprogif = pcidev->class & ~0xff; @@ -966,6 +969,7 @@ "tim@cyberelk.demon.co.uk\n", pcidev->vendor, pcidev->device); } +#endif return count; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.2.17/drivers/net/3c505.c Fri Apr 21 12:46:14 2000 +++ linux/drivers/net/3c505.c Mon Sep 11 17:58:02 2000 @@ -129,15 +129,15 @@ #define INVALID_PCB_MSG(len) \ printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__) -static const char *search_msg = "%s: Looking for 3c505 adapter at address %#x..."; +static char *search_msg __initdata = "%s: Looking for 3c505 adapter at address %#x..."; -static const char *stilllooking_msg = "still looking..."; +static char *stilllooking_msg __initdata = "still looking..."; -static const char *found_msg = "found.\n"; +static char *found_msg __initdata = "found.\n"; -static const char *notfound_msg = "not found (reason = %d)\n"; +static char *notfound_msg __initdata = "not found (reason = %d)\n"; -static const char *couldnot_msg = "%s: 3c505 not found\n"; +static char *couldnot_msg __initdata = "%s: 3c505 not found\n"; /********************************************************* * @@ -179,7 +179,7 @@ * Last element MUST BE 0! *****************************************************************/ -static const int addr_list[] __initdata = {0x300, 0x280, 0x310, 0}; +static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0}; /* Dma Memory related stuff */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.2.17/drivers/net/3c509.c Fri Apr 21 12:46:14 2000 +++ linux/drivers/net/3c509.c Mon Sep 11 17:58:02 2000 @@ -64,6 +64,7 @@ #include #include #include /* for udelay() */ +#include #include #include @@ -156,7 +157,7 @@ int id; }; -struct el3_mca_adapters_struct el3_mca_adapters[] = { +static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = { { "3Com 3c529 EtherLink III (10base2)", 0x627c }, { "3Com 3c529 EtherLink III (10baseT)", 0x627d }, { "3Com 3c529 EtherLink III (test mode)", 0x62db }, @@ -166,7 +167,7 @@ }; #endif -int el3_probe(struct device *dev) +int __init el3_probe(struct device *dev) { short lrs_state = 0xff, i; int ioaddr, irq, if_port; @@ -396,7 +397,7 @@ /* Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero. */ -static ushort read_eeprom(int ioaddr, int index) +static ushort __init read_eeprom(int ioaddr, int index) { outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ @@ -405,7 +406,7 @@ } /* Read a word from the EEPROM when in the ISA ID probe state. */ -static ushort id_read_eeprom(int index) +static ushort __init id_read_eeprom(int index) { int bit, word = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.2.17/drivers/net/3c515.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/net/3c515.c Mon Sep 11 17:58:02 2000 @@ -62,6 +62,7 @@ #define NEW_MULTICAST #include +#include /* Kernel version compatibility functions. */ #define RUN_AT(x) (jiffies + (x)) @@ -399,7 +400,7 @@ } #else -int tc515_probe(struct device *dev) +int __init tc515_probe(struct device *dev) { int cards_found = 0; @@ -412,7 +413,7 @@ } #endif /* not MODULE */ -static int vortex_scan(struct device *dev) +static int __init vortex_scan(struct device *dev) { int cards_found = 0; static int ioaddr = 0x100; @@ -452,7 +453,7 @@ return cards_found; } -static struct device *vortex_found_device(struct device *dev, int ioaddr, +static struct device * __init vortex_found_device(struct device *dev, int ioaddr, int irq, int product_index, int options) { @@ -517,7 +518,7 @@ return dev; } -static int vortex_probe1(struct device *dev) +static int __init vortex_probe1(struct device *dev) { int ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.2.17/drivers/net/3c523.c Fri Apr 21 12:46:15 2000 +++ linux/drivers/net/3c523.c Sat Sep 30 18:35:22 2000 @@ -161,15 +161,10 @@ /**************************************************************************/ -#define DELAY(x) {int i=jiffies; \ - if(loops_per_sec == 1) \ - while(time_after(i+(x), jiffies)); \ - else \ - __delay((loops_per_sec>>5)*x); \ - } +#define DELAY(x) { mdelay(32 * x); } /* a much shorter delay: */ -#define DELAY_16(); { __delay( (loops_per_sec>>16)+1 ); } +#define DELAY_16(); { udelay(16) ; } /* wait for command with timeout: */ #define WAIT_4_SCB_CMD() { int i; \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/3c527.c linux/drivers/net/3c527.c --- v2.2.17/drivers/net/3c527.c Fri Apr 21 12:46:15 2000 +++ linux/drivers/net/3c527.c Mon Sep 11 17:58:02 2000 @@ -124,7 +124,7 @@ char *name; }; -const struct mca_adapters_t mc32_adapters[] = { +static struct mca_adapters_t mc32_adapters[] __initdata = { { 0x0041, "3COM EtherLink MC/32" }, { 0x8EF5, "IBM High Performance Lan Adapter" }, { 0x0000, NULL } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.2.17/drivers/net/3c59x.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/3c59x.c Thu Dec 7 14:50:16 2000 @@ -60,11 +60,14 @@ - In vortex_open(), set vp->tx_full to zero (else we get errors if the device was closed with a full Tx ring). + 15Sep00 <2.2.18-pre3> andrewm + - Added support for the 3c556B Laptop Hurricane (Louis Gerbarg) + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.2 for more details. */ static char version[] = -"3c59x.c 16Aug00 Donald Becker and others http://www.scyld.com/network/vortex.html\n"; +"3c59x.c 15Sep00 Donald Becker and others http://www.scyld.com/network/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -336,6 +339,8 @@ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, {"3c556 10/100 Mini PCI Adapter", 0x10B7, 0x6055, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_CB_FNS, 128, vortex_probe1}, + {"3c556B Laptop Hurricane", 0x10B7, 0x6056, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_CB_FNS, 128, vortex_probe1}, {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, @@ -932,6 +937,8 @@ #else if (pci_tbl[chip_idx].device_id == 0x6055) { outw(0x230 + i, ioaddr + Wn0EepromCmd); + } else if (pci_tbl[chip_idx].device_id == 0x6056) { + outw(EEPROM_Read + 0x30 + i, ioaddr + Wn0EepromCmd); } else { outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); } @@ -1245,7 +1252,7 @@ vp->tx_skbuff[i] = 0; outl(0, ioaddr + DownListPtr); } - /* Set reciever mode: presumably accept b-case and phys addr only. */ + /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.2.17/drivers/net/8139too.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/8139too.c Sun Oct 1 11:24:15 2000 @@ -0,0 +1,2255 @@ +/* + + 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. + + Maintained by Jeff Garzik + + Much code comes from Donald Becker's rtl8139.c driver, + versions 1.11 and older. This driver was originally based + on rtl8139.c version 1.07. Header of rtl8139.c version 1.11: + + ---------- + + Written 1997-2000 by Donald Becker. + This software may be used and distributed according to the + terms of the GNU General Public License (GPL), incorporated + herein by reference. Drivers based on or derived from this + code fall under the GPL and must retain the authorship, + copyright and license notice. This file is not a complete + program and may only be used when the entire operating + system is licensed under the GPL. + + This driver is for boards based on the RTL8129 and RTL8139 + PCI ethernet chips. + + The author may be reached as becker@scyld.com, or C/O Scyld + Computing Corporation 410 Severn Ave., Suite 210 Annapolis + MD 21403 + + Support and updates available at + http://www.scyld.com/network/rtl8139.html + + Twister-tuning table provided by Kinston + . + + ---------- + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Contributors: + + Donald Becker - he wrote the original driver, kudos to him! + (but please don't e-mail him for support, this isn't his driver) + + Tigran Aivazian - bug fixes, skbuff free cleanup + + Martin Mares - suggestions for PCI cleanup + + David S. Miller - PCI DMA and softnet updates + + Ernst Gill - fixes ported from BSD driver + + Daniel Kobras - identified specific locations of + posted MMIO write bugginess + + Gerard Sharp - bug fix, testing and feedback + + David Ford - Rx ring wrap fix + + Dan DeMaggio - swapped RTL8139 cards with me, and allowed me + to find and fix a crucial bug on older chipsets. + + Donald Becker/Chris Butterworth/Marcus Westergren - + Noticed various Rx packet size-related buglets. + + Santiago Garcia Mantinan - testing and feedback + + Jens David - 2.2.x kernel backports + + Martin Dennett - incredibly helpful insight on undocumented + features of the 8139 chips + + Submitting bug reports: + + "rtl8139-diag -mmmaaavvveefN" output + enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log + + See 8139too.txt for more details. + +----------------------------------------------------------------------------- + + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the RealTek RTL8139 series, the RealTek +Fast Ethernet controllers for PCI and CardBus. This chip is used on many +low-end boards, sometimes with its markings changed. + + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS will assign the +PCI INTA signal to a (preferably otherwise unused) system IRQ line. + +III. Driver operation + +IIIa. Rx Ring buffers + +The receive unit uses a single linear ring buffer rather than the more +common (and more efficient) descriptor-based architecture. Incoming frames +are sequentially stored into the Rx region, and the host copies them into +skbuffs. + +Comment: While it is theoretically possible to process many frames in place, +any delay in Rx processing would cause us to drop frames. More importantly, +the Linux protocol stack is not designed to operate in this manner. + +IIIb. Tx operation + +The RTL8139 uses a fixed set of four Tx descriptors in register space. +In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux +aligns the IP header on word boundaries, and 14 byte ethernet header means +that almost all frames will need to be copied to an alignment buffer. + +IVb. References + +http://www.realtek.com.tw/cn/cn.html +http://www.scyld.com/expert/NWay.html + +IVc. Errata + +1) The RTL-8139 has a serious problem with motherboards which do +posted MMIO writes to PCI space. This driver works around the +problem by having an MMIO register write be immediately followed by +an MMIO register read. + +2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define RTL8139_VERSION "0.9.10-2.2" +#define RTL8139_MODULE_NAME "8139too" +#define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " FastEthernet driver " RTL8139_VERSION +#define RTL8139_AUTHOR "Jeff Garzik " +#define PFX RTL8139_MODULE_NAME ": " + + +/* define to 1 to enable PIO instead of MMIO */ +#undef USE_IO_OPS + +/* define to 1 to enable copious debugging info */ +#undef RTL8139_DEBUG + +/* define to 1 to disable lightweight runtime debugging checks */ +#undef RTL8139_NDEBUG + + +#ifdef RTL8139_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef RTL8139_NDEBUG +#define assert(expr) do {} while (0) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +#define dev_kfree_skb_irq(a) dev_kfree_skb(a) +#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) +#define netif_stop_queue(dev) set_bit(0, &dev->tbusy) + +static inline void netif_start_queue(struct device *dev) +{ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; +} + +#define netif_queue_stopped(dev) dev->tbusy +#define netif_running(dev) dev->start +#define dma_addr_t unsigned long + +struct resource { + const char *name; + unsigned long start, end; + unsigned long flags; + struct resource *parent, *sibling, *child; +}; + +#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ +#define IORESOURCE_IO 0x00000100 /* Resource type */ +#define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_DMA 0x00000800 +#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ +#define IORESOURCE_READONLY 0x00002000 +#define IORESOURCE_CACHEABLE 0x00004000 +#define IORESOURCE_RANGELENGTH 0x00008000 +#define IORESOURCE_SHADOWABLE 0x00010000 +#define IORESOURCE_UNSET 0x20000000 +#define IORESOURCE_AUTO 0x40000000 +#define IORESOURCE_BUSY 0x80000000 + +#define PCI_USES_IO 1 +#define PCI_USES_MEM 2 +#define PCI_USES_MASTER 4 + +static inline unsigned int pci_calc_resource_flags(unsigned int flags) +{ + if (flags & PCI_BASE_ADDRESS_SPACE_IO) + return IORESOURCE_IO; + + if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) + return IORESOURCE_MEM | IORESOURCE_PREFETCH; + + return IORESOURCE_MEM; +} + +static void rtl8139_read_pci_resources(struct pci_dev *dev, struct resource *res) +{ + unsigned int pos, reg, next; + u32 l, sz, tmp; + u16 cmd; + + /* Disable IO and memory while we fiddle */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(dev, PCI_COMMAND, tmp); + + for (pos=0; pos<4; pos = next, res++) { + next = pos+1; + reg = PCI_BASE_ADDRESS_0 + (pos << 2); + pci_read_config_dword(dev, reg, &l); + pci_write_config_dword(dev, reg, ~0); + pci_read_config_dword(dev, reg, &sz); + pci_write_config_dword(dev, reg, l); + if (!sz || sz == 0xffffffff) + continue; + if (l == 0xffffffff) + l = 0; + if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { + res->start = l & PCI_BASE_ADDRESS_MEM_MASK; + sz = ~(sz & PCI_BASE_ADDRESS_MEM_MASK); + } else { + res->start = l & PCI_BASE_ADDRESS_IO_MASK; + sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; + } + res->end = res->start + (unsigned long) sz; + res->flags |= (l & 0xf) | pci_calc_resource_flags(l); + } +} + +#define pci_resource_start(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].start) +#define pci_resource_end(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].end) +#define pci_resource_flags(dev_priv,bar) ((dev_priv)->rtl8139_pci_resource[(bar)].flags) +#define pci_resource_len(dev_priv,bar) \ + ((pci_resource_start((dev_priv),(bar)) == 0 && \ + pci_resource_end((dev_priv),(bar)) == \ + pci_resource_start((dev_priv),(bar))) ? 0 : \ + \ + (pci_resource_end((dev_priv),(bar)) - \ + pci_resource_start((dev_priv),(bar)) + 1)) + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + + +/* A few user-configurable values. */ +/* media options */ +static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* Size of the in-memory receive ring. */ +#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +#define RX_BUF_PAD 16 +#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ +#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) + +/* Number of Tx descriptor registers. */ +#define NUM_TX_DESC 4 + +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ +#define TX_BUF_SIZE 1536 +#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) + +/* PCI Tuning Parameters + Threshold is bytes transferred to chip before transmission starts. */ +#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ + +/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ +#define RX_FIFO_THRESH 6 /* Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ + + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (HZ/2) + + +enum { + HAS_CHIP_XCVR = 0x020000, + HAS_LNK_CHNG = 0x040000, +}; + +#define RTL_MIN_IO_SIZE 0x80 +#define RTL8139B_IO_SIZE 256 + +#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG + +typedef enum { + RTL8139 = 0, + RTL8139_CB, + SMC1211TX, + DELTA8139, + ADDTRON8139, +} board_t; + + +/* indexed by board_t, above */ +static struct { + const char *name; +} board_info[] = { + { "RealTek RTL8139 Fast Ethernet" }, + { "RealTek RTL8139B PCI/CardBus" }, + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" }, + { "Delta Electronics 8139 10/100BaseTX" }, + { "Addtron Technolgy 8139 10/100BaseTX" }, +}; + +struct pci_device_id { + unsigned int vendor, device; + board_t board; +}; + +static struct pci_device_id rtl8139_pci_tbl[] = { + {0x10ec, 0x8139, RTL8139 }, + {0x10ec, 0x8138, RTL8139_CB }, + {0x1113, 0x1211, SMC1211TX }, + {0x1500, 0x1360, DELTA8139 }, + {0x4033, 0x1360, ADDTRON8139 }, + {0,} +}; + +/* The rest of these values should never change. */ + +static struct device *rtl8139_device_tab[16]; +static int rtl8139_device_count = 0; +static int rtl8139_initialized = 0; + +/* Symbolic offsets to registers. */ +enum RTL8139_registers { + MAC0 = 0, /* Ethernet hardware address. */ + MAR0 = 8, /* Multicast filter. */ + TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + RxBuf = 0x30, + RxEarlyCnt = 0x34, + RxEarlyStatus = 0x36, + ChipCmd = 0x37, + RxBufPtr = 0x38, + RxBufAddr = 0x3A, + IntrMask = 0x3C, + IntrStatus = 0x3E, + TxConfig = 0x40, + ChipVersion = 0x43, + RxConfig = 0x44, + Timer = 0x48, /* A general-purpose counter. */ + RxMissed = 0x4C, /* 24 bits valid, write clears. */ + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + FlashReg = 0x54, + MediaStatus = 0x58, + Config3 = 0x59, + Config4 = 0x5A, /* absent on RTL-8139A */ + HltClk = 0x5B, + MultiIntr = 0x5C, + TxSummary = 0x60, + BasicModeCtrl = 0x62, + BasicModeStatus = 0x64, + NWayAdvert = 0x66, + NWayLPAR = 0x68, + NWayExpansion = 0x6A, + /* Undocumented registers, but required for proper operation. */ + FIFOTMS = 0x70, /* FIFO Control and test. */ + CSCR = 0x74, /* Chip Status and Configuration Register. */ + PARA78 = 0x78, + PARA7c = 0x7c, /* Magic transceiver parameter register. */ + Config5 = 0xD8, /* absent on RTL-8139A */ +}; + +enum ClearBitMasks { + MultiIntrClear = 0xF000, + ChipCmdClear = 0xE2, + Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), +}; + +enum ChipCmdBits { + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, +}; + +/* Interrupt register bits, using my own meaningful names. */ +enum IntrStatusBits { + PCIErr = 0x8000, + PCSTimeout = 0x4000, + RxFIFOOver = 0x40, + RxUnderrun = 0x20, + RxOverflow = 0x10, + TxErr = 0x08, + TxOK = 0x04, + RxErr = 0x02, + RxOK = 0x01, +}; +enum TxStatusBits { + TxHostOwns = 0x2000, + TxUnderrun = 0x4000, + TxStatOK = 0x8000, + TxOutOfWindow = 0x20000000, + TxAborted = 0x40000000, + TxCarrierLost = 0x80000000, +}; +enum RxStatusBits { + RxMulticast = 0x8000, + RxPhysical = 0x4000, + RxBroadcast = 0x2000, + RxBadSymbol = 0x0020, + RxRunt = 0x0010, + RxTooLong = 0x0008, + RxCRCErr = 0x0004, + RxBadAlign = 0x0002, + RxStatusOK = 0x0001, +}; + +/* Bits in RxConfig. */ +enum rx_mode_bits { + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, +}; + +/* Bits in TxConfig. */ +enum tx_config_bits { + TxIFG1 = (1 << 25), /* Interframe Gap Time */ + TxIFG0 = (1 << 24), /* Enabling these bits violates IEEE 802.3 */ + TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ + TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ + TxClearAbt = (1 << 0), /* Clear abort (WO) */ + TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + + TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ +}; + +/* Bits in Config1 */ +enum Config1Bits { + Cfg1_PM_Enable = 0x01, + Cfg1_VPD_Enable = 0x02, + Cfg1_PIO = 0x04, + Cfg1_MMIO = 0x08, + Cfg1_LWAKE = 0x10, + Cfg1_Driver_Load = 0x20, + Cfg1_LED0 = 0x40, + Cfg1_LED1 = 0x80, +}; + +enum RxConfigBits { + /* Early Rx threshold, none or X/16 */ + RxCfgEarlyRxNone = 0, + RxCfgEarlyRxShift = 24, + + /* rx fifo threshold */ + RxCfgFIFOShift = 13, + RxCfgFIFONone = (7 << RxCfgFIFOShift), + + /* Max DMA burst */ + RxCfgDMAShift = 8, + RxCfgDMAUnlimited = (7 << RxCfgDMAShift), + + /* rx ring buffer length */ + RxCfgRcv8K = 0, + RxCfgRcv16K = (1 << 11), + RxCfgRcv32K = (1 << 12), + RxCfgRcv64K = (1 << 11) | (1 << 12), + + /* Disable packet wrap at end of Rx buffer */ + RxNoWrap = (1 << 7), +}; + + +/* Twister tuning parameters from RealTek. + Completely undocumented, but required to tune bad links. */ +enum CSCRBits { + CSCR_LinkOKBit = 0x0400, + CSCR_LinkChangeBit = 0x0800, + CSCR_LinkStatusBits = 0x0f000, + CSCR_LinkDownOffCmd = 0x003c0, + CSCR_LinkDownCmd = 0x0f3c0, +}; + + +enum Cfg9346Bits { + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xC0, +}; + + +#define PARA78_default 0x78fa8388 +#define PARA7c_default 0xcb38de43 /* param[0][3] */ +#define PARA7c_xxx 0xcb38de43 +static const unsigned long param[4][4] = { + {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43}, + {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83}, + {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83}, + {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83} +}; + +struct ring_info { + struct sk_buff *skb; +}; + + +typedef enum { + CH_8139 = 0, + CH_8139_K, + CH_8139A, + CH_8139B, + CH_8130, + CH_8139C, +} chip_t; + + +/* directly indexed by chip_t, above */ +const static struct { + const char *name; + u8 version; /* from RTL8139C docs */ + u32 RxConfigMask; /* should clear the bits supported by this chip */ +} rtl_chip_info[] = { + { "RTL-8139", + 0x40, + 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + }, + + { "RTL-8139 rev K", + 0x60, + 0xf0fe0040, + }, + + { "RTL-8139A", + 0x70, + 0xf0fe0040, + }, + + { "RTL-8139B", + 0x78, + 0xf0fc0040 + }, + + { "RTL-8130", + 0x7C, + 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + }, + + { "RTL-8139C", + 0x74, + 0xf0fc0040, /* XXX copied from RTL8139B, verify */ + }, + +}; + + +struct rtl8139_private { + board_t board; + void *mmio_addr; + int drv_flags; + struct pci_dev *pci_dev; + struct resource rtl8139_pci_resource[4]; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + unsigned char *rx_ring; + unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ + unsigned int tx_flag; + atomic_t cur_tx; + atomic_t dirty_tx; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct ring_info tx_info[NUM_TX_DESC]; + unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ + unsigned char *tx_bufs; /* Tx bounce buffer region. */ + dma_addr_t rx_ring_dma; + dma_addr_t tx_bufs_dma; + char phys[4]; /* MII device addresses. */ + char twistie, twist_row, twist_col; /* Twister tune state. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + spinlock_t lock; + chip_t chipset; +}; + + + +static int read_eeprom (void *ioaddr, int location, int addr_len); +static int rtl8139_open (struct device *dev); +static int mdio_read (struct device *dev, int phy_id, int location); +static void mdio_write (struct device *dev, int phy_id, int location, + int val); +static void rtl8139_timer (unsigned long data); +static void rtl8139_tx_timeout (struct device *dev); +static void rtl8139_init_ring (struct device *dev); +static int rtl8139_start_xmit (struct sk_buff *skb, + struct device *dev); +static void rtl8139_interrupt (int irq, void *dev_instance, + struct pt_regs *regs); +static int rtl8139_close (struct device *dev); +static int mii_ioctl (struct device *dev, struct ifreq *rq, int cmd); +static struct net_device_stats *rtl8139_get_stats (struct device *dev); +static inline u32 ether_crc (int length, unsigned char *data); +static void rtl8139_set_rx_mode (struct device *dev); +static void rtl8139_hw_start (struct device *dev); + + +#ifdef USE_IO_OPS + +#define RTL_R8(reg) inb (((unsigned long)ioaddr) + (reg)) +#define RTL_R16(reg) inw (((unsigned long)ioaddr) + (reg)) +#define RTL_R32(reg) inl (((unsigned long)ioaddr) + (reg)) +#define RTL_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg)) +#define RTL_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg)) +#define RTL_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg)) +#define RTL_W8_F RTL_W8 +#define RTL_W16_F RTL_W16 +#define RTL_W32_F RTL_W32 +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb(addr) inb((unsigned long)(addr)) +#define readw(addr) inw((unsigned long)(addr)) +#define readl(addr) inl((unsigned long)(addr)) +#define writeb(val,addr) outb((val),(unsigned long)(addr)) +#define writew(val,addr) outw((val),(unsigned long)(addr)) +#define writel(val,addr) outl((val),(unsigned long)(addr)) + +#else + +/* write MMIO register, with flush */ +/* Flush avoids rtl8139 bug w/ posted MMIO writes */ +#define RTL_W8_F(reg, val8) do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0) +#define RTL_W16_F(reg, val16) do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0) +#define RTL_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0) + + +#if MMIO_FLUSH_AUDIT_COMPLETE + +/* write MMIO register */ +#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) +#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) +#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) + +#else + +/* write MMIO register, then flush */ +#define RTL_W8 RTL_W8_F +#define RTL_W16 RTL_W16_F +#define RTL_W32 RTL_W32_F + +#endif /* MMIO_FLUSH_AUDIT_COMPLETE */ + +/* read MMIO register */ +#define RTL_R8(reg) readb (ioaddr + (reg)) +#define RTL_R16(reg) readw (ioaddr + (reg)) +#define RTL_R32(reg) readl (ioaddr + (reg)) + +#endif /* USE_IO_OPS */ + + +static const u16 rtl8139_intr_mask = + PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | + TxErr | TxOK | RxErr | RxOK; + +static const unsigned int rtl8139_rx_config = + RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); + + +static int rtl8139_init_board (struct pci_dev *pdev, struct device **dev_out, + void **ioaddr_out) +{ + void *ioaddr = NULL; + struct device *dev; + struct rtl8139_private *tp; + u8 tmp8; + int rc, i; + u32 pio_start, pio_end, pio_flags, pio_len; + unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + u32 tmp; + u16 pci_command, new_command; + + DPRINTK ("ENTER\n"); + + assert (pdev != NULL); + assert (ioaddr_out != NULL); + + *ioaddr_out = NULL; + *dev_out = NULL; + + /* dev zeroed in init_etherdev */ + dev = init_etherdev (NULL, sizeof (*tp)); + if (dev == NULL) { + printk (KERN_ERR PFX "unable to alloc new ethernet\n"); + DPRINTK ("EXIT, returning -ENOMEM\n"); + return -ENOMEM; + } + tp = dev->priv; + + rtl8139_read_pci_resources(pdev, &tp->rtl8139_pci_resource[0]); + + pio_start = pci_resource_start (tp, 0); + pio_end = pci_resource_end (tp, 0); + pio_flags = pci_resource_flags (tp, 0); + pio_len = pci_resource_len (tp, 0); + + mmio_start = pci_resource_start (tp, 1); + mmio_end = pci_resource_end (tp, 1); + mmio_flags = pci_resource_flags (tp, 1); + mmio_len = pci_resource_len (tp, 1); + + /* set this immediately, we need to know before + * we talk to the chip directly */ + DPRINTK("PIO region size == 0x%02X\n", pio_len); + DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); + if (pio_len == RTL8139B_IO_SIZE) + tp->chipset = CH_8139B; + + /* make sure PCI base addr 0 is PIO */ + if (!(pio_flags & IORESOURCE_IO)) { + printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; + } + + /* make sure PCI base addr 1 is MMIO */ + if (!(mmio_flags & IORESOURCE_MEM)) { + printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; + } + + /* check for weird/broken PCI region reporting */ + if ((pio_len != mmio_len) || + (pio_len < RTL_MIN_IO_SIZE) || + (mmio_len < RTL_MIN_IO_SIZE)) { + printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + rc = -ENODEV; + goto err_out; + } + + /* make sure our PIO region in PCI space is available */ + if (check_region(pio_start, pio_len)) { + printk (KERN_ERR PFX "no I/O resource available, aborting\n"); + rc = -EBUSY; + goto err_out; + } + request_region(pio_start, pio_len, dev->name); + + pci_set_master (pdev); + +#ifdef USE_IO_OPS + ioaddr = (void *) pio_start; +#else + /* ioremap MMIO region */ + ioaddr = ioremap_nocache(mmio_start, mmio_len); + + if (ioaddr == NULL) { + printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); + rc = -EIO; + goto err_out_free_mmio; + } +#endif /* USE_IO_OPS */ + + /* Activate the card: fix for brain-damaged Win98 BIOSes. */ + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + new_command = pci_command | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER; + if (pci_command != new_command) + pci_write_config_word(pdev, PCI_COMMAND, new_command); + + /* Soft reset the chip. */ + RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 10000; i > 0; i--) + if ((RTL_R8 (ChipCmd) & CmdReset) == 0) + break; + else + udelay (10); + + /* Bring the chip out of low-power mode. */ + if (tp->chipset == CH_8139B) { + RTL_W8 (Config1, RTL_R8 (Config1) & ~(1<<4)); + RTL_W8 (Config4, RTL_R8 (Config4) & ~(1<<2)); + } else { + /* handle RTL8139A and RTL8139 cases */ + /* XXX from becker driver. is this right?? */ + RTL_W8 (Config1, 0); + } + +#ifndef USE_IO_OPS + /* sanity checks -- ensure PIO and MMIO registers agree */ + assert (inb (pio_start+Config0) == readb (ioaddr+Config0)); + assert (inb (pio_start+Config1) == readb (ioaddr+Config1)); + assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig)); + assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); +#endif /* !USE_IO_OPS */ + + /* make sure chip thinks PIO and MMIO are enabled */ + tmp8 = RTL_R8 (Config1); + if ((tmp8 & Cfg1_PIO) == 0) { + printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); + rc = -EIO; + goto err_out_iounmap; + } + if ((tmp8 & Cfg1_MMIO) == 0) { + printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); + rc = -EIO; + goto err_out_iounmap; + } + + /* identify chip attached to board */ + tmp = RTL_R8 (ChipVersion); + for (i = arraysize (rtl_chip_info) - 1; i >= 0; i--) + if (tmp == rtl_chip_info[i].version) { + tp->chipset = i; + goto match; + } + + /* if unknown chip, assume array element #0, original RTL-8139 in this case */ + printk (KERN_DEBUG PFX "PCI device %08lX: unknown chip version, assuming RTL-8139\n", + (unsigned long) pdev); + printk (KERN_DEBUG PFX "PCI device %08lX: TxConfig = 0x%x\n", (unsigned long) pdev, RTL_R32 (TxConfig)); + tp->chipset = 0; + +match: + DPRINTK ("chipset id (%d) == index %d, '%s'\n", + tmp, + tp->chipset, + rtl_chip_info[tp->chipset].name); + + DPRINTK ("EXIT, returning 0\n"); + *ioaddr_out = ioaddr; + *dev_out = dev; + return 0; + +err_out_iounmap: + assert (ioaddr > 0); +#ifndef USE_IO_OPS + iounmap (ioaddr); +#endif /* !USE_IO_OPS */ +err_out_free_mmio: + release_region (pio_start, pio_len); +err_out: + unregister_netdev (dev); + kfree (dev); + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + +static int rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct device *dev = NULL; + struct rtl8139_private *tp; + int i, addr_len, option; + void *ioaddr = NULL; + static int board_idx = -1; + u8 tmp; + + DPRINTK ("ENTER\n"); + + assert (pdev != NULL); + assert (ent != NULL); + + board_idx++; + + i = rtl8139_init_board (pdev, &dev, &ioaddr); + if (i < 0) { + DPRINTK ("EXIT, returning %d\n", i); + return i; + } + + tp = dev->priv; + + assert (ioaddr != NULL); + assert (dev != NULL); + assert (tp != NULL); + + addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; + for (i = 0; i < 3; i++) + ((u16 *) (dev->dev_addr))[i] = + le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); + + /* The Rtl8139-specific entries in the device structure. */ + dev->open = rtl8139_open; + dev->hard_start_xmit = rtl8139_start_xmit; + dev->stop = rtl8139_close; + dev->get_stats = rtl8139_get_stats; + dev->set_multicast_list = rtl8139_set_rx_mode; + dev->do_ioctl = mii_ioctl; + + dev->irq = pdev->irq; + dev->base_addr = (unsigned long) ioaddr; + + /* dev->priv/tp zeroed and aligned in init_etherdev */ + tp = dev->priv; + + /* note: tp->chipset set in rtl8139_init_board */ + tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | RTL8139_CAPS; + tp->pci_dev = pdev; + tp->board = ent->board; + tp->mmio_addr = ioaddr; + tp->lock = SPIN_LOCK_UNLOCKED; + + tp->phys[0] = 32; + + if (rtl8139_device_count == 0) { + printk (KERN_INFO "%s: " RTL8139_DRIVER_NAME " " RTL8139_AUTHOR "\n", dev->name); + printk (KERN_INFO "%s: Linux-2.2 bug reports to Jens David \n", dev->name); + } + + printk (KERN_INFO "%s: %s board found at 0x%lx, IRQ %d\n", + dev->name, board_info[ent->board].name, + dev->base_addr, dev->irq); + + printk (KERN_INFO "%s: Chip is '%s' - MAC address '%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x'.\n", + dev->name, + rtl_chip_info[tp->chipset].name, + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + /* Put the chip into low-power mode. */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + + tmp = RTL_R8 (Config1) & Config1Clear; + tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ + RTL_W8_F (Config1, tmp); + + RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ + + /* The lower four bits are the media type. */ + option = (board_idx > 7) ? 0 : media[board_idx]; + if (option > 0) { + tp->full_duplex = (option & 0x200) ? 1 : 0; + tp->default_port = option & 15; + if (tp->default_port) + tp->medialock = 1; + } + + if (tp->full_duplex) { + printk (KERN_INFO + "%s: Media type forced to Full Duplex.\n", + dev->name); + mdio_write (dev, tp->phys[0], 4, 0x141); + tp->duplex_lock = 1; + } + + rtl8139_device_tab[rtl8139_device_count++] = dev; + + DPRINTK ("EXIT - returning 0\n"); + return 0; +} + +static void rtl8139_remove_one (struct device *dev) +{ + struct pci_dev *pdev; + struct rtl8139_private *np; + + DPRINTK ("ENTER\n"); + + assert (dev != NULL); + + np = (struct rtl8139_private *) (dev->priv); + assert (np != NULL); + + pdev = np->pci_dev; + assert (pdev != NULL); + + unregister_netdev (dev); + +#ifndef USE_IO_OPS + iounmap (np->mmio_addr); +#endif /* !USE_IO_OPS */ + + release_region (pci_resource_start (np, 0), + pci_resource_len (np, 0)); +#ifndef RTL8139_NDEBUG + /* poison memory before freeing */ + memset (dev, 0xBC, + sizeof (struct device) + + sizeof (struct rtl8139_private)); +#endif /* RTL8139_NDEBUG */ + + kfree (dev); + + DPRINTK ("EXIT\n"); +} + +/* Serial EEPROM section. */ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ +#define EE_CS 0x08 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x00 +#define EE_WRITE_1 0x02 +#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ +#define EE_ENB (0x80 | EE_CS) + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. + */ + +#define eeprom_delay() readl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5) +#define EE_READ_CMD (6) +#define EE_ERASE_CMD (7) + +static int read_eeprom (void *ioaddr, int location, int addr_len) +{ + int i; + unsigned retval = 0; + void *ee_addr = ioaddr + Cfg9346; + int read_cmd = location | (EE_READ_CMD << addr_len); + + DPRINTK ("ENTER\n"); + + writeb (EE_ENB & ~EE_CS, ee_addr); + writeb (EE_ENB, ee_addr); + eeprom_delay (); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + writeb (EE_ENB | dataval, ee_addr); + eeprom_delay (); + writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay (); + } + writeb (EE_ENB, ee_addr); + eeprom_delay (); + + for (i = 16; i > 0; i--) { + writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay (); + retval = + (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 : + 0); + writeb (EE_ENB, ee_addr); + eeprom_delay (); + } + + /* Terminate the EEPROM access. */ + writeb (~EE_CS, ee_addr); + eeprom_delay (); + + DPRINTK ("EXIT - returning %d\n", retval); + return retval; +} + +/* MII serial management: mostly bogus for now. */ +/* Read and write the MII management registers using software-generated + serial MDIO protocol. + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues. */ +#define MDIO_DIR 0x80 +#define MDIO_DATA_OUT 0x04 +#define MDIO_DATA_IN 0x02 +#define MDIO_CLK 0x01 +#define MDIO_WRITE0 (MDIO_DIR) +#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) + +#define mdio_delay() readb(mdio_addr) + + +static char mii_2_8139_map[8] = { + BasicModeCtrl, + BasicModeStatus, + 0, + 0, + NWayAdvert, + NWayLPAR, + NWayExpansion, + 0 +}; + + +/* Syncronize the MII management interface by shifting 32 one bits out. */ +static void mdio_sync (void *mdio_addr) +{ + int i; + + DPRINTK ("ENTER\n"); + + for (i = 32; i >= 0; i--) { + writeb (MDIO_WRITE1, mdio_addr); + mdio_delay (); + writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); + mdio_delay (); + } + + DPRINTK ("EXIT\n"); +} + + +static int mdio_read (struct device *dev, int phy_id, int location) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *mdio_addr = tp->mmio_addr + Config4; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + int i; + + DPRINTK ("ENTER\n"); + + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ + DPRINTK ("EXIT after directly using 8139 internal regs\n"); + return location < 8 && mii_2_8139_map[location] ? + readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; + } + mdio_sync (mdio_addr); + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; + + writeb (MDIO_DIR | dataval, mdio_addr); + mdio_delay (); + writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); + mdio_delay (); + } + + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + writeb (0, mdio_addr); + mdio_delay (); + retval = + (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 + : 0); + writeb (MDIO_CLK, mdio_addr); + mdio_delay (); + } + + DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); + return (retval >> 1) & 0xffff; +} + + +static void mdio_write (struct device *dev, int phy_id, int location, + int value) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *mdio_addr = tp->mmio_addr + Config4; + int mii_cmd = + (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + int i; + + DPRINTK ("ENTER\n"); + + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ + if (location < 8 && mii_2_8139_map[location]) { + writew (value, + tp->mmio_addr + mii_2_8139_map[location]); + readw (tp->mmio_addr + mii_2_8139_map[location]); + } + DPRINTK ("EXIT after directly using 8139 internal regs\n"); + return; + } + mdio_sync (mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = + (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + writeb (dataval, mdio_addr); + mdio_delay (); + writeb (dataval | MDIO_CLK, mdio_addr); + mdio_delay (); + } + + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + writeb (0, mdio_addr); + mdio_delay (); + writeb (MDIO_CLK, mdio_addr); + mdio_delay (); + } + + DPRINTK ("EXIT\n"); +} + + +static int rtl8139_open (struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + int retval; +#ifdef RTL8139_DEBUG + void *ioaddr = tp->mmio_addr; +#endif + + DPRINTK ("ENTER\n"); + + MOD_INC_USE_COUNT; + + retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); + if (retval) { + DPRINTK ("EXIT, returning %d\n", retval); + MOD_DEC_USE_COUNT; + return retval; + } + + tp->tx_bufs = kmalloc(TX_BUF_TOT_LEN, GFP_KERNEL | GFP_DMA); + tp->tx_bufs_dma = virt_to_bus(tp->tx_bufs); + tp->rx_ring = kmalloc(RX_BUF_TOT_LEN, GFP_KERNEL | GFP_DMA); + tp->rx_ring_dma = virt_to_bus(tp->rx_ring); + + if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { + free_irq(dev->irq, dev); + + if (tp->tx_bufs) kfree(tp->tx_bufs); + if (tp->rx_ring) kfree(tp->rx_ring); + + DPRINTK ("EXIT, returning -ENOMEM\n"); + MOD_DEC_USE_COUNT; + return -ENOMEM; + + } + + tp->full_duplex = tp->duplex_lock; + tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; + + rtl8139_init_ring (dev); + rtl8139_hw_start (dev); + + DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" + " GP Pins %2.2x %s-duplex.\n", + dev->name, pci_resource_start (tp, 1), + dev->irq, RTL_R8 (MediaStatus), + tp->full_duplex ? "full" : "half"); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer (&tp->timer); + tp->timer.expires = jiffies + 3 * HZ; + tp->timer.data = (unsigned long) dev; + tp->timer.function = &rtl8139_timer; + add_timer (&tp->timer); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* Start the hardware at open or resume. */ +static void rtl8139_hw_start (struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + u32 i; + u8 tmp; + + DPRINTK ("ENTER\n"); + + /* Soft reset the chip. */ + RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); + udelay (100); + + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--) + if ((RTL_R8 (ChipCmd) & CmdReset) == 0) + break; + + /* Restore our idea of the MAC address. */ + RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); + RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); + + /* Must enable Tx/Rx before setting transfer thresholds! */ + RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | + CmdRxEnb | CmdTxEnb); + + i = rtl8139_rx_config | + (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + RTL_W32_F (RxConfig, i); + + /* Check this value: the documentation for IFG contradicts ifself. */ + RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); + + /* unlock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + udelay (10); + + tp->cur_rx = 0; + + if (tp->chipset >= CH_8139A) { + tmp = RTL_R8 (Config1) & Config1Clear; + tmp |= Cfg1_Driver_Load; + tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ + RTL_W8_F (Config1, tmp); + } else { + u8 foo = RTL_R8 (Config1) & Config1Clear; + RTL_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); + } + + if (tp->chipset >= CH_8139B) { + tmp = RTL_R8 (Config4) & ~(1<<2); + /* chip will clear Rx FIFO overflow automatically */ + tmp |= (1<<7); + RTL_W8 (Config4, tmp); + + /* disable magic packet scanning, which is enabled + * when PM is enabled above (Config1) */ + RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); + } + + /* Lock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Lock); + udelay (10); + + /* init Rx ring buffer DMA address */ + RTL_W32_F (RxBuf, tp->rx_ring_dma); + + /* init Tx buffer DMA addresses */ + for (i = 0; i < NUM_TX_DESC; i++) + RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs)); + + RTL_W32_F (RxMissed, 0); + + rtl8139_set_rx_mode (dev); + + /* no early-rx interrupts */ + RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear); + + /* make sure RxTx has started */ + RTL_W8_F (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | + CmdRxEnb | CmdTxEnb); + + /* Enable all known interrupts by setting the interrupt mask. */ + RTL_W16_F (IntrMask, rtl8139_intr_mask); + + netif_start_queue (dev); + + DPRINTK ("EXIT\n"); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void rtl8139_init_ring (struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + int i; + + DPRINTK ("ENTER\n"); + + tp->cur_rx = 0; + atomic_set (&tp->cur_tx, 0); + atomic_set (&tp->dirty_tx, 0); + + for (i = 0; i < NUM_TX_DESC; i++) { + tp->tx_info[i].skb = NULL; + tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE]; + } + + DPRINTK ("EXIT\n"); +} + + +#ifndef RTL_TUNE_TWISTER +static inline void rtl8139_tune_twister (struct device *dev, + struct rtl8139_private *tp) {} +#else +static void rtl8139_tune_twister (struct device *dev, + struct rtl8139_private *tp) +{ + int linkcase; + + DPRINTK ("ENTER\n"); + + /* This is a complicated state machine to configure the "twister" for + impedance/echos based on the cable length. + All of this is magic and undocumented. + */ + switch (tp->twistie) { + case 1: + if (RTL_R16 (CSCR) & CSCR_LinkOKBit) { + /* We have link beat, let us tune the twister. */ + RTL_W16 (CSCR, CSCR_LinkDownOffCmd); + tp->twistie = 2; /* Change to state 2. */ + next_tick = HZ / 10; + } else { + /* Just put in some reasonable defaults for when beat returns. */ + RTL_W16 (CSCR, CSCR_LinkDownCmd); + RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */ + RTL_W32 (PARA78, PARA78_default); + RTL_W32 (PARA7c, PARA7c_default); + tp->twistie = 0; /* Bail from future actions. */ + } + break; + case 2: + /* Read how long it took to hear the echo. */ + linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits; + if (linkcase == 0x7000) + tp->twist_row = 3; + else if (linkcase == 0x3000) + tp->twist_row = 2; + else if (linkcase == 0x1000) + tp->twist_row = 1; + else + tp->twist_row = 0; + tp->twist_col = 0; + tp->twistie = 3; /* Change to state 2. */ + next_tick = HZ / 10; + break; + case 3: + /* Put out four tuning parameters, one per 100msec. */ + if (tp->twist_col == 0) + RTL_W16 (FIFOTMS, 0); + RTL_W32 (PARA7c, param[(int) tp->twist_row] + [(int) tp->twist_col]); + next_tick = HZ / 10; + if (++tp->twist_col >= 4) { + /* For short cables we are done. + For long cables (row == 3) check for mistune. */ + tp->twistie = + (tp->twist_row == 3) ? 4 : 0; + } + break; + case 4: + /* Special case for long cables: check for mistune. */ + if ((RTL_R16 (CSCR) & + CSCR_LinkStatusBits) == 0x7000) { + tp->twistie = 0; + break; + } else { + RTL_W32 (PARA7c, 0xfb38de03); + tp->twistie = 5; + next_tick = HZ / 10; + } + break; + case 5: + /* Retune for shorter cable (column 2). */ + RTL_W32 (FIFOTMS, 0x20); + RTL_W32 (PARA78, PARA78_default); + RTL_W32 (PARA7c, PARA7c_default); + RTL_W32 (FIFOTMS, 0x00); + tp->twist_row = 2; + tp->twist_col = 0; + tp->twistie = 3; + next_tick = HZ / 10; + break; + + default: + /* do nothing */ + break; + } + + DPRINTK ("EXIT\n"); +} +#endif /* RTL_TUNE_TWISTER */ + + +static void rtl8139_timer (unsigned long data) +{ + struct device *dev = (struct device *) data; + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int next_tick = 60 * HZ; + int mii_reg5; + + mii_reg5 = mdio_read (dev, tp->phys[0], 5); + + if (!tp->duplex_lock && mii_reg5 != 0xffff) { + int duplex = (mii_reg5 & 0x0100) + || (mii_reg5 & 0x01C0) == 0x0040; + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + printk (KERN_INFO + "%s: Setting %s-duplex based on MII #%d link" + " partner ability of %4.4x.\n", dev->name, + tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + RTL_W8 (Cfg9346, Cfg9346_Lock); + } + } + + rtl8139_tune_twister (dev, tp); + + DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", + dev->name, RTL_R16 (NWayLPAR)); + DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" + " RxStatus %4.4x.\n", dev->name, + RTL_R16 (IntrMask), + RTL_R16 (IntrStatus), + RTL_R32 (RxEarlyStatus)); + DPRINTK ("%s: Chip config %2.2x %2.2x.\n", + dev->name, RTL_R8 (Config0), + RTL_R8 (Config1)); + + tp->timer.expires = jiffies + next_tick; + add_timer (&tp->timer); +} + + +static void rtl8139_tx_timeout (struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int i; + unsigned long flags; + + DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " + "media %2.2x.\n", dev->name, + RTL_R8 (ChipCmd), + RTL_R16 (IntrStatus), + RTL_R8 (MediaStatus)); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0x0000); + + /* Emit info to figure out what went wrong. */ + printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", + dev->name, atomic_read (&tp->cur_tx), + atomic_read (&tp->dirty_tx)); + for (i = 0; i < NUM_TX_DESC; i++) + printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n", + dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), + i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? + " (queue head)" : ""); + + spin_lock_irqsave (&tp->lock, flags); + + /* Stop a shared interrupt from scavenging while we are. */ + atomic_set (&tp->cur_tx, 0); + atomic_set (&tp->dirty_tx, 0); + + /* Dump the unsent Tx packets. */ + for (i = 0; i < NUM_TX_DESC; i++) { + struct ring_info *rp = &tp->tx_info[i]; + if (rp->skb) { + dev_kfree_skb (rp->skb); + rp->skb = NULL; + tp->stats.tx_dropped++; + } + } + + spin_unlock_irqrestore (&tp->lock, flags); + + /* ...and finally, reset everything */ + rtl8139_hw_start (dev); +} + + + +static int rtl8139_start_xmit (struct sk_buff *skb, struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int entry; + + if (dev->tbusy) { + /* If this happens network layer tells us we're broken. */ + if (jiffies - dev->trans_start > TX_TIMEOUT) + rtl8139_tx_timeout(dev); + } + + /* Calculate the next Tx descriptor entry. */ + entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC; + + assert (tp->tx_info[entry].skb == NULL); + + tp->tx_info[entry].skb = skb; + memcpy (tp->tx_buf[entry], skb->data, skb->len); + + /* Note: the chip doesn't have auto-pad! */ + RTL_W32 (TxStatus0 + (entry * sizeof(u32)), + tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + + dev->trans_start = jiffies; + atomic_inc (&tp->cur_tx); + if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC) + netif_stop_queue (dev); + + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", + dev->name, skb->data, skb->len, entry); + + return 0; +} + + +static inline void rtl8139_tx_interrupt (struct device *dev, + struct rtl8139_private *tp, + void *ioaddr) +{ + unsigned int dirty_tx; + + assert (dev != NULL); + assert (tp != NULL); + assert (ioaddr != NULL); + + dirty_tx = atomic_read (&tp->dirty_tx); + + while ((atomic_read (&tp->cur_tx) - dirty_tx) > 0) { + int entry = dirty_tx % NUM_TX_DESC; + int txstatus; + + txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32))); + + if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted))) + break; /* It still hasn't been Txed */ + + /* Note: TxCarrierLost is always asserted at 100mbps. */ + if (txstatus & (TxOutOfWindow | TxAborted)) { + /* There was an major error, log it. */ + DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); + tp->stats.tx_errors++; + if (txstatus & TxAborted) { + tp->stats.tx_aborted_errors++; + RTL_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); + } + if (txstatus & TxCarrierLost) + tp->stats.tx_carrier_errors++; + if (txstatus & TxOutOfWindow) + tp->stats.tx_window_errors++; +#ifdef ETHER_STATS + if ((txstatus & 0x0f000000) == 0x0f000000) + tp->stats.collisions16++; +#endif + } else { + if (txstatus & TxUnderrun) { + /* Add 64 to the Tx FIFO threshold. */ + if (tp->tx_flag < 0x00300000) + tp->tx_flag += 0x00020000; + tp->stats.tx_fifo_errors++; + } + tp->stats.collisions += (txstatus >> 24) & 15; + tp->stats.tx_bytes += txstatus & 0x7ff; + tp->stats.tx_packets++; + } + + dev_kfree_skb_irq (tp->tx_info[entry].skb); + tp->tx_info[entry].skb = NULL; + dirty_tx++; + if (netif_queue_stopped (dev) && + (atomic_read (&tp->cur_tx) - dirty_tx < NUM_TX_DESC)) + netif_wake_queue (dev); + mark_bh(NET_BH); + } + +#ifndef RTL8139_NDEBUG + if (atomic_read (&tp->cur_tx) - dirty_tx > NUM_TX_DESC) { + printk (KERN_ERR + "%s: Out-of-sync dirty pointer, %d vs. %d.\n", + dev->name, dirty_tx, atomic_read (&tp->cur_tx)); + dirty_tx += NUM_TX_DESC; + } +#endif /* RTL8139_NDEBUG */ + + atomic_set (&tp->dirty_tx, dirty_tx); +} + +/* TODO: clean this up! Rx reset need not be this intensive */ +static void rtl8139_rx_err (u32 rx_status, struct device *dev, + struct rtl8139_private *tp, void *ioaddr) +{ + u8 tmp8; + int tmp_work = 1000; + + DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", + dev->name, rx_status); + if (rx_status & RxTooLong) { + DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", + dev->name, rx_status); + /* A.C.: The chip hangs here. */ + } + tp->stats.rx_errors++; + if (rx_status & (RxBadSymbol | RxBadAlign)) + tp->stats.rx_frame_errors++; + if (rx_status & (RxRunt | RxTooLong)) + tp->stats.rx_length_errors++; + if (rx_status & RxCRCErr) + tp->stats.rx_crc_errors++; + /* Reset the receiver, based on RealTek recommendation. (Bug?) */ + tp->cur_rx = 0; + + /* disable receive */ + tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear; + RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb); + + /* A.C.: Reset the multicast list. */ + rtl8139_set_rx_mode (dev); + + /* XXX potentially temporary hack to + * restart hung receiver */ + while (--tmp_work > 0) { + tmp8 = RTL_R8 (ChipCmd); + if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) + break; + RTL_W8_F (ChipCmd, + (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb); + } + + /* G.S.: Re-enable receiver */ + /* XXX temporary hack to work around receiver hang */ + rtl8139_set_rx_mode (dev); + + if (tmp_work <= 0) + printk (KERN_WARNING PFX "tx/rx enable wait too long\n"); +} + + +/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the + field alignments and semantics. */ +static void rtl8139_rx_interrupt (struct device *dev, + struct rtl8139_private *tp, void *ioaddr) +{ + unsigned char *rx_ring; + u16 cur_rx; + + assert (dev != NULL); + assert (tp != NULL); + assert (ioaddr != NULL); + + rx_ring = tp->rx_ring; + cur_rx = tp->cur_rx; + + DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," + " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, + RTL_R16 (RxBufAddr), + RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); + + while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { + int ring_offset = cur_rx % RX_BUF_LEN; + u32 rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); + int rx_size = rx_status >> 16; + struct sk_buff *skb; + int pkt_size = rx_size - 4; + + DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," + " cur %4.4x.\n", dev->name, rx_status, + rx_size, cur_rx); +#if RTL8139_DEBUG > 2 + { + int i; + DPRINTK ("%s: Frame contents ", dev->name); + for (i = 0; i < 70; i++) + printk (" %2.2x", + rx_ring[ring_offset + i]); + printk (".\n"); + } +#endif + + /* E. Gill */ + /* Note from BSD driver: + * Here's a totally undocumented fact for you. When the + * RealTek chip is in the process of copying a packet into + * RAM for you, the length will be 0xfff0. If you spot a + * packet header with this value, you need to stop. The + * datasheet makes absolutely no mention of this and + * RealTek should be shot for this. + */ + if (rx_size == 0xfff0) + break; + + /* if Rx err received, Rx process gets reset, so + * we abort any further Rx processing + */ + if (rx_status & + (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | RxBadAlign)) { + rtl8139_rx_err (rx_status, dev, tp, ioaddr); + return; + } + + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + + /* TODO: consider allocating skb's outside of + * interrupt context, both to speed interrupt processing, + * and also to reduce the chances of having to + * drop packets here under memory pressure. + */ + + skb = dev_alloc_skb (pkt_size + 2); + if (skb == NULL) { + printk (KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + dev->name); + tp->stats.rx_dropped++; + break; + } + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align the IP fields. */ + + eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); + skb_put (skb, pkt_size); + + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); + mark_bh(NET_BH); + tp->stats.rx_bytes += pkt_size ; + tp->stats.rx_packets++; + + cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; + RTL_W16_F (RxBufPtr, cur_rx - 16); + } + + DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," + " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, + RTL_R16 (RxBufAddr), + RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); + + tp->cur_rx = cur_rx; +} + + +static void rtl8139_weird_interrupt (struct device *dev, + struct rtl8139_private *tp, + void *ioaddr, + int status, int link_changed) +{ + printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n", + dev->name, status); + + assert (dev != NULL); + assert (tp != NULL); + assert (ioaddr != NULL); + + /* Update the error count. */ + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + + if ((status & RxUnderrun) && link_changed && + (tp->drv_flags & HAS_LNK_CHNG)) { + /* Really link-change on new chips. */ + int lpar = RTL_R16 (NWayLPAR); + int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040 + || tp->duplex_lock; + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + } + status &= ~RxUnderrun; + } + if (status & + (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) + tp->stats.rx_errors++; + + if (status & (PCSTimeout)) + tp->stats.rx_length_errors++; + if (status & (RxUnderrun | RxFIFOOver)) + tp->stats.rx_fifo_errors++; + if (status & RxOverflow) { + tp->stats.rx_over_errors++; + tp->cur_rx = RTL_R16 (RxBufAddr) % RX_BUF_LEN; + RTL_W16_F (RxBufPtr, tp->cur_rx - 16); + } + if (status & PCIErr) { + u16 pci_cmd_status; + pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); + + printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", + dev->name, pci_cmd_status); + } +} + + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void rtl8139_interrupt (int irq, void *dev_instance, + struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_instance; + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + int boguscnt = max_interrupt_work; + void *ioaddr = tp->mmio_addr; + int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ + + spin_lock (&tp->lock); + + do { + status = RTL_R16 (IntrStatus); + + /* h/w no longer present (hotplug?) or major error, bail */ + if (status == 0xFFFF) + break; + + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if (status & RxUnderrun) + link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; + + /* E. Gill */ + /* In case of an RxFIFOOver we must also clear the RxOverflow + bit to avoid dropping frames for ever. Believe me, I got a + lot of troubles copying huge data (approximately 2 RxFIFOOver + errors per 1GB data transfer). + The following is written in the 'p-guide.pdf' file (RTL8139(A/B) + Programming guide V0.1, from 1999/1/15) on page 9 from REALTEC. + ----------------------------------------------------------- + 2. RxFIFOOvw handling: + When RxFIFOOvw occurs, all incoming packets are discarded. + Clear ISR(RxFIFOOvw) doesn't dismiss RxFIFOOvw event. To + dismiss RxFIFOOvw event, the ISR(RxBufOvw) must be written + with a '1'. + ----------------------------------------------------------- + Unfortunately I was not able to find any reason for the + RxFIFOOver error (I got the feeling this depends on the + CPU speed, lower CPU speed --> more errors). + After clearing the RxOverflow bit the transfer of the + packet was repeated and all data are error free transfered */ + RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); + + DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", + dev->name, status, + RTL_R16 (IntrStatus)); + + if ((status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow + | RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) + break; + + /* Check uncommon events with one test. */ + if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | + RxFIFOOver | TxErr | RxErr)) + rtl8139_weird_interrupt (dev, tp, ioaddr, + status, link_changed); + + if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ + rtl8139_rx_interrupt (dev, tp, ioaddr); + + if (status & (TxOK | TxErr)) + rtl8139_tx_interrupt (dev, tp, ioaddr); + + boguscnt--; + } while (boguscnt > 0); + + if (boguscnt <= 0) { + printk (KERN_WARNING + "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", dev->name, + status); + + /* Clear all interrupt sources. */ + RTL_W16 (IntrStatus, 0xffff); + } + + spin_unlock (&tp->lock); + + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", + dev->name, RTL_R16 (IntrStatus)); +} + + +static int rtl8139_close (struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int i; + unsigned long flags; + + DPRINTK ("ENTER\n"); + + netif_stop_queue (dev); + dev->start = 0; + + DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", + dev->name, RTL_R16 (IntrStatus)); + + del_timer (&tp->timer); + + spin_lock_irqsave (&tp->lock, flags); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0x0000); + + /* Stop the chip's Tx and Rx DMA processes. */ + RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear)); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); + + /* snooze for a small bit */ + if (current->need_resched) + schedule (); + + free_irq (dev->irq, dev); + + for (i = 0; i < NUM_TX_DESC; i++) { + struct sk_buff *skb = tp->tx_info[i].skb; + + if (skb) { + dev_kfree_skb (skb); + DPRINTK("PCI unmap?\n"); + } + tp->tx_info[i].skb = NULL; + } + + kfree(tp->rx_ring); + kfree(tp->tx_bufs); + tp->rx_ring = NULL; + tp->tx_bufs = NULL; + + /* Green! Put the chip in low-power mode. */ + RTL_W8 (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, 0x03); + RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + + MOD_DEC_USE_COUNT; + + DPRINTK ("EXIT\n"); + return 0; +} + + +static int mii_ioctl (struct device *dev, struct ifreq *rq, int cmd) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + u16 *data = (u16 *) & rq->ifr_data; + unsigned long flags; + int rc = 0; + + DPRINTK ("ENTER\n"); + + switch (cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = tp->phys[0] & 0x3f; + /* Fall Through */ + + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + spin_lock_irqsave (&tp->lock, flags); + data[3] = mdio_read (dev, data[0], data[1] & 0x1f); + spin_unlock_irqrestore (&tp->lock, flags); + break; + + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + if (!capable (CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + spin_lock_irqsave (&tp->lock, flags); + mdio_write (dev, data[0], data[1] & 0x1f, data[2]); + spin_unlock_irqrestore (&tp->lock, flags); + break; + + default: + rc = -EOPNOTSUPP; + break; + } + + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + + +static struct net_device_stats *rtl8139_get_stats (struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + + DPRINTK ("ENTER\n"); + + assert (tp != NULL); + + if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); + } + + DPRINTK ("EXIT\n"); + return &tp->stats; +} + + + +/* Set or clear the multicast filter for this adaptor. + This routine is not state sensitive and need not be SMP locked. */ + +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc (int length, unsigned char *data) +{ + int crc = -1; + + DPRINTK ("ENTER\n"); + + while (--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? + ethernet_polynomial : 0); + } + + DPRINTK ("EXIT\n"); + return crc; +} + + +static void rtl8139_set_rx_mode (struct device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + u32 mc_filter[2]; /* Multicast hash filter */ + int i, rx_mode; + u32 tmp; + + DPRINTK ("ENTER\n"); + + DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", + dev->name, dev->flags, RTL_R32 (RxConfig)); + + /* Note: do not reorder, GCC is clever about common statements. */ + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); + rx_mode = + AcceptBroadcast | AcceptMulticast | AcceptMyPhys | + AcceptAllPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else { + struct dev_mc_list *mclist; + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, + mc_filter); + } + + spin_lock_irq (&tp->lock); + + /* We can safely update without stopping the chip. */ + tmp = rtl8139_rx_config | rx_mode | + (RTL_R32 (RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); + RTL_W32_F (RxConfig, tmp); + RTL_W32_F (MAR0 + 0, mc_filter[0]); + RTL_W32_F (MAR0 + 4, mc_filter[1]); + + spin_unlock_irq (&tp->lock); + + DPRINTK ("EXIT\n"); +} + + +int rtl8139_init(void) +{ + struct pci_dev *pcidev; + struct pci_device_id *pdid; + + if (rtl8139_initialized) return -ENODEV; + for (pdid=&rtl8139_pci_tbl[0]; pdid->vendor != 0; pdid++) { + for (pcidev = pci_find_device(pdid->vendor, pdid->device, NULL); pcidev != NULL; pcidev = pci_find_device(pdid->vendor, pdid->device, pcidev)) { + if (rtl8139_init_one(pcidev, pdid) != 0) { + printk(KERN_ERR "Error initializing PCI device %08lX.\n", (unsigned long) pcidev); + } + } + } + rtl8139_initialized++; + return (rtl8139_device_count > 0 ? 0 : -ENODEV); +} + +void rtl8139_cleanup(void) +{ + int i; + + for (i=0; i #include #include +#include #define NEXT_DEV NULL @@ -114,6 +115,7 @@ extern int am79c961_probe(struct device *dev); extern int epic100_probe(struct device *dev); extern int rtl8139_probe(struct device *dev); +extern int rtl8139too_probe(struct device *dev); extern int sis900_probe(struct device *dev); extern int hplance_probe(struct device *dev); extern int bagetlance_probe(struct device *); @@ -140,6 +142,7 @@ /* FDDI adapters */ extern int dfx_probe(struct device *dev); extern int apfddi_init(struct device *dev); +extern int skfp_probe(struct device *dev); /* HIPPI boards */ extern int rr_hippi_probe(struct device *); @@ -171,13 +174,35 @@ struct devprobe *p = plist; unsigned long base_addr = dev->base_addr; +#ifdef CONFIG_NET_DIVERT + int ret; +#endif + while (p->probe != NULL) { if (base_addr && p->probe(dev) == 0) /* probe given addr */ +#ifdef CONFIG_NET_DIVERT + { + ret=alloc_divert_blk(dev); + if (ret) + return ret; return 0; + } +#else + return 0; +#endif else if (p->status == 0) { /* has autoprobe failed yet? */ p->status = p->probe(dev); /* no, try autoprobe */ if (p->status == 0) +#ifdef CONFIG_NET_DIVERT + { + ret=alloc_divert_blk(dev); + if (ret) + return ret; return 0; + } +#else + return 0; +#endif } p++; } @@ -226,6 +251,9 @@ #ifdef CONFIG_RTL8139 {rtl8139_probe, 0}, #endif +#ifdef CONFIG_RTL8139TOO + {rtl8139too_probe, 0}, +#endif #ifdef CONFIG_SIS900 {sis900_probe, 0}, #endif @@ -583,6 +611,9 @@ #endif #ifdef CONFIG_APFDDI && apfddi_init(dev) +#endif +#ifdef CONFIG_SKFP + && skfp_probe(dev) #endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.2.17/drivers/net/acenic.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/net/acenic.c Tue Nov 21 17:37:51 2000 @@ -2,7 +2,7 @@ * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card * and other Tigon based cards. * - * Copyright 1998-2000 by Jes Sorensen, . + * Copyright 1998-2000 by Jes Sorensen, . * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. @@ -29,7 +29,16 @@ * infrastructure and Sparc support * Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the * driver under Linux/Sparc64 - * Matt Domsch : Detect 1000baseT cards + * Matt Domsch : Detect Alteon 1000baseT cards + * Chip Salzenberg : Fix race condition between tx + * handler and close() cleanup. + * Ken Aaker : Correct check for whether + * memory mapped IO is enabled to + * make the driver work on RS/6000. + * Stephen Hack : Fixed ace_set_mac_addr for little + * endian systems. + * Val Henson : Reset Jumbo skb producer and rx producer + * index when flushing the Jumbo ring. */ #include @@ -83,8 +92,13 @@ #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a #endif +#ifndef PCI_DEVICE_ID_NETGEAR_GA620T +#define PCI_DEVICE_ID_NETGEAR_GA620T 0x630a +#endif + /* - * They used the DEC vendor ID by mistake + * Farallon used the DEC vendor ID by mistake and they seem not + * to care - stinky! */ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX #define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a @@ -124,7 +138,6 @@ #endif #if (LINUX_VERSION_CODE < 0x02032a) -typedef u32 dma_addr_t; static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) @@ -389,7 +402,7 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; static const char __initdata *version = - "acenic.c: v0.44 05/11/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" + "acenic.c: v0.46 2000/09/05 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev = NULL; @@ -429,7 +442,8 @@ !((pdev->vendor == PCI_VENDOR_ID_3COM) && (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && - (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620)) && + ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) || + (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) && /* * Farallon used the DEC vendor ID on their cards by * mistake for a while @@ -480,7 +494,7 @@ pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); /* OpenFirmware on Mac's does not set this - DOH.. */ - if (!ap->pci_command & PCI_COMMAND_MEMORY) { + if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { printk(KERN_INFO "%s: Enabling PCI Memory Mapped " "access - was not enabled by BIOS/Firmware\n", dev->name); @@ -597,8 +611,7 @@ } -#ifdef MODULE -MODULE_AUTHOR("Jes Sorensen "); +MODULE_AUTHOR("Jes Sorensen "); MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i"); @@ -606,7 +619,6 @@ MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); -#endif void __exit ace_module_cleanup(void) @@ -712,7 +724,7 @@ return status; } - +#ifdef MODULE #if (LINUX_VERSION_CODE < 0x02032a) int init_module(void) { @@ -728,7 +740,7 @@ module_init(ace_module_init); module_exit(ace_module_cleanup); #endif - +#endif static void ace_free_descriptors(struct net_device *dev) { @@ -1010,7 +1022,7 @@ pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache); if ((cache << 2) != SMP_CACHE_BYTES) { printk(KERN_INFO " PCI cache line size set incorrectly " - "(%i bytes) by BIOS/FW, corring to %i\n", + "(%i bytes) by BIOS/FW, correcting to %i\n", (cache << 2), SMP_CACHE_BYTES); pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, SMP_CACHE_BYTES >> 2); @@ -1065,7 +1077,7 @@ default: printk(KERN_INFO " Cache line size %i not " "supported, PCI write and invalidate " - "disabled\n", L1_CACHE_BYTES); + "disabled\n", SMP_CACHE_BYTES); ap->pci_command &= ~PCI_COMMAND_INVALIDATE; pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); @@ -1819,7 +1831,20 @@ ap->skb->rx_jumbo_skbuff[i].skb = NULL; } } + + if (ACE_IS_TIGON_I(ap)) { + struct cmd cmd; + cmd.evt = C_SET_RX_JUMBO_PRD_IDX; + cmd.code = 0; + cmd.idx = 0; + ace_issue_cmd(ap->regs, &cmd); + } else { + writel(0, &((ap->regs)->RxJumboPrd)); + wmb(); + } + ap->jumbo = 0; + ap->rx_jumbo_skbprd = 0; printk(KERN_INFO "%s: Jumbo ring flushed\n", dev->name); if (!ap->tx_full) @@ -1996,6 +2021,19 @@ struct sk_buff *skb; skb = ap->skb->tx_skbuff[idx].skb; + /* + * Race condition between the code cleaning + * the tx queue in the interrupt handler and the + * interface close, + * + * This is a kludge that really should be fixed + * by preventing the driver from generating a tx + * interrupt when the packet has already been + * removed from the tx queue. + * + * Nailed by Don Dugger and Chip Salzenberg of + * VA Linux. + */ if (skb) { dma_addr_t mapping; @@ -2532,7 +2570,7 @@ { struct sockaddr *addr=p; struct ace_regs *regs; - u16 *da; + u8 *da; struct cmd cmd; if(netif_running(dev)) @@ -2540,11 +2578,11 @@ memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); - da = (u16 *)dev->dev_addr; + da = (u8 *)dev->dev_addr; regs = ((struct ace_private *)dev->priv)->regs; - writel(da[0], ®s->MacAddrHi); - writel((da[1] << 16) | da[2], ®s->MacAddrLo); + writel(da[0] << 8 | da[1], ®s->MacAddrHi); + writel((da[2] << 24) | (da[3] << 16) | (da[4] << 8) | da[5] , ®s->MacAddrLo); cmd.evt = C_SET_MAC_ADDR; cmd.code = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.2.17/drivers/net/acenic.h Sun Jun 11 21:44:14 2000 +++ linux/drivers/net/acenic.h Fri Sep 8 16:58:34 2000 @@ -609,7 +609,7 @@ struct timer_list timer; unsigned long std_refill_busy - __attribute__ ((aligned (L1_CACHE_BYTES))); + __attribute__ ((aligned (SMP_CACHE_BYTES))); unsigned long mini_refill_busy, jumbo_refill_busy; atomic_t cur_rx_bufs, cur_mini_bufs, @@ -642,7 +642,7 @@ char name[48]; #ifdef INDEX_DEBUG spinlock_t debug_lock - __attribute__ ((aligned (L1_CACHE_BYTES)));; + __attribute__ ((aligned (SMP_CACHE_BYTES)));; u32 last_tx, last_std_rx, last_mini_rx; #endif struct net_device_stats stats; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c --- v2.2.17/drivers/net/am79c961a.c Fri Apr 21 12:46:15 2000 +++ linux/drivers/net/am79c961a.c Mon Oct 2 10:08:21 2000 @@ -38,35 +38,29 @@ static void am79c961_setmulticastlist (struct device *dev); -static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n"; - -#define FUNC_PROLOGUE \ - struct dev_priv *priv = (struct dev_priv *)dev->priv +static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.01\n"; /* --------------------------------------------------------------------------- */ +#ifdef __arm__ static void write_rreg (unsigned long base, unsigned int reg, unsigned short val) { - __asm__(" - strh %1, [%2] @ NET_RAP - strh %0, [%2, #-4] @ NET_RDP + __asm__("str%?h %1, [%2] @ NET_RAP + str%?h %0, [%2, #-4] @ NET_RDP " : : "r" (val), "r" (reg), "r" (0xf0000464)); } static inline void write_ireg (unsigned long base, unsigned int reg, unsigned short val) { - __asm__(" - strh %1, [%2] @ NET_RAP - strh %0, [%2, #8] @ NET_RDP + __asm__("str%?h %1, [%2] @ NET_RAP + str%?h %0, [%2, #8] @ NET_RDP " : : "r" (val), "r" (reg), "r" (0xf0000464)); } #define am_writeword(dev,off,val)\ - __asm__("\ - strh %0, [%1]\ - " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1))); + __asm__("str%?h %0, [%1]" : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1))); static inline void am_writebuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length) @@ -74,30 +68,28 @@ offset = 0xe0000000 + (offset << 1); length = (length + 1) & ~1; if ((int)buf & 2) { - __asm__ __volatile__(" - strh %2, [%0], #4 - " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + __asm__ __volatile__("str%?h %2, [%0], #4" + : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); buf += 2; length -= 2; } while (length > 8) { unsigned int tmp, tmp2; __asm__ __volatile__(" - ldmia %1!, {%2, %3} - strh %2, [%0], #4 - mov %2, %2, lsr #16 - strh %2, [%0], #4 - strh %3, [%0], #4 - mov %3, %3, lsr #16 - strh %3, [%0], #4 - " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) + ldm%?ia %1!, {%2, %3} + str%?h %2, [%0], #4 + mov%? %2, %2, lsr #16 + str%?h %2, [%0], #4 + str%?h %3, [%0], #4 + mov%? %3, %3, lsr #16 + str%?h %3, [%0], #4 + " : "=&r" (offset), "=&r" (buf), "=&r" (tmp), "=&r" (tmp2) : "0" (offset), "1" (buf)); length -= 8; } while (length > 0) { - __asm__ __volatile__(" - strh %2, [%0], #4 - " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + __asm__ __volatile__("str%?h %2, [%0], #4" + : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); buf += 2; length -= 2; } @@ -107,9 +99,8 @@ read_rreg (unsigned int base_addr, unsigned int reg) { unsigned short v; - __asm__(" - strh %1, [%2] @ NET_RAP - ldrh %0, [%2, #-4] @ NET_IDP + __asm__("str%?h %1, [%2] @ NET_RAP + ldr%?h %0, [%2, #-4] @ NET_IDP " : "=r" (v): "r" (reg), "r" (0xf0000464)); return v; } @@ -120,9 +111,7 @@ unsigned long address = 0xe0000000 + (off << 1); unsigned short val; - __asm__(" - ldrh %0, [%1] - " : "=r" (val): "r" (address)); + __asm__("ldr%?h %0, [%1]" : "=r" (val): "r" (address)); return val; } @@ -134,38 +123,41 @@ if ((int)buf & 2) { unsigned int tmp; __asm__ __volatile__(" - ldrh %2, [%0], #4 - strb %2, [%1], #1 - mov %2, %2, lsr #8 - strb %2, [%1], #1 + ldr%?h %2, [%0], #4 + str%?b %2, [%1], #1 + mov%? %2, %2, lsr #8 + str%?b %2, [%1], #1 " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); length -= 2; } while (length > 8) { unsigned int tmp, tmp2, tmp3; __asm__ __volatile__(" - ldrh %2, [%0], #4 - ldrh %3, [%0], #4 - orr %2, %2, %3, lsl #16 - ldrh %3, [%0], #4 - ldrh %4, [%0], #4 - orr %3, %3, %4, lsl #16 - stmia %1!, {%2, %3} - " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) + ldr%?h %2, [%0], #4 + ldr%?h %3, [%0], #4 + orr%? %2, %2, %3, lsl #16 + ldr%?h %3, [%0], #4 + ldr%?h %4, [%0], #4 + orr%? %3, %3, %4, lsl #16 + stm%?ia %1!, {%2, %3} + " : "=&r" (offset), "=&r" (buf), "=&r" (tmp), "=&r" (tmp2), "=&r" (tmp3) : "0" (offset), "1" (buf)); length -= 8; } while (length > 0) { unsigned int tmp; __asm__ __volatile__(" - ldrh %2, [%0], #4 - strb %2, [%1], #1 - mov %2, %2, lsr #8 - strb %2, [%1], #1 + ldr%?h %2, [%0], #4 + str%?b %2, [%1], #1 + mov%? %2, %2, lsr #8 + str%?b %2, [%1], #1 " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); length -= 2; } } +#else +#error Not compatable +#endif static int am79c961_ramtest(struct device *dev, unsigned int val) @@ -259,7 +251,7 @@ write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM); + write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO); write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); } @@ -304,7 +296,7 @@ /* * The PNP initialisation should have been done by the ether bootp loader. */ - inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */ + inb((dev->base_addr + NET_RESET) >> 1); /* reset the device */ udelay (5); @@ -420,26 +412,105 @@ return &priv->stats; } +static inline u32 update_crc(u32 crc, u8 byte) +{ + int i; + + for (i = 8; i != 0; i--) { + byte ^= crc & 1; + crc >>= 1; + + if (byte & 1) + crc ^= 0xedb88320; + + byte >>= 1; + } + + return crc; +} + +static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash) +{ + if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) { + int i, idx, bit; + u32 crc; + + crc = 0xffffffff; + + for (i = 0; i < ETH_ALEN; i++) + crc = update_crc(crc, dmi->dmi_addr[i]); + + idx = crc >> 30; + bit = (crc >> 26) & 15; + + hash[idx] |= 1 << bit; + } +} + /* * Set or clear promiscuous/multicast mode filter for this adaptor. - * - * We don't attempt any packet filtering. The card may have a SEEQ 8004 - * in which does not have the other ethernet address registers present... + * We don't attempt any packet filtering. */ static void am79c961_setmulticastlist (struct device *dev) { unsigned long flags; - int i; + unsigned short multi_hash[4], mode; + int i, stopped; - dev->flags &= ~IFF_ALLMULTI; + mode = MODE_PORT0; - i = MODE_PORT0; - if (dev->flags & IFF_PROMISC) - i |= MODE_PROMISC; + if (dev->flags & IFF_PROMISC) { + mode |= MODE_PROMISC; + } else if (dev->flags & IFF_ALLMULTI) { + memset(multi_hash, 0xff, sizeof(multi_hash)); + } else { + struct dev_mc_list *dmi; - save_flags_cli (flags); - write_rreg (dev->base_addr, MODE, i); - restore_flags (flags); + memset(multi_hash, 0x00, sizeof(multi_hash)); + + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + am79c961_mc_hash(dmi, multi_hash); + } + + save_flags_cli(flags); + + stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; + + if (!stopped) { + /* + * Put the chip into suspend mode + */ + write_rreg(dev->base_addr, CTRL1, CTRL1_SPND); + + /* + * Spin waiting for chip to report suspend mode + */ + while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) { + restore_flags(flags); + nop(); + save_flags_cli(flags); + } + } + + /* + * Update the multicast hash table + */ + for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++) + write_rreg(dev->base_addr, i + LADRL, multi_hash[i]); + + /* + * Write the mode register + */ + write_rreg(dev->base_addr, MODE, mode); + + if (!stopped) { + /* + * Put the chip back into running mode + */ + write_rreg(dev->base_addr, CTRL1, 0); + } + + restore_flags(flags); } /* @@ -455,17 +526,20 @@ if (!test_and_set_bit(0, (void*)&dev->tbusy)) { unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int hdraddr, bufaddr; + unsigned int head; unsigned long flags; - hdraddr = priv->txhdr + (priv->txhead << 3); - bufaddr = priv->txbuffer[priv->txhead]; - priv->txhead ++; - if (priv->txhead >= TX_BUFFERS) - priv->txhead = 0; + head = priv->txhead; + hdraddr = priv->txhdr + (head << 3); + bufaddr = priv->txbuffer[head]; + head += 1; + if (head >= TX_BUFFERS) + head = 0; am_writebuffer (dev, bufaddr, skb->data, length); am_writeword (dev, hdraddr + 4, -length); am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); + priv->txhead = head; save_flags_cli (flags); write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); @@ -483,10 +557,14 @@ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; - printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name); + printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name); /* Try to restart the adaptor. */ + disable_irq(dev->irq); + am79c961_init(dev); + am79c961_init_for_open(dev); dev->tbusy = 0; dev->trans_start = jiffies; + enable_irq(dev->irq); goto again; } } @@ -613,7 +691,7 @@ am_writeword (dev, hdraddr + 6, 0); if (status2 & TST_RTRY) - priv->stats.collisions += 1; + priv->stats.collisions += 16; if (status2 & TST_LCOL) priv->stats.tx_window_errors ++; if (status2 & TST_LCAR) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/am79c961a.h linux/drivers/net/am79c961a.h --- v2.2.17/drivers/net/am79c961a.h Fri Apr 21 12:46:15 2000 +++ linux/drivers/net/am79c961a.h Mon Oct 2 10:08:21 2000 @@ -45,6 +45,7 @@ #define CSR3_EMBA 0x0008 #define CSR3_DXMT2PD 0x0010 #define CSR3_LAPPEN 0x0020 +#define CSR3_DXSUFLO 0x0040 #define CSR3_IDONM 0x0100 #define CSR3_TINTM 0x0200 #define CSR3_RINTM 0x0400 @@ -53,6 +54,9 @@ #define CSR3_BABLM 0x4000 #define CSR3_MASKALL 0x5F00 +#define CTRL1 5 +#define CTRL1_SPND 0x0001 + #define LADRL 8 #define LADRM1 9 #define LADRM2 10 @@ -97,8 +101,8 @@ #define TMD_ERR 0x4000 #define TMD_OWN 0x8000 -#define TST_RTRY 0x0200 -#define TST_LCAR 0x0400 +#define TST_RTRY 0x0400 +#define TST_LCAR 0x0800 #define TST_LCOL 0x1000 #define TST_UFLO 0x4000 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.2.17/drivers/net/ariadne.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/ariadne.c Fri Oct 13 23:58:25 2000 @@ -399,8 +399,8 @@ board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has been - return; generated by the board. */ + if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has been */ + return; /* generated by the board. */ if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ariadne2.c linux/drivers/net/ariadne2.c --- v2.2.17/drivers/net/ariadne2.c Fri Apr 21 12:46:15 2000 +++ linux/drivers/net/ariadne2.c Fri Oct 13 23:58:25 2000 @@ -178,6 +178,7 @@ name = "NE2000"; dev->base_addr = ioaddr; + dev->irq = IRQ_AMIGA_PORTS; /* Install the Interrupt handler */ if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, 0, "AriadNE2 Ethernet", @@ -192,7 +193,9 @@ ((struct ei_device *)dev->priv)->priv = key; for(i = 0; i < ETHER_ADDR_LEN; i++) { +#ifdef DEBUG printk(" %2.2x", SA_prom[i]); +#endif dev->dev_addr[i] = SA_prom[i]; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.2.17/drivers/net/arlan.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/arlan.c Sat Nov 18 18:01:24 2000 @@ -1346,7 +1346,7 @@ priv->timer.function = &arlan_registration_timer; /* timer handler */ arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); - udelay(200000); + mdelay(200); dev->tbusy = 0; dev->start = 1; add_timer(&priv->timer); @@ -1784,7 +1784,7 @@ break; default: - printk(KERN_ERR "arlan intr: recieved unknown status\n"); + printk(KERN_ERR "arlan intr: received unknown status\n"); priv->stats.rx_crc_errors++; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/atari_bionet.c linux/drivers/net/atari_bionet.c --- v2.2.17/drivers/net/atari_bionet.c Fri Apr 21 12:46:15 2000 +++ linux/drivers/net/atari_bionet.c Sat Oct 14 00:07:14 2000 @@ -446,7 +446,7 @@ } else { int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned long buf = VTOP(skb->data); + unsigned long buf = virt_to_phys(skb->data); int stat; stdma_lock(bionet_intr, NULL); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/atari_pamsnet.c linux/drivers/net/atari_pamsnet.c --- v2.2.17/drivers/net/atari_pamsnet.c Fri Apr 21 12:46:15 2000 +++ linux/drivers/net/atari_pamsnet.c Sat Oct 14 00:07:14 2000 @@ -439,7 +439,7 @@ unsigned char *buffer; { int ret = -1; - unsigned char *vbuffer = (unsigned char *)PTOV(buffer); + unsigned char *vbuffer = phys_to_virt((unsigned long)buffer); unsigned char cmd_buffer[5]; if (send_first(target, INQUIRY)) @@ -487,7 +487,7 @@ !acsi_wait_for_IRQ(TIMEOUTDMA) || get_status()) goto bad; - ret = (HADDR *)PTOV(&(((DMAHWADDR *)buffer)->hwaddr)); + ret = phys_to_virt(&(((DMAHWADDR *)buffer)->hwaddr)); dma_cache_maintenance((unsigned long)buffer, 512, 0); bad: return (ret); @@ -707,7 +707,7 @@ } else { int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned long buf = VTOP(skb->data); + unsigned long buf = virt_to_phys(skb->data); int stat; stdma_lock(pamsnet_intr, NULL); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.2.17/drivers/net/bmac.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/bmac.c Wed Nov 8 23:00:34 2000 @@ -248,12 +248,16 @@ dbdma_reset(rd); dbdma_reset(td); + dbdma_st32((volatile unsigned long *)&rd->intr_sel, 0x40); + dbdma_st32((volatile unsigned long *)&rd->br_sel, 0x40); + dbdma_st32((volatile unsigned long *)&td->wait_sel, 0x20); + feature_set(bp->node, FEATURE_BMac_IO_enable); - udelay(10000); + mdelay(100); feature_set(bp->node, FEATURE_BMac_reset); - udelay(10000); + mdelay(10); feature_clear(bp->node, FEATURE_BMac_reset); - udelay(10000); + mdelay(10); } #define MIFDELAY udelay(10) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/bonding.c linux/drivers/net/bonding.c --- v2.2.17/drivers/net/bonding.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/bonding.c Fri Nov 3 12:48:53 2000 @@ -176,6 +176,9 @@ { struct device *slave = dev_get(ifr->ifr_slave); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + #ifdef BONDING_DEBUG printk("master=%s, slave=%s\n", master->name, slave->name); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/cops.c linux/drivers/net/cops.c --- v2.2.17/drivers/net/cops.c Fri Apr 21 12:46:16 2000 +++ linux/drivers/net/cops.c Sat Sep 30 18:18:15 2000 @@ -363,7 +363,8 @@ { outb(0, ioaddr+DAYNA_RESET); inb(ioaddr+DAYNA_RESET); - udelay(333333); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/3); } if(board==TANGENT) { @@ -499,7 +500,7 @@ schedule(); } else - udelay(333333); + mdelay(334); } dev->tbusy=0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/cosa.c linux/drivers/net/cosa.c --- v2.2.17/drivers/net/cosa.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/net/cosa.c Tue Nov 28 16:16:24 2000 @@ -102,13 +102,6 @@ #include "syncppp.h" #include "cosa.h" -/* Linux version stuff */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(wait, current) \ - struct wait_queue wait = { current, NULL } -#endif - /* Maximum length of the identification string. */ #define COSA_MAX_ID_STRING 128 @@ -575,6 +568,7 @@ struct device *d; chan->if_ptr = &chan->pppdev; chan->pppdev.dev = kmalloc(sizeof(struct device), GFP_KERNEL); + memset(chan->pppdev.dev, 0, sizeof(struct device)); sppp_attach(&chan->pppdev); d=chan->pppdev.dev; d->name = chan->name; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/daynaport.c linux/drivers/net/daynaport.c --- v2.2.17/drivers/net/daynaport.c Fri Apr 21 12:46:16 2000 +++ linux/drivers/net/daynaport.c Fri Oct 13 23:52:23 2000 @@ -1,4 +1,4 @@ -/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */ +/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */ /* Derived from code: @@ -15,14 +15,20 @@ The block output routines may be wrong for non Dayna cards - Reading MAC addresses -*/ + Fix this driver so that it will attempt to use the info + (i.e. iobase, iosize) given to it by the new and improved + NuBus code. + + Despite its misleading filename, this driver is not Dayna-specific + anymore. */ +/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */ static const char *version = - "mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n"; + "daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n"; +static int version_printed = 0; #include - +#include #include #include #include @@ -31,20 +37,26 @@ #include #include #include +#include #include #include #include #include "8390.h" -int ns8390_probe1(struct device *dev, int word16, char *name, int id, int prom); +extern int console_loglevel; + +int ns8390_probe1(struct device *dev, int word16, char *name, int id, + int prom, struct nubus_dev *ndev); static int ns8390_open(struct device *dev); static void ns8390_no_reset(struct device *dev); static int ns8390_close_card(struct device *dev); +/* Interlan */ static void interlan_reset(struct device *dev); +/* Dayna */ static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void dayna_block_input(struct device *dev, int count, @@ -52,6 +64,7 @@ static void dayna_block_output(struct device *dev, int count, const unsigned char *buf, const int start_page); +/* Sane (32-bit chunk memory read/write) */ static void sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void sane_block_input(struct device *dev, int count, @@ -59,6 +72,7 @@ static void sane_block_output(struct device *dev, int count, const unsigned char *buf, const int start_page); +/* Slow Sane (16-bit chunk memory read/write) */ static void slow_sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void slow_sane_block_input(struct device *dev, int count, @@ -71,6 +85,10 @@ #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ #define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ +#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */ +#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ +#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */ + #define DAYNA_MAC_BASE 0xf0007 #define DAYNA_8390_BASE 0x80000 /* 3 */ @@ -81,9 +99,14 @@ #define APPLE_8390_MEM 0xD0000 #define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */ -#define KINETICS_8390_BASE 0x80003 -#define KINETICS_8390_MEM 0x00000 +#define KINETICS_MAC_BASE 0xf0004 /* first byte of each long */ +#define KINETICS_8390_BASE 0x80000 +#define KINETICS_8390_MEM 0x00000 /* first word of each long */ #define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */ +/*#define KINETICS_MEMSIZE (0x10000/2) * CSA: on the board I have, at least */ + +#define CABLETRON_8390_BASE 0x90000 +#define CABLETRON_8390_MEM 0x00000 static int test_8390(volatile char *ptr, int scale) { @@ -113,34 +136,59 @@ * Identify the species of NS8390 card/driver we need */ -#define NS8390_DAYNA 1 -#define NS8390_INTERLAN 2 -#define NS8390_KINETICS 3 -#define NS8390_APPLE 4 -#define NS8390_FARALLON 5 -#define NS8390_ASANTE 6 - -int ns8390_ident(struct nubus_type *nb) -{ - /* It appears anything with a software type of 0 is an apple - compatible - even if the hardware matches others */ - - if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100) - return NS8390_APPLE; - +enum mac8390_type { + NS8390_DAYNA, + NS8390_INTERLAN, + NS8390_KINETICS, + NS8390_APPLE, + NS8390_FARALLON, + NS8390_ASANTE, + NS8390_CABLETRON +}; + +__initfunc(int ns8390_ident(struct nubus_dev* ndev)) +{ + /* This really needs to be tested and tested hard. */ + + /* Summary of what we know so far -- + * SW: 0x0104 -- asante, 16 bit, back4_offsets + * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets + * SW: 0x010c -- farallon, 16 bit, back4_offsets, no long word access + * SW: 0x011a -- focus, [no details yet] + * SW: ?????? -- interlan, 16 bit, back4_offsets, funny reset + * SW: ?????? -- kinetics, 8 bit, back4_offsets + * -- so i've this hypothesis going that says DrSW&1 says whether the + * map is forward or backwards -- and maybe DrSW&256 says what the + * register spacing is -- for all cards that report a DrSW in some + * range. + * This would allow the "apple compatible" driver to drive many + * seemingly different types of cards. More DrSW info is needed + * to investigate this properly. [CSA, 21-May-1999] + */ /* Dayna ex Kinetics board */ - if(nb->DrHW==0x0103) + if(ndev->dr_sw == NUBUS_DRSW_DAYNA) return NS8390_DAYNA; - - /* Asante board */ - if(nb->DrHW==0x0104) + if(ndev->dr_sw == NUBUS_DRSW_ASANTE) return NS8390_ASANTE; - if(nb->DrHW==0x0100) - return NS8390_INTERLAN; - if(nb->DrHW==0x0106) - return NS8390_KINETICS; - if(nb->DrSW==0x010C) + if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */ return NS8390_FARALLON; + if(ndev->dr_sw == NUBUS_DRSW_KINETICS) + return NS8390_KINETICS; + /* My ATI Engineering card with this combination crashes the */ + /* driver trying to xmit packets. Best not touch it for now. */ + /* - 1999-05-20 (funaho@jurai.org) */ + if(ndev->dr_sw == NUBUS_DRSW_FOCUS) + return -1; + + /* Check the HW on this one, because it shares the same DrSW as + the on-board SONIC chips */ + if(ndev->dr_hw == NUBUS_DRHW_CABLETRON) + return NS8390_CABLETRON; + /* does anyone have one of these? */ + if(ndev->dr_hw == NUBUS_DRHW_INTERLAN) + return NS8390_INTERLAN; + + /* FIXME: what do genuine Apple boards look like? */ return -1; } @@ -148,7 +196,7 @@ * Memory probe for 8390 cards */ -int apple_8390_mem_probe(volatile unsigned short *p) +__initfunc(int apple_8390_mem_probe(volatile unsigned short *p)) { int i, j; /* @@ -192,61 +240,79 @@ /* * Probe for 8390 cards. * The ns8390_probe1() routine initializes the card and fills the - * station address field. On entry base_addr is set, irq is set - * (These come from the nubus probe code). dev->mem_start points + * station address field. + * + * The NuBus interface has changed! We now scan for these somewhat + * like how the PCI and Zorro drivers do. It's not clear whether + * this is actually better, but it makes things more consistent. + * + * dev->mem_start points * at the memory ring, dev->mem_end gives the end of it. */ -int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match) +__initfunc(int mac8390_probe(struct device *dev)) { - struct device *dev; + static int slots = 0; volatile unsigned short *i; volatile unsigned char *p; int plen; int id; + static struct nubus_dev* ndev = NULL; - if(match->category!=NUBUS_CAT_NETWORK || match->type!=1) - return -ENODEV; - /* Ok so it is an ethernet network device */ - if((id=ns8390_ident(match))==-1) - { - printk("Ethernet but type unknown %d\n",match->DrHW); + /* Find the first card that hasn't already been seen */ + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, + NUBUS_TYPE_ETHERNET, ndev)) != NULL) { + /* Have we seen it already? */ + if (slots & (1<board->slot)) + continue; + slots |= 1<board->slot; + + /* Is it one of ours? */ + if ((id = ns8390_ident(ndev)) != -1) + break; + } + + /* Hm. No more cards, then */ + if (ndev == NULL) return -ENODEV; + + dev = init_etherdev(dev, 0); + + if (!version_printed) { + printk(KERN_INFO "%s", version); + version_printed = 1; } - dev = init_etherdev(0, 0); - if(dev==NULL) - return -ENOMEM; /* * Dayna specific init */ if(id==NS8390_DAYNA) { - dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM); - dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ + dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE); + dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM); + dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ - printk("daynaport: testing board: "); - + printk(KERN_INFO "%s: daynaport. testing board: ", dev->name); + printk("memory - "); - - i=(void *)dev->mem_start; + + i = (void *)dev->mem_start; memset((void *)i,0xAA, DAYNA_MEMSIZE); while(i<(volatile unsigned short *)dev->mem_end) { if(*i!=0xAAAA) goto membad; - *i=0x5555; - if(*i!=0x5555) + *i=0x5678; /* make sure we catch byte smearing */ + if(*i!=0x5678) goto membad; i+=2; /* Skip a word */ } - + printk("controller - "); - + p=(void *)dev->base_addr; plen=0; - + while(plen<0x3FF00) { if(test_8390(p,0)==0) @@ -263,26 +329,71 @@ if(plen==0x3FF00) goto membad; printk("OK\n"); - dev->irq=slot; - if(ns8390_probe1(dev, 0, "dayna", id, -1)==0) - return 0; + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0) + return 0; + } + /* Cabletron */ + if (id==NS8390_CABLETRON) { + int memsize = 16<<10; /* fix this */ + + dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM); + dev->mem_end=dev->mem_start+memsize; + dev->irq = SLOT2IRQ(ndev->board->slot); + + /* The base address is unreadable if 0x00 has been written to the command register */ + /* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */ + i = (void *)dev->base_addr; + *i = 0x21; + + printk(KERN_INFO "%s: cabletron: testing board: ", dev->name); + printk("%dK memory - ", memsize>>10); + i=(void *)dev->mem_start; + while(i<(volatile unsigned short *)(dev->mem_start+memsize)) + { + *i=0xAAAA; + if(*i!=0xAAAA) + goto membad; + *i=0x5555; + if(*i!=0x5555) + goto membad; + i+=2; /* Skip a word */ + } + printk("OK\n"); + + if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0) + return 0; } /* Apple, Farallon, Asante */ - if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE) + if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE) { int memsize; - - dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); - + + dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); + memsize = apple_8390_mem_probe((void *)dev->mem_start); - + dev->mem_end=dev->mem_start+memsize; - dev->irq=slot; - printk("apple/clone: testing board: "); - + dev->irq = SLOT2IRQ(ndev->board->slot); + + switch(id) + { + case NS8390_FARALLON: + printk(KERN_INFO "%s: farallon: testing board: ", dev->name); + break; + case NS8390_ASANTE: + printk(KERN_INFO "%s: asante: testing board: ", dev->name); + break; + case NS8390_APPLE: + default: + printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name); + break; + } + printk("%dK memory - ", memsize>>10); - + i=(void *)dev->mem_start; memset((void *)i,0xAA, memsize); while(i<(volatile unsigned short *)dev->mem_end) @@ -295,51 +406,75 @@ i+=2; /* Skip a word */ } printk("OK\n"); - - if(id==NS8390_FARALLON) + + switch (id) { - if(ns8390_probe1(dev, 1, "farallon", id, -1)==0) + case NS8390_FARALLON: + if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0) return 0; - } - else - { - if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0) - return 0; + break; + case NS8390_ASANTE: + if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0) + return 0; + break; + case NS8390_APPLE: + default: + if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0) + return 0; + break; } } /* Interlan */ if(id==NS8390_INTERLAN) { /* As apple and asante */ - dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); + dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */ - dev->irq=slot; - if(ns8390_probe1(dev, 1, "interlan", id, -1)==0) + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0) return 0; } - /* Kinetics */ + /* Kinetics (Shiva Etherport) */ if(id==NS8390_KINETICS) { - dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE); - dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM); + dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE); + dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM); dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */ - dev->irq=slot; - if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0) + dev->irq = SLOT2IRQ(ndev->board->slot); + if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0) return 0; } - kfree(dev); + + /* We should hopefully not get here */ + printk(KERN_ERR "Probe unsucessful.\n"); return -ENODEV; -membad: - printk("failed.\n"); - kfree(dev); + + membad: + printk(KERN_ERR "failed at %p in %p - %p.\n", i, + (void *)dev->mem_start, (void *)dev->mem_end); return -ENODEV; } -int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, int promoff) +__initfunc(int mac8390_ethernet_addr(struct nubus_dev* ndev, + unsigned char addr[6])) { - static unsigned version_printed = 0; + struct nubus_dir dir; + struct nubus_dirent ent; + + /* Get the functional resource for this device */ + if (nubus_get_func_dir(ndev, &dir) == -1) + return -1; + if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) + return -1; + + nubus_get_rsrc_mem(addr, &ent, 6); + return 0; +} +__initfunc(int ns8390_probe1(struct device *dev, int word16, char *model_name, + int type, int promoff, struct nubus_dev *ndev)) +{ static u32 fwrd4_offsets[16]={ 0, 4, 8, 12, 16, 20, 24, 28, @@ -352,25 +487,19 @@ 28, 24, 20, 16, 12, 8, 4, 0 }; + static u32 fwrd2_offsets[16]={ + 0, 2, 4, 6, + 8, 10, 12, 14, + 16, 18, 20, 22, + 24, 26, 28, 30 + }; - unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff; + unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff; - if (ei_debug && version_printed++ == 0) - printk(version); - - /* Snarf the interrupt now. There's no point in waiting since we cannot - share a slot! and the board will usually be enabled. */ - if (nubus_request_irq(dev->irq, dev, ei_interrupt)) - { - printk (" unable to get nubus IRQ %d.\n", dev->irq); - return EAGAIN; - } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - nubus_free_irq(dev->irq); + printk ("%s: unable to get memory for dev->priv.\n", dev->name); return -ENOMEM; } @@ -378,16 +507,25 @@ ei_status.name = model_name; ei_status.word16 = word16; - ei_status.tx_start_page = WD_START_PG; - ei_status.rx_start_page = WD_START_PG + TX_PAGES; - dev->rmem_start = dev->mem_start + TX_PAGES*256; - ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; - dev->rmem_end = dev->mem_end; + if (type==NS8390_CABLETRON) { + /* Cabletron card puts the RX buffer before the TX buffer */ + ei_status.tx_start_page = CABLETRON_TX_START_PG; + ei_status.rx_start_page = CABLETRON_RX_START_PG; + ei_status.stop_page = CABLETRON_RX_STOP_PG; + dev->rmem_start = dev->mem_start; + dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; + } else { + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->rmem_end = dev->mem_end; + } if(promoff==-1) /* Use nubus resources ? */ { - if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr)) + if(mac8390_ethernet_addr(ndev, dev->dev_addr)) { printk("mac_ns8390: MAC address not in resources!\n"); return -ENODEV; @@ -400,7 +538,7 @@ /* These should go in the end I hope */ if(type==NS8390_DAYNA) x=2; - if(type==NS8390_INTERLAN) + if(type==NS8390_INTERLAN || type==NS8390_KINETICS) x=4; while(i<6) { @@ -412,12 +550,24 @@ } } - printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", - model_name, dev->irq, dev->mem_start, dev->mem_end-1); + printk(KERN_INFO "%s: %s in slot %X (type %s)\n", + dev->name, ndev->board->name, ndev->board->slot, model_name); + printk(KERN_INFO "MAC "); + { + int i; + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + } + printk(" IRQ %d, shared memory at %#lx-%#lx.\n", + dev->irq, dev->mem_start, dev->mem_end-1); switch(type) { case NS8390_DAYNA: /* Dayna card */ + case NS8390_KINETICS: /* Kinetics -- 8 bit config, but 16 bit mem */ /* 16 bit, 4 word offsets */ ei_status.reset_8390 = &ns8390_no_reset; ei_status.block_input = &dayna_block_input; @@ -425,6 +575,15 @@ ei_status.get_8390_hdr = &dayna_get_8390_hdr; ei_status.reg_offset = fwrd4_offsets; break; + case NS8390_CABLETRON: /* Cabletron */ + /* 16 bit card, register map is short forward */ + ei_status.reset_8390 = &ns8390_no_reset; + /* Ctron card won't accept 32bit values read or written to it */ + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = fwrd2_offsets; + break; case NS8390_FARALLON: case NS8390_APPLE: /* Apple/Asante/Farallon */ /* 16 bit card, register map is reversed */ @@ -450,6 +609,8 @@ ei_status.get_8390_hdr = &sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; break; +#if 0 /* i think this suffered code rot. my kinetics card has much + * different settings. -- CSA [22-May-1999] */ case NS8390_KINETICS: /* Kinetics */ /* 8bit card, map is forward */ ei_status.reset_8390 = &ns8390_no_reset; @@ -458,6 +619,7 @@ ei_status.get_8390_hdr = &sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; break; +#endif default: panic("Detected a card I can't drive - whoops\n"); } @@ -472,6 +634,19 @@ static int ns8390_open(struct device *dev) { ei_open(dev); + + /* At least on my card (a Focus Enhancements PDS card) I start */ + /* getting interrupts right away, so the driver needs to be */ + /* completely initialized before enabling the interrupt. */ + /* - funaho@jurai.org (1999-05-17) */ + + /* Non-slow interrupt, works around issues with the SONIC driver */ + if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) + { + printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return EAGAIN; + } + MOD_INC_USE_COUNT; return 0; } @@ -489,24 +664,19 @@ { if (ei_debug > 1) printk("%s: Shutting down ethercard.\n", dev->name); + free_irq(dev->irq, dev); ei_close(dev); MOD_DEC_USE_COUNT; return 0; } -struct nubus_device_specifier nubus_8390={ - ns8390_probe, - NULL -}; - - /* * Interlan Specific Code Starts Here */ static void interlan_reset(struct device *dev) { - unsigned char *target=nubus_slot_addr(dev->irq); + unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); if (ei_debug > 1) printk("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; @@ -531,16 +701,23 @@ The only complications are that the ring buffer wraps. */ -static void dayna_cpu_memcpy(struct device *dev, void *to, int from, int count) +static void dayna_memcpy_fromcard(struct device *dev, void *to, int from, int count) { volatile unsigned short *ptr; unsigned short *target=to; from<<=1; /* word, skip overhead */ ptr=(unsigned short *)(dev->mem_start+from); + /* + * Leading byte? + */ + if (from&2) { + *((char *)target)++ = *(((char *)ptr++)-1); + count--; + } while(count>=2) { *target++=*ptr++; /* Copy and */ - ptr++; /* Cruft and */ + ptr++; /* skip cruft */ count-=2; } /* @@ -554,16 +731,24 @@ } } -static void cpu_dayna_memcpy(struct device *dev, int to, const void *from, int count) +static void dayna_memcpy_tocard(struct device *dev, int to, const void *from, int count) { volatile unsigned short *ptr; const unsigned short *src=from; to<<=1; /* word, skip overhead */ ptr=(unsigned short *)(dev->mem_start+to); + /* + * Leading byte? + */ + if (to&2) { /* avoid a byte write (stomps on other data) */ + ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++; + ptr++; + count--; + } while(count>=2) { *ptr++=*src++; /* Copy and */ - ptr++; /* Cruft and */ + ptr++; /* skip cruft */ count-=2; } /* @@ -573,14 +758,15 @@ { /* Big endian */ unsigned short v=*src; - *((char *)ptr)=v>>8; + /* card doesn't like byte writes */ + *ptr=(*ptr&0x00FF)|(v&0xFF00); } } static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4); + dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4); /* Register endianism - fix here rather than 8390.c */ hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); } @@ -599,14 +785,14 @@ { /* We must wrap the input move. */ int semi_count = dev->rmem_end - xfer_start; - dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count); + dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count); count -= semi_count; - dayna_cpu_memcpy(dev, skb->data + semi_count, + dayna_memcpy_fromcard(dev, skb->data + semi_count, dev->rmem_start - dev->mem_start, count); } else { - dayna_cpu_memcpy(dev, skb->data, xfer_base, count); + dayna_memcpy_fromcard(dev, skb->data, xfer_base, count); } } @@ -615,7 +801,7 @@ { long shmem = (start_page - WD_START_PG)<<8; - cpu_dayna_memcpy(dev, shmem, buf, count); + dayna_memcpy_tocard(dev, shmem, buf, count); } /* @@ -739,6 +925,7 @@ * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c" * version-control: t + * c-basic-offset: 4 * tab-width: 4 * kept-new-versions: 5 * End: diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.2.17/drivers/net/de4x5.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/de4x5.c Wed Nov 8 23:00:34 2000 @@ -4165,7 +4165,7 @@ /* If possible, try to fix a broken card - SMC only so far */ srom_repair(dev, broken); -#ifdef CONFIG_PMAC +#ifdef CONFIG_POWERMAC /* ** If the address starts with 00 a0, we have to bit-reverse ** each byte of the address. @@ -4178,7 +4178,7 @@ dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1); } } -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_POWERMAC */ /* Test for a bad enet address */ status = test_bad_enet(dev, status); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.2.17/drivers/net/dmfe.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/dmfe.c Sat Nov 18 18:01:24 2000 @@ -183,7 +183,7 @@ u8 link_failed; /* Ever link failed */ u8 wait_reset; /* Hardware failed, need to reset */ u8 in_reset_state; /* Now driver in reset routine */ - u8 rx_error_cnt; /* recievd abnormal case count */ + u8 rx_error_cnt; /* received abnormal case count */ u8 dm910x_chk_mode; /* Operating mode check */ struct timer_list timer; struct enet_statistics stats; /* statistic counter */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.2.17/drivers/net/eepro.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/eepro.c Tue Sep 26 17:05:33 2000 @@ -23,6 +23,8 @@ This is a compatibility hardware problem. Versions: + 0.12c fixed other multiple cards bug and other cleanups + (aris, 08/21/2000) 0.12b added reset when the tx interrupt is called and TX isn't done and other minor fixes. this may fix a problem found after initialization that delays tx until a transmit timeout is @@ -212,6 +214,12 @@ version of the 82595 chip. */ int stepping; spinlock_t lock; /* Serializing lock */ + unsigned rcv_ram; + unsigned rcv_start; + unsigned xmt_bar; + unsigned xmt_lower_limit_reg; + unsigned xmt_upper_limit_reg; + unsigned eeprom_reg; }; /* The station (ethernet) address prefix, used for IDing the board. */ @@ -356,24 +364,20 @@ #define RCV_HEADER 8 #define RCV_DEFAULT_RAM 0x6000 -#define RCV_RAM rcv_ram - -static unsigned rcv_ram = RCV_DEFAULT_RAM; +#define RCV_RAM lp->rcv_ram #define XMT_HEADER 8 #define XMT_RAM (RAM_SIZE - RCV_RAM) -#define XMT_START ((rcv_start + RCV_RAM) % RAM_SIZE) +#define XMT_START ((lp->rcv_start + RCV_RAM) % RAM_SIZE) -#define RCV_LOWER_LIMIT (rcv_start >> 8) -#define RCV_UPPER_LIMIT (((rcv_start + RCV_RAM) - 2) >> 8) +#define RCV_LOWER_LIMIT (lp->rcv_start >> 8) +#define RCV_UPPER_LIMIT (((lp->rcv_start + RCV_RAM) - 2) >> 8) #define XMT_LOWER_LIMIT (XMT_START >> 8) #define XMT_UPPER_LIMIT (((XMT_START + XMT_RAM) - 2) >> 8) #define RCV_START_PRO 0x00 #define RCV_START_10 XMT_RAM - /* by default the old driver */ -static unsigned rcv_start = RCV_START_PRO; #define RCV_DONE 0x0008 #define RX_OK 0x2000 @@ -422,7 +426,6 @@ #define XMT_BAR_PRO 0x0a #define XMT_BAR_10 0x0b -static unsigned xmt_bar = XMT_BAR_PRO; #define HOST_ADDRESS_REG 0x0c #define IO_PORT 0x0e @@ -440,8 +443,6 @@ #define XMT_UPPER_LIMIT_REG_PRO 0x0b #define XMT_LOWER_LIMIT_REG_10 0x0b #define XMT_UPPER_LIMIT_REG_10 0x0a -static unsigned xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; -static unsigned xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; /* Bank 2 registers */ #define XMT_Chain_Int 0x20 /* Interrupt at the end of the transmit chain */ @@ -466,7 +467,6 @@ #define EEPROM_REG_PRO 0x0a #define EEPROM_REG_10 0x0b -static unsigned eeprom_reg = EEPROM_REG_PRO; #define EESK 0x01 #define EECS 0x02 @@ -528,7 +528,8 @@ #define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG) /* a complete sel reset */ -#define eepro_complete_selreset(ioaddr) { eepro_dis_int(ioaddr);\ +#define eepro_complete_selreset(ioaddr) { \ + /* eepro_dis_int(ioaddr); */ \ lp->stats.tx_errors++;\ eepro_sel_reset(ioaddr);\ lp->tx_end = \ @@ -537,7 +538,7 @@ lp->tx_last = 0;\ dev->tbusy=0;\ dev->trans_start = jiffies;\ - eepro_en_int(ioaddr);\ + /*eepro_en_int(ioaddr); */ \ eepro_en_rx(ioaddr);\ } @@ -670,7 +671,15 @@ lp = (struct eepro_local *)dev->priv; - /* Now, get the ethernet hardware address from + /* default values */ + lp->rcv_start = RCV_START_PRO; + lp->xmt_bar = XMT_BAR_PRO; + lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; + lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; + lp->eeprom_reg = EEPROM_REG_PRO; + lp->rcv_ram = RCV_DEFAULT_RAM; + + /* Now, get the ethernet hardware address from the EEPROM */ station_addr[0] = read_eeprom(ioaddr, 2, dev); @@ -682,18 +691,18 @@ station_addr[0] == 0xffff) { eepro = 3; lp->eepro = LAN595FX_10ISA; - eeprom_reg = EEPROM_REG_10; - rcv_start = RCV_START_10; - xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; - xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; + lp->eeprom_reg = EEPROM_REG_10; + lp->rcv_start = RCV_START_10; + lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; + lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; + lp->xmt_bar = XMT_BAR_10; station_addr[0] = read_eeprom(ioaddr, 2, dev); } - + station_addr[1] = read_eeprom(ioaddr, 3, dev); station_addr[2] = read_eeprom(ioaddr, 4, dev); - if (eepro) { printk("%s: Intel EtherExpress 10 ISA\n at %#x,", dev->name, ioaddr); @@ -729,7 +738,7 @@ else { dev->mem_end = (dev->mem_end * 1024) + (RCV_LOWER_LIMIT << 8); - rcv_ram = dev->mem_end - (RCV_LOWER_LIMIT << 8); + lp->rcv_ram = dev->mem_end - (RCV_LOWER_LIMIT << 8); } /* From now on, dev->mem_end - dev->mem_start contains @@ -939,7 +948,7 @@ /* Initialize the 82595. */ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ - temp_reg = inb(ioaddr + eeprom_reg); + temp_reg = inb(ioaddr + lp->eeprom_reg); lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */ /* Get the stepping number of the 595 */ @@ -948,7 +957,7 @@ printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping); if (temp_reg & 0x10) /* Check the TurnOff Enable bit */ - outb(temp_reg & 0xef, ioaddr + eeprom_reg); + outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg); for (i=0; i < 6; i++) /* Fill the mac address */ outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); @@ -983,8 +992,8 @@ /* Initialize the RCV and XMT upper and lower limits */ outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); - outb(XMT_LOWER_LIMIT, ioaddr + xmt_lower_limit_reg); - outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg); + outb(XMT_LOWER_LIMIT, ioaddr + lp->xmt_lower_limit_reg); + outb(XMT_UPPER_LIMIT, ioaddr + lp->xmt_upper_limit_reg); /* Enable the interrupt line. */ eepro_en_intline(ioaddr); @@ -1003,7 +1012,7 @@ outw(((RCV_UPPER_LIMIT << 8) | 0xfe), ioaddr + RCV_STOP); /* Initialize XMT */ - outw((XMT_LOWER_LIMIT << 8), ioaddr + xmt_bar); + outw((XMT_LOWER_LIMIT << 8), ioaddr + lp->xmt_bar); /* Check for the i82595TX and i82595FX */ old8 = inb(ioaddr + 8); @@ -1174,7 +1183,6 @@ break; case TX_INT: eepro_ack_tx(ioaddr); - break; } if (status & RX_INT) { if (net_debug > 4) @@ -1330,7 +1338,7 @@ outw(eaddrs[0], ioaddr + IO_PORT); outw(eaddrs[1], ioaddr + IO_PORT); outw(eaddrs[2], ioaddr + IO_PORT); - outw(lp->tx_end, ioaddr + xmt_bar); + outw(lp->tx_end, ioaddr + lp->xmt_bar); outb(MC_SETUP, ioaddr); /* Update the transmit queue */ @@ -1392,8 +1400,8 @@ { int i; unsigned short retval = 0; - short ee_addr = ioaddr + eeprom_reg; struct eepro_local *lp = (struct eepro_local *)dev->priv; + short ee_addr = ioaddr + lp->eeprom_reg; int read_cmd = location | EE_READ_CMD; short ctrl_val = EECS ; @@ -1512,7 +1520,7 @@ status = inw(ioaddr + IO_PORT); if (lp->tx_start == lp->tx_end) { - outw(last, ioaddr + xmt_bar); + outw(last, ioaddr + lp->xmt_bar); outb(XMT_CMD, ioaddr); lp->tx_start = last; /* I don't like to change tx_start here */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.2.17/drivers/net/eepro100.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/eepro100.c Sat Nov 18 18:13:24 2000 @@ -1,5 +1,3 @@ -#define USE_IO - /* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */ /* NOTICE: this version of the driver is supposed to work with 2.2 kernels. @@ -37,18 +35,28 @@ 2000 May 30 Dragan Stancevic and Andrey Moruga Honor PortReset timing specification. + 2000 Jul 25 Dragan Stancevic + Changed to MMIO, resized FIFOs, resized rings, changed ISR timeout + Problem reported by: + Marc MERLIN + 2000 Nov 15 Dragan Stancevic + Changed command completion time and added debug info as to which + CMD timed out. Problem reported by: + "Ulrich Windl" */ +/*#define USE_IO*/ static const char *version = "eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n" -"eepro100.c: $Revision: 1.20.2.10 $ 2000/05/31 Modified by Andrey V. Savochkin and others\n"; +"eepro100.c: $Revision: 1.20.2.10 $ 2000/05/31 Modified by Andrey V. Savochkin and others\n" +"eepro100.c: VA Linux custom, Dragan Stancevic 2000/11/15\n"; /* A few user-configurable values that apply to all boards. First set is undocumented and spelled per Intel recommendations. */ static int congenb = 0; /* Enable congestion control in the DP83840. */ -static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ -static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ +static int txfifo = 0; /* Tx FIFO threshold in 4 byte units, 0-15 */ +static int rxfifo = 0xF; /* Rx FIFO threshold, default 32 bytes. */ /* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */ static int txdmacount = 128; static int rxdmacount = 0; @@ -63,7 +71,7 @@ #endif /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; +static int max_interrupt_work = 200; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ static int multicast_filter_limit = 64; @@ -78,8 +86,8 @@ /* A few values that may be tweaked. */ /* The ring sizes should be a power of two for efficiency. */ -#define TX_RING_SIZE 32 -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 64 +#define RX_RING_SIZE 64 /* How much slots multicast filter setup may take. Do not descrease without changing set_rx_mode() implementaion. */ #define TX_MULTICAST_SIZE 2 @@ -167,6 +175,9 @@ #ifndef PCI_DEVICE_ID_INTEL_ID1030 #define PCI_DEVICE_ID_INTEL_ID1030 0x1030 #endif +#ifndef PCI_DEVICE_ID_INTEL_ID2449 +#define PCI_DEVICE_ID_INTEL_ID2449 0x2449 +#endif /* The total I/O port extent of the board. The registers beyond 0x18 only exist on the i82558. */ @@ -326,6 +337,10 @@ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, 0 }, + { "Intel PCI EtherExpress Pro100 82562EM", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID2449, + 0 + }, {0,} /* 0 terminated list. */ }; @@ -357,13 +372,21 @@ Typically this takes 0 ticks. */ static inline void wait_for_cmd_done(long cmd_ioaddr) { - int wait = 1000; + int wait = 20000; + char cmd_reg1, cmd_reg2; do ; - while(inb(cmd_ioaddr) && --wait >= 0); -#ifndef final_version - if (wait < 0) - printk(KERN_ALERT "eepro100: wait_for_cmd_done timeout!\n"); -#endif + while((cmd_reg1 = inb(cmd_ioaddr)) && (--wait >= 0)); + + /* Last chance to change your mind --Dragan*/ + if (wait < 0){ + cmd_reg2 = inb(cmd_ioaddr); + if(cmd_reg2){ + printk(KERN_ALERT "eepro100: cmd_wait for(%#2.2x) timedout with(%#2.2x)!\n", + cmd_reg1, cmd_reg2); + + } + } + } /* Offsets to the various registers. @@ -1140,8 +1163,10 @@ static void speedo_show_state(struct net_device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; +#if 0 long ioaddr = dev->base_addr; int phy_num = sp->phy[0] & 0x1f; +#endif int i; /* Print a few items for debugging. */ @@ -1501,7 +1526,7 @@ FCP and ER interrupts --Dragan */ outw(status & 0xfc00, ioaddr + SCBStatus); - if (speedo_debug > 4) + if (speedo_debug > 3) printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n", dev->name, status); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c --- v2.2.17/drivers/net/fc/iph5526.c Fri Apr 21 12:46:17 2000 +++ linux/drivers/net/fc/iph5526.c Mon Oct 2 10:13:24 2000 @@ -2242,7 +2242,7 @@ /* (i)chip reset */ writel(ICHIP_HCR_RESET, fi->i_r.ptr_ichip_hw_control_reg); /*wait for chip to get reset */ - udelay(10000); + mdelay(10); /*de-assert reset */ writel(ICHIP_HCR_DERESET, fi->i_r.ptr_ichip_hw_control_reg); @@ -3884,7 +3884,7 @@ /* This is to make sure that the ACC to the PRLI comes in * for the last ALPA. */ - udelay(1000000); /* Ugly! Let the Gods forgive me */ + mdelay(1000); /* Ugly! Let the Gods forgive me */ DPRINTK1("leaving iph5526_detect\n"); return no_of_hosts; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/gmac.c linux/drivers/net/gmac.c --- v2.2.17/drivers/net/gmac.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/gmac.c Wed Nov 8 23:00:35 2000 @@ -6,6 +6,13 @@ * * portions based on sunhme.c by David S. Miller * + * Changes: + * Arnaldo Carvalho de Melo - 08/06/2000 + * - check init_etherdev return in gmac_probe1 + * BenH - 03/09/2000 + * - Add support for new PHYs + * - Add some PowerBook sleep code + * */ #include @@ -21,18 +28,25 @@ #include #include #include +#include #include #include #include #include -#include +#include +#include +#ifdef CONFIG_PMAC_PBOOK +#include +#include +#include +#endif #include "gmac.h" #define DEBUG_PHY -/* Driver version 1.1, kernel 2.2.x */ -#define GMAC_VERSION "v1.1k2" +/* Driver version 1.3, kernel 2.2.x */ +#define GMAC_VERSION "v1.3k2" static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; static struct device *gmacs = NULL; @@ -45,9 +59,12 @@ static void mii_interrupt(struct gmac *gm); static int mii_lookup_and_reset(struct gmac *gm); static void mii_setup_phy(struct gmac *gm); +static int mii_do_reset_phy(struct gmac *gm, int phy_addr); +static void mii_init_BCM5400(struct gmac *gm); static void gmac_set_power(struct gmac *gm, int power_up); static int gmac_powerup_and_reset(struct device *dev); +static void gmac_set_gigabit_mode(struct gmac *gm, int gigabit); static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex); static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr); static void gmac_init_rings(struct gmac *gm, int from_irq); @@ -67,6 +84,13 @@ extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr); +#ifdef CONFIG_PMAC_PBOOK +int gmac_sleep_notify(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier gmac_sleep_notifier = { + gmac_sleep_notify, SLEEP_LEVEL_NET, +}; +#endif + /* Stuff for talking to the physical-layer chip */ static int mii_read(struct gmac *gm, int phy, int r) @@ -136,6 +160,18 @@ udelay(GM_MIF_POLL_DELAY); } +/* Link modes of the BCM5400 PHY */ +static int phy_BCM5400_link_table[8][3] = { + { 0, 0, 0 }, /* No link */ + { 0, 0, 0 }, /* 10BT Half Duplex */ + { 1, 0, 0 }, /* 10BT Full Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 1, 1, 0 }, /* 100BT Full Duplex*/ + { 1, 0, 1 }, /* 1000BT */ + { 1, 0, 1 }, /* 1000BT */ +}; + static void mii_interrupt(struct gmac *gm) { @@ -150,8 +186,9 @@ /* We read the Auxilliary Status Summary register */ phy_status = mii_read(gm, gm->phy_addr, MII_SR); if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) { - int full_duplex; - int link_100; + int full_duplex = 0; + int link_100 = 0; + int gigabit = 0; #ifdef DEBUG_PHY printk("Link state change, phy_status: 0x%04x\n", phy_status); #endif @@ -163,8 +200,9 @@ else GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN); - /* Link ? For now we handle only the 5201 PHY */ + /* Link ? Check for speed and duplex */ if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) { + int restart = 0; if (gm->phy_type == PHY_B5201) { int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS); #ifdef DEBUG_PHY @@ -172,19 +210,41 @@ #endif full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0); link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0); - } else { - full_duplex = 1; - link_100 = 1; + } else if (gm->phy_type == PHY_B5400) { + int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS); + int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> + MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT; +#ifdef DEBUG_PHY + printk(" Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n", + aux_stat, link); +#endif + full_duplex = phy_BCM5400_link_table[link][0]; + link_100 = phy_BCM5400_link_table[link][1]; + gigabit = phy_BCM5400_link_table[link][2]; + } else if (gm->phy_type == PHY_LXT971) { + int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2); +#ifdef DEBUG_PHY + printk(" Link up ! LXT971 stat2: 0x%04x\n", stat2); +#endif + full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0); + link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0); } #ifdef DEBUG_PHY printk(" full_duplex: %d, speed: %s\n", full_duplex, - link_100 ? "100" : "10"); + gigabit ? "1000" : (link_100 ? "100" : "10")); #endif + if (gigabit != gm->gigabit) { + gm->gigabit = gigabit; + gmac_set_gigabit_mode(gm, gm->gigabit); + restart = 1; + } if (full_duplex != gm->full_duplex) { gm->full_duplex = full_duplex; gmac_set_duplex_mode(gm, gm->full_duplex); - gmac_start_dma(gm); + restart = 1; } + if (restart) + gmac_start_dma(gm); } else if (!(phy_status & MII_SR_LKS)) { #ifdef DEBUG_PHY printk(" Link down !\n"); @@ -194,16 +254,73 @@ } static int +mii_do_reset_phy(struct gmac *gm, int phy_addr) +{ + int mii_control, timeout; + + mii_control = mii_read(gm, phy_addr, MII_CR); + mii_write(gm, phy_addr, MII_CR, mii_control | MII_CR_RST); + mdelay(10); + for (timeout = 100; timeout > 0; --timeout) { + mii_control = mii_read(gm, phy_addr, MII_CR); + if (mii_control == -1) { + printk(KERN_ERR "%s PHY died after reset !\n", + gm->dev->name); + return 1; + } + if ((mii_control & MII_CR_RST) == 0) + break; + mdelay(10); + } + if (mii_control & MII_CR_RST) { + printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + return 1; + } + mii_write(gm, phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); + return 0; +} + +static void +mii_init_BCM5400(struct gmac *gm) +{ + int data; + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data |= MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + mii_do_reset_phy(gm, 0x1f); + + data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); +} + +static int mii_lookup_and_reset(struct gmac *gm) { - int i, timeout; - int mii_status, mii_control; + int i, mii_status, mii_control; - /* Find the PHY */ gm->phy_addr = -1; gm->phy_type = PHY_UNKNOWN; + + /* Hard reset the PHY */ + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT); + mdelay(10); + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE); + mdelay(10); - for(i=31; i>0; --i) { + /* Find the PHY */ + for(i=0; i<32; i++) { mii_control = mii_read(gm, i, MII_CR); mii_status = mii_read(gm, i, MII_SR); if (mii_control != -1 && mii_status != -1 && @@ -211,29 +328,13 @@ break; } gm->phy_addr = i; - if (gm->phy_addr < 0) + if (gm->phy_addr > 31) return 0; /* Reset it */ - mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST); - mdelay(10); - for (timeout = 100; timeout > 0; --timeout) { - mii_control = mii_read(gm, gm->phy_addr, MII_CR); - if (mii_control == -1) { - printk(KERN_ERR "%s PHY died after reset !\n", - gm->dev->name); - goto fail; - } - if ((mii_control & MII_CR_RST) == 0) - break; - mdelay(10); - } - if (mii_control & MII_CR_RST) { - printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + if (mii_do_reset_phy(gm, gm->phy_addr)) goto fail; - } - mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); - + /* Read the PHY ID */ gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) | mii_read(gm, gm->phy_addr, MII_ID1); @@ -242,10 +343,15 @@ #endif if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) { gm->phy_type = PHY_B5400; - printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n", + printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n", gm->dev->name); + mii_init_BCM5400(gm); } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) { gm->phy_type = PHY_B5201; + printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name); + } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) { + gm->phy_type = PHY_LXT971; + printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name); } else { printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n", gm->dev->name, gm->phy_id); @@ -288,9 +394,7 @@ gmac_set_power(struct gmac *gm, int power_up) { if (power_up) { - out_le32(gm->sysregs + 0x20/4, - in_le32(gm->sysregs + 0x20/4) | 0x02000000); - udelay(20); + feature_set_gmac_power(gm->of_node, 1); if (gm->pci_devfn != 0xff) { u16 cmd; @@ -308,9 +412,7 @@ } else { /* FIXME: Add PHY power down */ gm->phy_type = 0; - out_le32(gm->sysregs + 0x20/4, - in_le32(gm->sysregs + 0x20/4) & ~0x02000000); - udelay(20); + feature_set_gmac_power(gm->of_node, 0); } } @@ -357,6 +459,22 @@ } } +/* Set the MAC gigabit mode. Side effect: stops Tx MAC */ +static void +gmac_set_gigabit_mode(struct gmac *gm, int gigabit) +{ + /* Stop Tx MAC */ + GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE); + while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE) + ; + + if (gigabit) { + GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } else { + GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } +} + static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr) { @@ -388,12 +506,12 @@ (31 << GM_GCONF_TXDMA_LIMIT_SHIFT) | (31 << GM_GCONF_RXDMA_LIMIT_SHIFT)); GM_OUT(GM_TX_CONF, - GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT | + (GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT) | NTX_CONF); -/* 34 byte offset for checksum computation. This works because ip_input() will clear out - * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are - * present in the header. 34 == (ethernet header len) + sizeof(struct iphdr) - */ + /* 34 byte offset for checksum computation. This works because ip_input() will clear out + * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are + * present in the header. 34 == (ethernet header len) + sizeof(struct iphdr) + */ GM_OUT(GM_RX_CONF, (RX_OFFSET << GM_RX_CONF_FBYTE_OFF_SHIFT) | (0x22 << GM_RX_CONF_CHK_START_SHIFT) | @@ -703,6 +821,65 @@ return 0; } +#ifdef CONFIG_PMAC_PBOOK +int +gmac_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct gmac *gm; + int i; + + /* XXX should handle more than one */ + if (gmacs == NULL) + return PBOOK_SLEEP_OK; + + gm = (struct gmac *) gmacs->priv; + if (!gm->opened) + return PBOOK_SLEEP_OK; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + break; + case PBOOK_SLEEP_REJECT: + break; + case PBOOK_SLEEP_NOW: + disable_irq(gm->dev->irq); + gm->dev->tbusy = 1; + gmac_stop_dma(gm); + mii_poll_stop(gm); + gmac_set_power(gm, 0); + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + for (i = 0; i < NTX; ++i) { + if (gm->tx_buff[i] != 0) { + dev_kfree_skb(gm->tx_buff[i]); + gm->tx_buff[i] = 0; + } + } + break; + case PBOOK_WAKE: + /* see if this is enough */ + gmac_powerup_and_reset(gm->dev); + gm->full_duplex = 0; + gm->phy_status = 0; + mii_lookup_and_reset(gm); + mii_setup_phy(gm); + gmac_init_rings(gm, 0); + gmac_mac_init(gm, gm->dev->dev_addr); + gmac_set_multicast(gm->dev); + mii_interrupt(gm); + gmac_start_dma(gm); + gm->dev->tbusy = 0; + enable_irq(gm->dev->irq); + break; + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PMAC_PBOOK */ + /* * Handle a transmit timeout */ @@ -712,12 +889,11 @@ struct gmac *gm = (struct gmac *) dev->priv; int i, timeout; unsigned long flags; - - save_flags(flags); - cli(); printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + spin_lock_irqsave(&gm->lock, flags); + /* * Do something useful here * @@ -758,7 +934,7 @@ /* Restart chip */ gmac_start_dma(gm); - restore_flags(flags); + spin_unlock_irqrestore(&gm->lock, flags); dev->tbusy = 0; } @@ -770,6 +946,7 @@ struct gmac *gm = (struct gmac *) dev->priv; volatile struct gmac_dma_desc *dp; int i; + unsigned long flags; /* Check tbusy bit and handle eventual transmitter timeout */ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { @@ -780,9 +957,12 @@ return 1; } + spin_lock_irqsave(&gm->lock, flags); + i = gm->next_tx; if (gm->tx_buff[i] != 0) { /* buffer is full, can't send this packet at the moment */ + spin_unlock_irqrestore(&gm->lock, flags); return 1; } gm->next_tx = (i + 1) & (NTX - 1); @@ -804,6 +984,8 @@ dev->tbusy = (gm->tx_buff[gm->next_tx] != 0); + spin_unlock_irqrestore(&gm->lock, flags); + return 0; } @@ -820,9 +1002,8 @@ int gone, i; i = gm->tx_gone; - gone = GM_IN(GM_TX_COMP); - - while (force_cleanup || i != gone) { + do { + gone = GM_IN(GM_TX_COMP); skb = gm->tx_buff[i]; if (skb == NULL) break; @@ -837,7 +1018,7 @@ dev_kfree_skb(skb); if (++i >= NTX) i = 0; - } + } while (force_cleanup || i != gone); gm->tx_gone = i; if (!force_cleanup && dev->tbusy && @@ -987,15 +1168,23 @@ } if (status & GM_IRQ_MIF) { + spin_lock(&gm->lock); mii_interrupt(gm); + spin_unlock(&gm->lock); } - if (status & GM_IRQ_RX_DONE) + if (status & GM_IRQ_RX_DONE) { + spin_lock(&gm->lock); gmac_receive(dev); - - if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) + spin_unlock(&gm->lock); + } + + if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) { + spin_lock(&gm->lock); gmac_tx_cleanup(dev, 0); - + spin_unlock(&gm->lock); + } + dev->interrupt = 0; } @@ -1076,10 +1265,12 @@ dev->base_addr = gmac->addrs[0].address; gm->regs = (volatile unsigned int *) ioremap(gmac->addrs[0].address, 0x10000); - gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000); dev->irq = gmac->intrs[0].line; gm->dev = dev; - + gm->of_node = gmac; + + spin_lock_init(&gm->lock); + if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) { gm->pci_bus = gm->pci_devfn = 0xff; printk(KERN_ERR "Can't locate GMAC PCI entry\n"); @@ -1117,6 +1308,9 @@ gmacs = dev; +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&gmac_sleep_notifier); +#endif return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/gmac.h linux/drivers/net/gmac.h --- v2.2.17/drivers/net/gmac.h Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/gmac.h Wed Nov 8 23:00:35 2000 @@ -730,8 +730,9 @@ */ /* Supported PHYs (phy_type field ) */ -#define PHY_B5400 5400 -#define PHY_B5201 5201 +#define PHY_B5400 0x5400 +#define PHY_B5201 0x5201 +#define PHY_LXT971 0x0971 #define PHY_UNKNOWN 0 /* Identification (for multi-PHY) */ @@ -745,6 +746,11 @@ #define MII_BCM5400_REV 0x01 #define MII_BCM5400_ID ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4)) #define MII_BCM5400_MASK 0xfffffff0 +#define MII_LXT971_OUI 0x0004de +#define MII_LXT971_MODEL 0x0e +#define MII_LXT971_REV 0x00 +#define MII_LXT971_ID ((MII_LXT971_OUI << 10) | (MII_LXT971_MODEL << 4)) +#define MII_LXT971_MASK 0xfffffff0 /* BCM5201 AUX STATUS register */ #define MII_BCM5201_AUXCTLSTATUS 0x18 @@ -764,6 +770,26 @@ #define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002 #define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 +/* MII BCM5400 1000-BASET Control register */ +#define MII_BCM5400_GB_CONTROL 0x09 +#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 + +/* MII BCM5400 AUXCONTROL register */ +#define MII_BCM5400_AUXCONTROL 0x18 +#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004 + +/* MII BCM5400 AUXSTATUS register */ +#define MII_BCM5400_AUXSTATUS 0x19 +#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 + +/* MII LXT971 STATUS2 register */ +#define MII_LXT971_STATUS2 0x11 +#define MII_LXT971_STATUS2_SPEED 0x4000 +#define MII_LXT971_STATUS2_LINK 0x0400 +#define MII_LXT971_STATUS2_FULLDUPLEX 0x0200 +#define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080 + /* @@ -829,8 +855,8 @@ struct gmac { volatile unsigned int *regs; /* hardware registers, virtual addr */ - volatile unsigned int *sysregs; struct device *dev; + struct device_node *of_node; unsigned long tx_desc_page; /* page for DMA descriptors */ unsigned long rx_desc_page; /* page for DMA descriptors */ volatile struct gmac_dma_desc *rxring; @@ -845,9 +871,11 @@ int phy_type; int phy_status; /* Cached PHY status */ int full_duplex; /* Current set to full duplex */ + int gigabit; /* Current set to 1000BT */ struct net_device_stats stats; u8 pci_bus; u8 pci_devfn; + spinlock_t lock; int opened; }; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile --- v2.2.17/drivers/net/hamradio/Makefile Fri Apr 21 12:46:17 2000 +++ linux/drivers/net/hamradio/Makefile Thu Oct 19 01:28:39 2000 @@ -1,10 +1,6 @@ # File: drivers/hamradio/Makefile # # Makefile for the Linux AX.25 and HFMODEM device drivers. -# -# 19971130 Moved the amateur radio related network drivers from -# drivers/net/ to drivers/hamradio for easier maintainance. -# Joerg Reuter DL1BKE SUB_DIRS := diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c --- v2.2.17/drivers/net/hamradio/bpqether.c Fri Apr 21 12:46:17 2000 +++ linux/drivers/net/hamradio/bpqether.c Thu Oct 19 01:28:11 2000 @@ -652,7 +652,7 @@ #ifdef MODULE EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("Joerg Reuter DL1BKE "); +MODULE_AUTHOR("Joerg Reuter DL1BKE "); MODULE_DESCRIPTION("Transmit and receive AX.25 packets over Ethernet"); int init_module(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c --- v2.2.17/drivers/net/hamradio/mkiss.c Fri Apr 21 12:46:17 2000 +++ linux/drivers/net/hamradio/mkiss.c Wed Sep 13 16:18:07 2000 @@ -802,7 +802,7 @@ static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len) { unsigned char *ptr = d; - unsigned char c; + unsigned char c=0; *ptr++ = END; while (len > 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c --- v2.2.17/drivers/net/hamradio/scc.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/hamradio/scc.c Thu Oct 19 01:28:39 2000 @@ -19,7 +19,7 @@ ******************************************************************** - Copyright (c) 1993, 1998 Joerg Reuter DL1BKE + Copyright (c) 1993, 2000 Joerg Reuter DL1BKE portions (c) 1993 Guido ten Dolle PE1NNZ @@ -127,9 +127,9 @@ vy 73, Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org - AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU - Internet: jreuter@poboxes.com - www : http://poboxes.com/jreuter/ + AX-25 : DL1BKE @ DB0ABH.#BAY.DEU.EU + Internet: jreuter@yaina.de + www : http://yaina.de/jreuter/ */ /* ----------------------------------------------------------------------- */ @@ -236,7 +236,7 @@ static int Nchips = 0; static io_port Vector_Latch = 0; -MODULE_AUTHOR("Joerg Reuter "); +MODULE_AUTHOR("Joerg Reuter "); MODULE_DESCRIPTION("Network Device Driver for Z8530 based HDLC cards for Amateur Packet Radio"); MODULE_SUPPORTED_DEVICE("scc"); @@ -2242,7 +2242,7 @@ result = scc_init(); if (result == 0) - printk(KERN_INFO "Copyright 1993,1998 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n"); + printk(KERN_INFO "Copyright 1993,2000 Joerg Reuter DL1BKE (jreuter@yaina.de)\n"); return result; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/hdlc.c linux/drivers/net/hdlc.c --- v2.2.17/drivers/net/hdlc.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/hdlc.c Thu Nov 9 13:33:17 2000 @@ -50,6 +50,7 @@ #define CISCO_ADDR_REQ 0 /* Cisco address request */ #define CISCO_ADDR_REPLY 1 /* Cisco address reply */ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ +#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */ static int hdlc_ioctl(struct device *dev, struct ifreq *ifr, int cmd); @@ -141,6 +142,11 @@ return; #endif + case CISCO_SYS_INFO: + /* Packet is not needed, drop it. */ + dev_kfree_skb(skb); + return; + case CISCO_KEEPALIVE: if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) { @@ -206,7 +212,7 @@ } /* switch(keepalive type) */ } /* switch(protocol) */ - printk(KERN_INFO "%s: Unusupported protocol %x\n", hdlc->name, + printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc->name, data->protocol); hdlc->stats.rx_bytes+=skb->len; hdlc->stats.rx_packets++; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.2.17/drivers/net/ibmtr.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/net/ibmtr.c Sat Oct 28 11:27:54 2000 @@ -83,11 +83,18 @@ * Changes by Jochen Friedrich to enable RFC1469 Option 2 multicasting * i.e. using functional address C0 00 00 04 00 00 to transmit and * receive multicast packets. - * + * * Changes by Mike Sullivan (based on original sram patch by Dave Grothe * to support windowing into on adapter shared ram. * i.e. Use LANAID to setup a PnP configuration with 16K RAM. Paging * will shift this 16K window over the entire available shared RAM. + * + * Changes by Burt Silverman to allow the computer to behave nicely when + * a cable is pulled or not in place, or a PCMCIA card is removed hot. It + * is important for the user to understand that unlike some other systems, + * the system doesn't try continuously to establish insertion; however, an + * ifconfig tr0 down,ifconfig tr0 up sequence should restore connectivity, + * when all hardware is good and in place. */ /* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value @@ -107,15 +114,13 @@ #define NO_AUTODETECT 1 #undef NO_AUTODETECT -//#undef ENABLE_PAGING -#define ENABLE_PAGING 1 - +#undef ENABLE_PAGING +#define ENABLE_PAGING 1 #define FALSE 0 #define TRUE (!FALSE) -/* changes the output format of driver initialisation */ -#define TR_NEWFORMAT 1 +/* changes the output format of driver initialization */ #define TR_VERBOSE 0 /* some 95 OS send many non UI frame; this allow removing the warning */ @@ -123,11 +128,12 @@ /* version and credits */ static char *version = -"ibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" -" v2.1.125 10/20/98 Paul Norton \n" -" v2.2.0 12/30/98 Joel Sloan \n" -" v2.2.1 02/08/00 Mike Sullivan \n"; - + "\nibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" + " v2.1.125 10/20/98 Paul Norton \n" + " v2.2.0 12/30/98 Joel Sloan \n" + " v2.2.1 02/08/00 Mike Sullivan \n" + " v2.2.2 07/27/00 Burt Silverman \n"; + static char pcchannelid[] = { 0x05, 0x00, 0x04, 0x09, 0x04, 0x03, 0x04, 0x0f, @@ -171,63 +177,56 @@ #include "ibmtr.h" - #define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args) #define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args) #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) -#if TR_NEWFORMAT /* this allows displaying full adapter information */ -const char *channel_def[] __initdata = { - "ISA", "MCA", "ISA P&P" +const char *channel_def[] __initdata = { + "ISA", "MCA", "ISA P&P" }; __initfunc(char *adapter_def(char type)) { - switch (type) - { - case 0xF : return "PC Adapter | PC Adapter II | Adapter/A"; - case 0xE : return "16/4 Adapter | 16/4 Adapter/A (long)"; - case 0xD : return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter"; - case 0xC : return "Auto 16/4 Adapter"; - default : return "adapter (unknown type)"; + switch (type) { + case 0xF: + return "PC Adapter | PC Adapter II | Adapter/A"; + case 0xE: + return "16/4 Adapter | 16/4 Adapter/A (long)"; + case 0xD: + return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter"; + case 0xC: + return "Auto 16/4 Adapter"; + default: + return "adapter (unknown type)"; }; }; -#endif -#if !TR_NEWFORMAT -unsigned char ibmtr_debug_trace=1; /* Patch or otherwise alter to - control tokenring tracing. */ -#else -unsigned char ibmtr_debug_trace=0; -#endif -#define TRC_INIT 0x01 /* Trace initialization & PROBEs */ -#define TRC_INITV 0x02 /* verbose init trace points */ - -int ibmtr_probe(struct device *dev); -static int ibmtr_probe1(struct device *dev, int ioaddr); -static unsigned char get_sram_size(struct tok_info *adapt_info); -#ifdef PCMCIA -extern unsigned char pcmcia_reality_check(unsigned char gss); -#endif -static int tok_init_card(struct device *dev); -void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int trdev_init(struct device *dev); +#define TRC_INIT 0x01 /* Trace initialization & PROBEs */ +#define TRC_INITV 0x02 /* verbose init trace points */ +unsigned char ibmtr_debug_trace = 0; + +int ibmtr_probe(struct device *dev); +static int ibmtr_probe1(struct device *dev, int ioaddr); +static unsigned char get_sram_size(struct tok_info *adapt_info); +static int trdev_init(struct device *dev); +static int tok_init_card(struct device *dev); +static int tok_open(struct device *dev); +void tok_open_adapter(unsigned long dev_addr); +static void open_sap(unsigned char type, struct device *dev); +static void tok_set_multicast_list(struct device *dev); +static int tok_send_packet(struct sk_buff *skb, struct device *dev); +static int tok_close(struct device *dev); +void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void initial_tok_int(struct device *dev); -static void open_sap(unsigned char type,struct device *dev); -void tok_open_adapter(unsigned long dev_addr); -static void tr_rx(struct device *dev); -static void tr_tx(struct device *dev); -static int tok_open(struct device *dev); -static int tok_close(struct device *dev); -static int tok_send_packet(struct sk_buff *skb, struct device *dev); -static struct net_device_stats * tok_get_stats(struct device *dev); -static void tok_set_multicast_list(struct device *dev); -void ibmtr_readlog(struct device *dev); -void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev); -int ibmtr_change_mtu(struct device *dev, int mtu); +static void tr_tx(struct device *dev); +static void tr_rx(struct device *dev); +void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev); +void ibmtr_readlog(struct device *dev); +static struct net_device_stats *tok_get_stats(struct device *dev); +int ibmtr_change_mtu(struct device *dev, int mtu); static unsigned int ibmtr_portlist[] __initdata = { 0xa20, 0xa24, 0 @@ -235,23 +234,23 @@ static __u32 ibmtr_mem_base = 0xd0000; -__initfunc(static void PrtChanID(char *pcid, short stride) ) +__initfunc(static void PrtChanID(char *pcid, short stride)) { short i, j; - for (i=0, j=0; i<24; i++, j+=stride) + for (i = 0, j = 0; i < 24; i++, j += stride) printk("%1x", ((int) pcid[j]) & 0x0f); printk("\n"); } -__initfunc(static void HWPrtChanID (__u32 pcid, short stride)) +__initfunc(static void HWPrtChanID(__u32 pcid, short stride)) { short i, j; - for (i=0, j=0; i<24; i++, j+=stride) - printk("%1x", ((int)readb(pcid + j)) & 0x0f); + for (i = 0, j = 0; i < 24; i++, j += stride) + printk("%1x", ((int) readb(pcid + j)) & 0x0f); printk("\n"); } -/* +/**************************************************************************** * ibmtr_probe(): Routine specified in the network device structure * to probe for an IBM Token Ring Adapter. Routine outline: * I. Interrogate hardware to determine if an adapter exists @@ -262,258 +261,233 @@ * * We expect ibmtr_probe to be called once for each device entry * which references it. - */ - + ****************************************************************************/ + __initfunc(int ibmtr_probe(struct device *dev)) { - int i; - int base_addr = dev ? dev->base_addr : 0; + int i; + int base_addr = dev ? dev->base_addr : 0; - if (base_addr > 0x1ff) - { - /* - * Check a single specified location. - */ - - if (ibmtr_probe1(dev, base_addr)) - { + if (base_addr > 0x1ff) { + /* + * Check a single specified location. + */ + + if (ibmtr_probe1(dev, base_addr)) { #ifndef MODULE #ifndef PCMCIA - tr_freedev(dev); + tr_freedev(dev); #endif #endif - return -ENODEV; + return -ENODEV; } else - return 0; - } - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; + return 0; + } else if (base_addr != 0) /* Don't probe at all. */ + return -ENXIO; - for (i = 0; ibmtr_portlist[i]; i++) - { - int ioaddr = ibmtr_portlist[i]; + for (i = 0; ibmtr_portlist[i]; i++) { + int ioaddr = ibmtr_portlist[i]; if (check_region(ioaddr, IBMTR_IO_EXTENT)) - continue; - if (ibmtr_probe1(dev, ioaddr)) { + continue; + if (ibmtr_probe1(dev, ioaddr)) { #ifndef MODULE #ifndef PCMCIA - tr_freedev(dev); + tr_freedev(dev); #endif #endif } else return 0; - } + } - return -ENODEV; + return -ENODEV; } +/*****************************************************************************/ + __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) { - unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0; - __u32 t_mmio=0; - struct tok_info *ti=0; + + unsigned char segment = 0, intr = 0, irq = 0, i = 0, j = 0, cardpresent = NOTOK, temp = 0; + __u32 t_mmio = 0; + struct tok_info *ti = 0; __u32 cd_chanid; unsigned char *tchanid, ctemp; unsigned long timeout; #ifndef MODULE #ifndef PCMCIA - dev = init_trdev(dev,0); + dev = init_trdev(dev, 0); #endif #endif - /* Query the adapter PIO base port which will return - * indication of where MMIO was placed. We also have a - * coded interrupt number. + /* Query the adapter PIO base port which will return + * indication of where MMIO was placed. We also have a + * coded interrupt number. */ - - segment = inb(PIOaddr); - + segment = inb(PIOaddr); /* - * Out of range values so we'll assume non-existent IO device + * Out of range values so we'll assume non-existent IO device */ - if (segment < 0x40 || segment > 0xe0) - return -ENODEV; - + return -ENODEV; /* - * Compute the linear base address of the MMIO area - * as LINUX doesn't care about segments + * Compute the linear base address of the MMIO area + * as LINUX doesn't care about segments */ - - t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000); - intr = segment & 0x03; /* low bits is coded interrupt # */ + t_mmio = (((__u32) (segment & 0xfc) << 11) + 0x80000); + intr = segment & 0x03; /* low bits is coded interrupt # */ if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n", - PIOaddr, (int)segment, t_mmio, (int)intr); + DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n", PIOaddr, (int) segment, t_mmio, (int) intr); /* - * Now we will compare expected 'channelid' strings with - * what we is there to learn of ISA/MCA or not TR card + * Now we will compare expected 'channelid' strings with + * what we is there to learn of ISA/MCA or not TR card */ - - cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */ - tchanid=pcchannelid; - cardpresent=TR_ISA; /* try ISA */ - +#ifdef PCMCIA + ti = dev->priv; /*BMS moved up here */ + t_mmio = ti->mmio; /*BMS to get virtual address */ + irq = ti->irq; /*BMS to display the irq! */ +#endif + cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */ + tchanid = pcchannelid; + cardpresent = TR_ISA; /* try ISA */ /* - * Suboptimize knowing first byte different + * Suboptimize knowing first byte different */ - ctemp = readb(cd_chanid) & 0x0f; - if (ctemp != *tchanid) { /* NOT ISA card, try MCA */ - tchanid=mcchannelid; - cardpresent=TR_MCA; - if (ctemp != *tchanid) /* Neither ISA nor MCA */ - cardpresent=NOTOK; + if (ctemp != *tchanid) { /* NOT ISA card, try MCA */ + tchanid = mcchannelid; + cardpresent = TR_MCA; + if (ctemp != *tchanid) /* Neither ISA nor MCA */ + cardpresent = NOTOK; } - - if (cardpresent != NOTOK) - { + if (cardpresent != NOTOK) { /* - * Know presumed type, try rest of ID + * Know presumed type, try rest of ID */ - for (i=2,j=1; i<=46; i=i+2,j++) - { - if ((readb(cd_chanid+i) & 0x0f) != tchanid[j]) { - cardpresent=NOTOK; /* match failed, not TR card */ + for (i = 2, j = 1; i <= 46; i = i + 2, j++) { + if ((readb(cd_chanid + i) & 0x0f) != tchanid[j]) { + cardpresent = NOTOK; /* match failed, not TR card */ break; } } } - /* - * If we have an ISA board check for the ISA P&P version, - * as it has different IRQ settings + * If we have an ISA board check for the ISA P&P version, + * as it has different IRQ settings */ - - if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio)==0x0e)) - cardpresent=TR_ISAPNP; - - if (cardpresent == NOTOK) { /* "channel_id" did not match, report */ + if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e)) + cardpresent = TR_ISAPNP; + if (cardpresent == NOTOK) { /* "channel_id" did not match, report */ if (ibmtr_debug_trace & TRC_INIT) { DPRINTK("Channel ID string not found for PIOaddr: %4hx\n", PIOaddr); - DPRINTK("Expected for ISA: "); PrtChanID(pcchannelid,1); - DPRINTK(" found: "); HWPrtChanID(cd_chanid,2); - DPRINTK("Expected for MCA: "); PrtChanID(mcchannelid,1); + DPRINTK("Expected for ISA: "); + PrtChanID(pcchannelid, 1); + DPRINTK(" found: "); + HWPrtChanID(cd_chanid, 2); + DPRINTK("Expected for MCA: "); + PrtChanID(mcchannelid, 1); } - return -ENODEV; + return -ENODEV; } - /* Now, allocate some of the pl0 buffers for this driver.. */ /* If called from PCMCIA, ti is already set up, so no need to waste the memory, just use the existing structure */ #ifndef PCMCIA - ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL); - if (ti == NULL) + ti = (struct tok_info *) kmalloc(sizeof(struct tok_info), GFP_KERNEL); + if (ti == NULL) return -ENOMEM; - memset(ti, 0, sizeof(struct tok_info)); -#else - ti = dev->priv ; + ti->mmio = t_mmio; + dev->priv = ti; /* this seems like the logical use of the + field ... let's try some empirical tests + using the token-info structure -- that + should fit with out future hope of multiple + adapter support as well /dwm */ #endif - ti->mmio= t_mmio; ti->readlog_pending = 0; - dev->priv = ti; /* this seems like the logical use of the - field ... let's try some empirical tests - using the token-info structure -- that - should fit with out future hope of multiple - adapter support as well /dwm */ - - /* if PCMCIA, then the card is recognized as TR_ISAPNP - * and there is no need to set up the interrupt, it is already done. */ - + /* We ignore the retry count except for autonomous reopens so that we * + * don't hold up the operating system. */ + ti->retry_count = TR_RETRIES; + + /* if PCMCIA, the card can be recognized as either TR_ISA or TR_ISAPNP + * depending which card is inserted. */ + #ifndef PCMCIA - switch (cardpresent) - { - case TR_ISA: - if (intr==0) - irq=9; /* irq2 really is irq9 */ - if (intr==1) - irq=3; - if (intr==2) - irq=6; - if (intr==3) - irq=7; - ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq); - ti->adapter_int_enable=PIOaddr+ADAPTINTREL; - ti->sram=0; -#if !TR_NEWFORMAT - DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable); -#endif - break; - case TR_MCA: - if (intr==0) - irq=9; - if (intr==1) - irq=3; - if (intr==2) - irq=10; - if (intr==3) - irq=11; - ti->global_int_enable=0; - ti->adapter_int_enable=0; - ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12); - break; - case TR_ISAPNP: - if (intr==0) - irq=9; - if (intr==1) - irq=3; - if (intr==2) - irq=10; - if (intr==3) - irq=11; - timeout = jiffies + TR_SPIN_INTERVAL; - while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)) - if (time_after(jiffies, timeout)) { - DPRINTK("Hardware timeout during initialization.\n"); - kfree_s(ti, sizeof(struct tok_info)); - return -ENODEV; - } - - ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12); - ti->global_int_enable=PIOaddr+ADAPTINTREL; - ti->adapter_int_enable=PIOaddr+ADAPTINTREL; - break; - } -#endif + switch (cardpresent) { + case TR_ISA: + if (intr == 0) + irq = 9; /* irq2 really is irq9 */ + if (intr == 1) + irq = 3; + if (intr == 2) + irq = 6; + if (intr == 3) + irq = 7; + ti->global_int_enable = GLOBAL_INT_ENABLE + ((irq == 9) ? 2 : irq); + ti->adapter_int_enable = PIOaddr + ADAPTINTREL; + break; + case TR_MCA: + if (intr == 0) + irq = 9; + if (intr == 1) + irq = 3; + if (intr == 2) + irq = 10; + if (intr == 3) + irq = 11; + ti->global_int_enable = 0; + ti->adapter_int_enable = 0; + ti->sram_virt = ((__u32) (inb(PIOaddr + ADAPTRESETREL) & 0xfe) << 12); + break; + case TR_ISAPNP: + if (intr == 0) + irq = 9; + if (intr == 1) + irq = 3; + if (intr == 2) + irq = 10; + if (intr == 3) + irq = 11; + timeout = jiffies + TR_SPIN_INTERVAL; + while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)) + if (time_after(jiffies, timeout)) { + DPRINTK("Hardware timeout during initialization.\n"); + kfree_s(ti, sizeof(struct tok_info)); + return -ENODEV; + } + ti->sram_virt = ((__u32) readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN) << 12); + ti->global_int_enable = PIOaddr + ADAPTINTREL; + ti->adapter_int_enable = PIOaddr + ADAPTINTREL; + break; + } /*end switch (cardpresent) */ +#endif /*not PCMCIA */ - if (ibmtr_debug_trace & TRC_INIT) { /* just report int */ - DPRINTK("irq=%d",irq); - if (ibmtr_debug_trace & TRC_INITV) { /* full chat in verbose only */ - DPRINTK(", ti->mmio=%08X",ti->mmio); - printk(", segment=%02X",segment); + if (ibmtr_debug_trace & TRC_INIT) { /* just report int */ + DPRINTK("irq=%d", irq); + printk(", sram_virt=0x%x", ti->sram_virt); + if (ibmtr_debug_trace & TRC_INITV) { /* full chat in verbose only */ + DPRINTK(", ti->mmio=%08X", ti->mmio); + printk(", segment=%02X", segment); } printk(".\n"); } /* Get hw address of token ring card */ -#if !TR_NEWFORMAT - DPRINTK("hw address: "); -#endif - j=0; - for (i=0; i<0x18; i=i+2) - { + j = 0; + for (i = 0; i < 0x18; i = i + 2) { /* technical reference states to do this */ temp = readb(ti->mmio + AIP + i) & 0x0f; -#if !TR_NEWFORMAT - printk("%1X",ti->hw_address[j]=temp); -#else - ti->hw_address[j]=temp; -#endif - if(j&1) - dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4); + ti->hw_address[j] = temp; + if (j & 1) + dev->dev_addr[(j / 2)] = ti->hw_address[j] + (ti->hw_address[j - 1] << 4); ++j; } -#ifndef TR_NEWFORMAT - printk("\n"); -#endif - /* get Adapter type: 'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/ + /* get Adapter type: 'F' = Adapter/A, 'E' = 16/4 Adapter II,... */ ti->adapter_type = readb(ti->mmio + AIPADAPTYPE); /* get Data Rate: F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */ @@ -523,292 +497,263 @@ ti->token_release = readb(ti->mmio + AIPEARLYTOKEN); /* How much shared RAM is on adapter ? */ -#ifdef PCMCIA - ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti)); - ibmtr_mem_base = ti->sram_base << 12 ; -#else - ti->avail_shared_ram = get_sram_size(ti); -#endif + ti->avail_shared_ram = get_sram_size(ti); /* in 512 byte units */ + /* We need to set or do a bunch of work here based on previous results.. */ /* Support paging? What sizes?: F=no, E=16k, D=32k, C=16 & 32k */ ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE); - /* Available DHB 4Mb size: F=2048, E=4096, D=4464 */ + /* Available DHB 4Mb size: F=2048, E=4096, D=4464 */ switch (readb(ti->mmio + AIP4MBDHB)) { - case 0xe : + case 0xe: ti->dhb_size4mb = 4096; - break; - case 0xd : + break; + case 0xd: ti->dhb_size4mb = 4464; - break; - default : + break; + default: ti->dhb_size4mb = 2048; - break; + break; } - /* Available DHB 16Mb size: F=2048, E=4096, D=8192, C=16384, B=17960 */ switch (readb(ti->mmio + AIP16MBDHB)) { - case 0xe : + case 0xe: ti->dhb_size16mb = 4096; - break; - case 0xd : + break; + case 0xd: ti->dhb_size16mb = 8192; - break; - case 0xc : + break; + case 0xc: ti->dhb_size16mb = 16384; - break; - case 0xb : + break; + case 0xb: ti->dhb_size16mb = 17960; - break; - default : + break; + default: ti->dhb_size16mb = 2048; - break; + break; } -#if !TR_NEWFORMAT - DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, " - "dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type, - ti->data_rate, ti->token_release, ti->avail_shared_ram/2, - ti->shared_ram_paging, ti->dhb_size4mb, ti->dhb_size16mb); -#endif - - /* We must figure out how much shared memory space this adapter - * will occupy so that if there are two adapters we can fit both - * in. Given a choice, we will limit this adapter to 32K. The - * maximum space will will use for two adapters is 64K so if the - * adapter we are working on demands 64K (it also doesn't support - * paging), then only one adapter can be supported. + /* We must figure out how much shared memory space this adapter + * will occupy so that if there are two adapters we can fit both + * in. Given a choice, we will limit this adapter to 32K. The + * maximum space will will use for two adapters is 64K so if the + * adapter we are working on demands 64K (it also doesn't support + * paging), then only one adapter can be supported. */ /* - * determine how much of total RAM is mapped into PC space + * determine how much of total RAM is mapped into PC space */ - ti->mapped_ram_size=1<<((((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)) >>2) & 0x03) + 4); - ti->page_mask=0; - if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */ - ti->mapped_ram_size = ti->avail_shared_ram; + ti->mapped_ram_size = /* sixteen to one hundred twenty eight 512byte blocks */ + 1 << (((readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_ODD) >> 2) & 0x03) + 4); + ti->page_mask = 0; + if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */ } else { #ifdef ENABLE_PAGING - unsigned char pg_size=0; -#endif - -#if !TR_NEWFORMAT - DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2); -#endif -#ifdef ENABLE_PAGING - switch(ti->shared_ram_paging) - { + unsigned char pg_size = 0; + /* BMS: page size: PCMCIA, use configuration register; + ISAPNP, use LANAIDC config tool from www.ibm.com */ + switch (ti->shared_ram_paging) { case 0xf: break; case 0xe: - ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0; - pg_size=32; /* 16KB page size */ + ti->page_mask = (ti->mapped_ram_size == 32) ? 0xc0 : 0; + pg_size = 32; /* 16KB page size */ break; case 0xd: - ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0; - pg_size=64; /* 32KB page size */ + ti->page_mask = (ti->mapped_ram_size == 64) ? 0x80 : 0; + pg_size = 64; /* 32KB page size */ break; case 0xc: - switch (ti->mapped_ram_size) { - case 32: - ti->page_mask=0xc0; - pg_size=32; - break; - case 64: - ti->page_mask=0x80; - pg_size=64; - break; - } + switch (ti->mapped_ram_size) { + case 32: + ti->page_mask = 0xc0; + pg_size = 32; + break; + case 64: + ti->page_mask = 0x80; + pg_size = 64; + break; + } break; default: - DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging); + DPRINTK("Unknown shared ram paging info %01X\n", ti->shared_ram_paging); kfree_s(ti, sizeof(struct tok_info)); return -ENODEV; break; + } /*end switch shared_ram_paging */ + if (ibmtr_debug_trace & TRC_INIT) + DPRINTK("Shared RAM paging code: " + "%02X, mapped RAM size: %dK, shared RAM size: %dK, page mask: %02X\n:", + ti->shared_ram_paging, ti->mapped_ram_size / 2, ti->avail_shared_ram / 2, ti->page_mask); +#endif /*ENABLE_PAGING */ } - if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("Shared RAM paging code: " - "%02X mapped RAM size: %dK shared RAM size: %dK page mask: %0xX\n:", - ti->shared_ram_paging, ti->mapped_ram_size/2, ti->avail_shared_ram/2, ti->page_mask); - - if (ti->page_mask) { - if (pg_size > ti->mapped_ram_size) { - DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n", - pg_size/2, ti->mapped_ram_size/2); - ti->page_mask = 0; /* reset paging */ - } - } else if (pg_size > ti->mapped_ram_size) { - DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n", - pg_size/2, ti->mapped_ram_size/2); - } - -#endif - } +#ifndef PCMCIA /* finish figuring the shared RAM address */ - if (cardpresent==TR_ISA) { - static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000}; + if (cardpresent == TR_ISA) { + static __u32 ram_bndry_mask[] = { 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000 }; __u32 new_base, rrr_32, chk_base, rbm; - rrr_32 = ((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD))>>2) & 0x00000003; + rrr_32 = ((readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_ODD)) >> 2) & 0x03; rbm = ram_bndry_mask[rrr_32]; - new_base = (ibmtr_mem_base + (~rbm)) & rbm; /* up to boundary */ - chk_base = new_base + (ti->mapped_ram_size<<9); + new_base = (ibmtr_mem_base + (~rbm)) & rbm; /* up to boundary */ + chk_base = new_base + (ti->mapped_ram_size << 9); if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) { - DPRINTK("Shared RAM for this adapter (%05x) exceeds driver" - " limit (%05x), adapter not started.\n", - chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE); + DPRINTK("Shared RAM for this adapter (%05x) exceeds driver" " limit (%05x), adapter not started.\n", chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE); kfree_s(ti, sizeof(struct tok_info)); - return -ENODEV; - } else { /* seems cool, record what we have figured out */ + return -ENODEV; + } else { /* seems cool, record what we have figured out */ ti->sram_base = new_base >> 12; ibmtr_mem_base = chk_base; } } - -#if !TR_NEWFORMAT - DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2); -#endif + else ti->sram_base = ti->sram_virt >> 12; /* The PCMCIA has already got the interrupt line and the io port, so no chance of anybody else getting it - MLP */ - -#ifndef PCMCIA - if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) { - DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n",irq); + if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) { + DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n", irq); kfree_s(ti, sizeof(struct tok_info)); return -ENODEV; } - /*?? Now, allocate some of the PIO PORTs for this driver.. */ - request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr"); /* record PIOaddr range as busy */ -#endif - -#if !TR_NEWFORMAT - DPRINTK("%s",version); /* As we have passed card identification, - let the world know we're here! */ -#else - + /* record PIOaddr range as busy */ + request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr"); +#endif /*not PCMCIA */ +#ifndef PCMCIA if (version) { - printk("%s",version); - version = NULL; - } - DPRINTK("%s %s found\n", - channel_def[cardpresent-1], adapter_def(ti->adapter_type)); - DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", - irq, PIOaddr, ti->mapped_ram_size/2); - DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n", - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - if (ti->page_mask) - DPRINTK("Shared RAM paging enabled. Page size: %uK Shared Ram size %dK\n", - ((ti->page_mask ^ 0xff)+1)>>2,ti->avail_shared_ram/2); - else - DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n",ti->page_mask); + printk("%s", version); + version = NULL; + } #endif + DPRINTK("%s %s found\n", channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); + DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", irq, PIOaddr, ti->mapped_ram_size / 2); + DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + if (ti->page_mask) + DPRINTK("Shared RAM paging enabled. Page size: %uK Shared Ram size %dK\n", ((ti->page_mask ^ 0xff) + 1) >> 2, ti->avail_shared_ram / 2); + else + DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n", ti->page_mask); + /* Calculate the maximum DHB we can use */ if (!ti->page_mask) { - ti->avail_shared_ram=ti->mapped_ram_size; + /* two cases where avail_shared_ram doesn't equal mapped_ram_size: + 1. avail_shared_ram is 127 but mapped_ram_size is 128 (typical) + 2. user has configured adapter for less than avail_shared_ram + but is not using paging (she should use paging, I believe) + */ + ti->avail_shared_ram=MIN(ti->mapped_ram_size,ti->avail_shared_ram); } switch (ti->avail_shared_ram) { - case 16 : /* 8KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 16: /* 8KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 2; + ti->rbuf_cnt4=2; ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 2; + ti->rbuf_cnt16=2; break; - case 32 : /* 16KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); - ti->rbuf_len4 = 520; - ti->rbuf_cnt4 = 9; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); - ti->rbuf_len16 = 1032; /* 1024 usable */ - ti->rbuf_cnt16 = 4; + case 32: /* 16KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); + ti->rbuf_len4 = 1032; + ti->rbuf_cnt4=4; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 4096); + ti->rbuf_len16 = 1032; /*1024 usable */ + ti->rbuf_cnt16=4; break; - case 64 : /* 32KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 64: /* 32KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 6; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); + ti->rbuf_cnt4=6; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 10; + ti->rbuf_cnt16=6; break; - case 127 : /* 63KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 127: /* 63.5KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 6; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); + ti->rbuf_cnt4=6; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 16; + ti->rbuf_cnt16=16; break; - case 128 : /* 64KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 128: /* 64KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 6; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); + ti->rbuf_cnt4=6; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 18; + ti->rbuf_cnt16=16; break; - default : - ti->dhb_size4mb = 2048; + default: + ti->dhb_size4mb = 2048; ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 2; + ti->rbuf_cnt4=2; ti->dhb_size16mb = 2048; ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 2; + ti->rbuf_cnt16=2; break; } + /* these formulas are not smart enough for the paging case + ti->rbuf_cnt4 = (ti->avail_shared_ram * BLOCKSZ - + ADAPT_PRIVATE - ARBLENGTH - SSBLENGTH - + DLC_MAX_SAP * SAPLENGTH - DLC_MAX_STA * STALENGTH - ti->dhb_size4mb * NUM_DHB - SRBLENGTH - ASBLENGTH) / ti->rbuf_len4; + ti->rbuf_cnt16 = (ti->avail_shared_ram * BLOCKSZ - + ADAPT_PRIVATE - ARBLENGTH - SSBLENGTH - + DLC_MAX_SAP * SAPLENGTH - DLC_MAX_STA * STALENGTH - ti->dhb_size16mb * NUM_DHB - SRBLENGTH - ASBLENGTH) / ti->rbuf_len16; + */ + ti->maxmtu16 = (ti->rbuf_len16 - 8) * ti->rbuf_cnt16 - TR_HLEN; + ti->maxmtu4 = (ti->rbuf_len4 - 8) * ti->rbuf_cnt4 - TR_HLEN; + /*BMS assuming 18 bytes of Routing Information (usually works) */ + DPRINTK("Maximum Receive Internet Protocol MTU 16Mbps: %d, 4Mbps: %d\n", ti->maxmtu16, ti->maxmtu4); - ti->maxmtu16 = (ti->rbuf_len16*ti->rbuf_cnt16)-((ti->rbuf_cnt16)<<3)-TR_HLEN; - ti->maxmtu4 = (ti->rbuf_len4*ti->rbuf_cnt4)-((ti->rbuf_cnt4)<<3)-TR_HLEN; - DPRINTK("Maximum MTU 16Mbps: %d, 4Mbps: %d\n", - ti->maxmtu16, ti->maxmtu4); - - dev->base_addr=PIOaddr; /* set the value for device */ - + dev->base_addr = PIOaddr; /* set the value for device */ trdev_init(dev); tok_init_card(dev); + return 0; /* Return 0 to indicate we have found a Token Ring card. */ +} /*ibmtr_probe1() */ - return 0; /* Return 0 to indicate we have found a Token Ring card. */ -} +/*****************************************************************************/ /* query the adapter for the size of shared RAM */ +/* the function returns the RAM size in units of 512 bytes */ __initfunc(static unsigned char get_sram_size(struct tok_info *adapt_info)) { unsigned char avail_sram_code; - static unsigned char size_code[]={ 0,16,32,64,127,128 }; + static unsigned char size_code[] = { 0, 16, 32, 64, 127, 128 }; /* Adapter gives 'F' -- use RRR bits 3,2 'E' -- 8kb 'D' -- 16kb 'C' -- 32kb 'A' -- 64KB 'B' - 64KB less 512 bytes at top - (WARNING ... must zero top bytes in INIT */ + (WARNING ... must zero top bytes in INIT */ - avail_sram_code=0xf-readb(adapt_info->mmio + AIPAVAILSHRAM); + avail_sram_code = 0xf - readb(adapt_info->mmio + AIPAVAILSHRAM); if (avail_sram_code) return size_code[avail_sram_code]; - else /* for code 'F', must compute size from RRR(3,2) bits */ - return 1<<((readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4); + else /* for code 'F', must compute size from RRR(3,2) bits */ + return 1 << (((readb(adapt_info->mmio + ACA_OFFSET + ACA_RW + RRR_ODD) >> 2) & 0x03) + 4); } +/*****************************************************************************/ + __initfunc(static int trdev_init(struct device *dev)) { - struct tok_info *ti=(struct tok_info *)dev->priv; + struct tok_info *ti = (struct tok_info *) dev->priv; SET_PAGE(ti->srb_page); - ti->open_status = CLOSED; + ti->open_status = CLOSED; - dev->init = tok_init_card; - dev->open = tok_open; - dev->stop = tok_close; - dev->hard_start_xmit = tok_send_packet; - dev->get_stats = tok_get_stats; + dev->init = tok_init_card; + dev->open = tok_open; + dev->stop = tok_close; + dev->hard_start_xmit = tok_send_packet; + dev->get_stats = tok_get_stats; dev->set_multicast_list = tok_set_multicast_list; - dev->change_mtu = ibmtr_change_mtu; + dev->change_mtu = ibmtr_change_mtu; #ifndef MODULE #ifndef PCMCIA @@ -818,20 +763,141 @@ return 0; } +/*****************************************************************************/ + +static int tok_init_card(struct device *dev) +{ /* BMStok_init_card always returns zero */ + struct tok_info *ti; + short PIOaddr; + unsigned long i; + + PIOaddr = dev->base_addr; + ti = (struct tok_info *) dev->priv; + /* Special processing for first interrupt after reset */ + ti->do_tok_int = FIRST_INT; + /* Reset adapter */ + dev->tbusy = 1; /* nothing can be done before reset and open completed */ + writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); + outb(0, PIOaddr + ADAPTRESET); + for (i = jiffies + TR_RESET_INTERVAL; time_before_eq(jiffies, i);); /* wait 50ms */ + outb(0, PIOaddr + ADAPTRESETREL); +#ifdef ENABLE_PAGING + if (ti->page_mask) + writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); +#endif + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + i = sleep_on_timeout(&ti->wait_for_reset, 4 * HZ); + return 0; +} + +/*****************************************************************************/ +static int tok_open(struct device *dev) +{ + struct tok_info *ti = (struct tok_info *) dev->priv; + int i; + const char *printstate[] = {"CLOSED","SUCCESS","FAILURE","AUTOREOPEN"} ; + + /*BMS the case where we were left in a failure state during a previous open */ + if (ti->open_status == FAILURE) { + printk("Last time you were disconnected, how about now?\n"); + printk("Look, you cannot insert with your ICS connector half-cocked.\n"); + ti->open_status = CLOSED; + } + /* init the spinlock */ + ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + tok_open_adapter((unsigned long) dev); + i = sleep_on_timeout(&ti->wait_for_reset, 25 * HZ); + if (ti->open_status == SUCCESS) { + MOD_INC_USE_COUNT; + return 0; + } else { + printk("tok_open: returned with open_status==%s\n", printstate[ti->open_status]); /*BMS useful */ + return -EAGAIN; + } +} + +/*****************************************************************************/ + +void tok_open_adapter(unsigned long dev_addr) +{ + + struct device *dev = (struct device *) dev_addr; + struct tok_info *ti; + int i; + + ti = (struct tok_info *) dev->priv; + + writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); + writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); + + for (i = 0; i < sizeof(struct dir_open_adapter); i++) + writeb(0, ti->init_srb + i); + + writeb(DIR_OPEN_ADAPTER, ti->init_srb + offsetof(struct dir_open_adapter, command)); + writew(htons(OPEN_PASS_BCON_MAC), ti->init_srb + offsetof(struct dir_open_adapter, open_options)); + if (ti->ring_speed == 16) { + writew(htons(ti->dhb_size16mb), ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); + writew(htons(ti->rbuf_cnt16), ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); + writew(htons(ti->rbuf_len16), ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); + } else { + writew(htons(ti->dhb_size4mb), ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); + writew(htons(ti->rbuf_cnt4), ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); + writew(htons(ti->rbuf_len4), ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); + } + writeb(NUM_DHB, /* always 2 */ + ti->init_srb + offsetof(struct dir_open_adapter, num_dhb)); + writeb(DLC_MAX_SAP, ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap)); + writeb(DLC_MAX_STA, ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta)); + + ti->srb = ti->init_srb; /* We use this one in the interrupt handler */ + ti->srb_page = ti->init_srb_page; + DPRINTK("Opening adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n", + readb(ti->init_srb + offsetof(struct dir_open_adapter, num_dhb)), + ntohs(readw(ti->init_srb + offsetof(struct dir_open_adapter, dhb_length))), + ntohs(readw(ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf))), ntohs(readw(ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)))); + + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + +} + +/*****************************************************************************/ + +static void open_sap(unsigned char type, struct device *dev) +{ + int i; + struct tok_info *ti = (struct tok_info *) dev->priv; + SET_PAGE(ti->srb_page); + for (i = 0; i < sizeof(struct dlc_open_sap); i++) + writeb(0, ti->srb + i); + + writeb(DLC_OPEN_SAP, ti->srb + offsetof(struct dlc_open_sap, command)); + writew(htons(MAX_I_FIELD), ti->srb + offsetof(struct dlc_open_sap, max_i_field)); + writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, ti->srb + offsetof(struct dlc_open_sap, sap_options)); + writeb(SAP_OPEN_STATION_CNT, ti->srb + offsetof(struct dlc_open_sap, station_count)); + writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value)); + + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + +} + +/*****************************************************************************/ static void tok_set_multicast_list(struct device *dev) { - struct tok_info *ti=(struct tok_info *)dev->priv; + struct tok_info *ti = (struct tok_info *) dev->priv; struct dev_mc_list *mclist; unsigned char address[4]; int i; + /*BMS the next line is CRUCIAL or you may be sad when you */ + /*BMS ifconfig tr down or hot unplug a PCMCIA card */ + if (dev->start == 0 || ti->open_status != SUCCESS) + return; address[0] = address[1] = address[2] = address[3] = 0; - mclist = dev->mc_list; - for (i=0; i< dev->mc_count; i++) - { + for (i = 0; i < dev->mc_count; i++) { address[0] |= mclist->dmi_addr[2]; address[1] |= mclist->dmi_addr[3]; address[2] |= mclist->dmi_addr[4]; @@ -839,80 +905,102 @@ mclist = mclist->next; } SET_PAGE(ti->srb_page); - for (i=0; isrb+i); - - writeb(DIR_SET_FUNC_ADDR, - ti->srb + offsetof(struct srb_set_funct_addr, command)); + for (i = 0; i < sizeof(struct srb_set_funct_addr); i++) + writeb(0, ti->srb + i); + writeb(DIR_SET_FUNC_ADDR, ti->srb + offsetof(struct srb_set_funct_addr, command)); + for (i = 0; i < 4; i++) + writeb(address[i], ti->srb + offsetof(struct srb_set_funct_addr, funct_address) + i); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); +#if TR_VERBOSE DPRINTK("Setting functional address: "); - - for (i=0; i<4; i++) - { - writeb(address[i], - ti->srb + offsetof(struct srb_set_funct_addr, funct_address)+i); + for (i=0;i<4;i++) { printk("%02X ", address[i]); } - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); printk("\n"); +#endif } -static int tok_open(struct device *dev) +/*****************************************************************************/ + +static int tok_send_packet(struct sk_buff *skb, struct device *dev) { - struct tok_info *ti=(struct tok_info *)dev->priv; + struct tok_info *ti; + ti = (struct tok_info *) dev->priv; - /* init the spinlock */ - ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + if (dev->tbusy) { + int ticks_waited; - if (ti->open_status==CLOSED) tok_init_card(dev); + ticks_waited = jiffies - dev->trans_start; + if (ticks_waited < TR_BUSY_INTERVAL) + return 1; - if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset); + DPRINTK("Arrg. Transmitter busy.\n"); + dev->trans_start += 5; /* we fake the transmission start time... */ + return 1; + } - if (ti->open_status==SUCCESS) { - dev->tbusy=0; - dev->interrupt=0; - dev->start=1; - /* NEED to see smem size *AND* reset high 512 bytes if needed */ + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) + DPRINTK("Transmitter access conflict\n"); + else { + int flags; - MOD_INC_USE_COUNT; + /* lock against other CPUs */ + spin_lock_irqsave(&(ti->lock), flags); - return 0; - } else return -EAGAIN; + /* Save skb; we'll need it when the adapter asks for the data */ + ti->current_skb = skb; + SET_PAGE(ti->srb_page); + writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command)); + writew(ti->exsap_station_id, ti->srb + offsetof(struct srb_xmit, station_id)); + writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD)); + spin_unlock_irqrestore(&(ti->lock), flags); + dev->trans_start = jiffies; + } + + return 0; } +/*****************************************************************************/ + static int tok_close(struct device *dev) { - struct tok_info *ti=(struct tok_info *) dev->priv; - - SET_PAGE(ti->srb_page); - writeb(DIR_CLOSE_ADAPTER, - ti->srb + offsetof(struct srb_close_adapter, command)); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - ti->open_status=CLOSED; - - sleep_on(&ti->wait_for_tok_int); + struct tok_info *ti = (struct tok_info *) dev->priv; + char myclose = 0; + int x; + unsigned short y; - SET_PAGE(ti->srb_page); - if (readb(ti->srb + offsetof(struct srb_close_adapter, ret_code))) - DPRINTK("close adapter failed: %02X\n", - (int)readb(ti->srb + offsetof(struct srb_close_adapter, ret_code))); - dev->start = 0; -#ifdef PCMCIA - ti->sram = 0 ; -#endif - DPRINTK("Adapter closed.\n"); + x = del_timer(&ti->tr_timer); /*BMS Important for PCMCIA hot unplug */ + /* next line is crucial for PCMCIA */ + if (ti->open_status == SUCCESS && dev->start) { + myclose = 1; + SET_PAGE(ti->srb_page); + writeb(DIR_CLOSE_ADAPTER, ti->srb + offsetof(struct srb_close_adapter, command)); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + } + ti->open_status = CLOSED; /* indicator for popped timers */ + if (myclose) { + y = sleep_on_timeout(&ti->wait_for_tok_int, 2 * HZ); + /*BMSprintk("tok_close: returning from sleep, timeout=%d\n",y); */ + SET_PAGE(ti->srb_page); + if (readb(ti->srb + offsetof(struct srb_close_adapter, ret_code))) + DPRINTK("close adapter failed: %02X\n", (int) readb(ti->srb + offsetof(struct srb_close_adapter, ret_code))); + } + dev->start = 0; + DPRINTK("Adapter is closed.\n"); MOD_DEC_USE_COUNT; - return 0; } -void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs) +/*****************************************************************************/ + +void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - unsigned char status; + unsigned char status, prior_open_status; + /* unsigned char status_even ; */ struct tok_info *ti; struct device *dev; #ifdef ENABLE_PAGING @@ -921,427 +1009,353 @@ dev = dev_id; #if TR_VERBOSE - DPRINTK("Int from tok_driver, dev : %p\n",dev); + DPRINTK("Int from tok_driver, dev : %p\n", dev); #endif - ti = (struct tok_info *) dev->priv; + ti = (struct tok_info *) dev->priv; + if (ti->sram_virt & 1) + return; /* PCMCIA card extraction flag */ spin_lock(&(ti->lock)); #ifdef ENABLE_PAGING - save_srpr=readb(ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN); + save_srpr = readb(ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); #endif - /* Disable interrupts till processing is finished */ - dev->interrupt=1; + /* Disable interrupts till processing is finished */ + dev->interrupt = 1; writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); /* Reset interrupt for ISA boards */ - if (ti->adapter_int_enable) - outb(0,ti->adapter_int_enable); + if (ti->adapter_int_enable) + outb(0, ti->adapter_int_enable); else - outb(0,ti->global_int_enable); - + outb(0, ti->global_int_enable); switch (ti->do_tok_int) { - - case NOT_FIRST: - - /* Begin the regular interrupt handler HERE inline to avoid - the extra levels of logic and call depth for the - original solution. */ - - status=readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD); -#ifdef PCMCIA - /* Check if the PCMCIA card was pulled. */ - if (status == 0xFF) - { - DPRINTK("PCMCIA card removed.\n"); - dev->interrupt = 0; - goto return_point; - } - - /* Check ISRP EVEN too. */ - if ( readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF) - { - DPRINTK("PCMCIA card removed.\n"); - dev->interrupt = 0; - goto return_point; - } -#endif - - + case NOT_FIRST: + /* Begin the regular interrupt handler HERE inline to avoid the extra + levels of logic and call depth for the original solution. */ + status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD); + /*BMSstatus_even = readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) */ + /*BMSdebugprintk("tok_interrupt: ISRP_ODD = 0x%x ISRP_EVEN = 0x%x\n", */ + /*BMS status,status_even); */ if (status & ADAP_CHK_INT) { - int i; __u32 check_reason; - __u8 check_reason_page=0; - - check_reason=ntohs(readw(ti->sram + ACA_OFFSET + ACA_RW +WWCR_EVEN)); + __u8 check_reason_page = 0; + check_reason = ntohs(readw(ti->sram_virt + ACA_OFFSET + ACA_RW + WWCR_EVEN)); if (ti->page_mask) { - check_reason_page=(check_reason>>8) & ti->page_mask; - check_reason &= ~(ti->page_mask << 8); + check_reason_page = (check_reason >> 8) & ti->page_mask; + check_reason &= ~(ti->page_mask << 8); } - check_reason += ti->sram; + check_reason += ti->sram_virt; SET_PAGE(check_reason_page); DPRINTK("Adapter check interrupt\n"); DPRINTK("8 reason bytes follow: "); - for(i=0; i<8; i++, check_reason++) - printk("%02X ", (int)readb(check_reason)); + for (i = 0; i < 8; i++, check_reason++) + printk("%02X ", (int) readb(check_reason)); printk("\n"); - writeb((~ADAP_CHK_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - dev->interrupt=0; - + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + dev->interrupt = 0; } else if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) - & (TCR_INT | ERR_INT | ACCESS_INT)) { - - DPRINTK("adapter error: ISRP_EVEN : %02x\n", - (int)readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)); - writeb(~(TCR_INT | ERR_INT | ACCESS_INT), - ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - dev->interrupt=0; - - } else if (status - & (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) { + & (TCR_INT | ERR_INT | ACCESS_INT)) { + DPRINTK("adapter error: ISRP_EVEN : %02x\n", (int) readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)); + writeb(~(TCR_INT | ERR_INT | ACCESS_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + dev->interrupt = 0; + } else if (status & (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) { /* SRB, ASB, ARB or SSB response */ - - if (status & SRB_RESP_INT) { /* SRB response */ - SET_PAGE(ti->srb_page); + if (status & SRB_RESP_INT) { /* SRB response */ + SET_PAGE(ti->srb_page); #if TR_VERBOSE - DPRINTK("SRB resp: cmd=%02X rsp=%02X\n", - readb(ti->srb), - readb(ti->srb + offsetof(struct srb_xmit, ret_code))); -#endif - - switch(readb(ti->srb)) { /* SRB command check */ - - case XMIT_DIR_FRAME: { - unsigned char xmit_ret_code; - - xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code)); - if (xmit_ret_code != 0xff) { - DPRINTK("error on xmit_dir_frame request: %02X\n", - xmit_ret_code); - if (ti->current_skb) { - dev_kfree_skb(ti->current_skb); - ti->current_skb=NULL; - } - dev->tbusy=0; - if (ti->readlog_pending) ibmtr_readlog(dev); - } - } - break; - - case XMIT_UI_FRAME: { - unsigned char xmit_ret_code; - - xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code)); - if (xmit_ret_code != 0xff) { - DPRINTK("error on xmit_ui_frame request: %02X\n", - xmit_ret_code); - if (ti->current_skb) { - dev_kfree_skb(ti->current_skb); - ti->current_skb=NULL; - } - dev->tbusy=0; - if (ti->readlog_pending) ibmtr_readlog(dev); - } - } - break; - - case DIR_OPEN_ADAPTER: { - unsigned char open_ret_code; - __u16 open_error_code; - - ti->srb=ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, srb_addr))); - ti->ssb=ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, ssb_addr))); - ti->arb=ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, arb_addr))); - ti->asb=ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, asb_addr))); - if (ti->page_mask) { - ti->srb_page=(ti->srb>>8) & ti->page_mask; - ti->srb &= ~(ti->page_mask<<8); - ti->ssb_page=(ti->ssb>>8) & ti->page_mask; - ti->ssb &= ~(ti->page_mask<<8); - ti->arb_page=(ti->arb>>8) & ti->page_mask; - ti->arb &= ~(ti->page_mask<<8); - ti->asb_page=(ti->asb>>8) & ti->page_mask; - ti->asb &= ~(ti->page_mask<<8); - } - ti->srb+=ti->sram; - ti->ssb+=ti->sram; - ti->arb+=ti->sram; - ti->asb+=ti->sram; - - ti->current_skb=NULL; - - open_ret_code = readb(ti->init_srb +offsetof(struct srb_open_response, ret_code)); - open_error_code = ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, error_code))); - - if (open_ret_code==7) { - - if (!ti->auto_ringspeedsave && (open_error_code==0x24)) { - DPRINTK("Open failed: Adapter speed must match ring " - "speed if Automatic Ring Speed Save is disabled.\n"); - ti->open_status=FAILURE; - wake_up(&ti->wait_for_reset); - } else if (open_error_code==0x24) - DPRINTK("Retrying open to adjust to ring speed.\n"); - else if ((open_error_code==0x2d) && ti->auto_ringspeedsave) - DPRINTK("No signal detected for Auto Speed Detection.\n"); - else if (open_error_code==0x11) - { - if (ti->retry_count--) - DPRINTK("Ring broken/disconnected, retrying...\n"); - else { - DPRINTK("Ring broken/disconnected, open failed.\n"); - ti->open_status = FAILURE; - } - } - else DPRINTK("Unrecoverable error: error code = %04x.\n", - open_error_code); - - } else if (!open_ret_code) { -#if !TR_NEWFORMAT - DPRINTK("board opened...\n"); -#else - DPRINTK("Adapter initialized and opened.\n"); -#endif - writeb(~(SRB_RESP_INT), - ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - writeb(~(CMD_IN_SRB), - ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); - open_sap(EXTENDED_SAP,dev); - - /* YdW probably hates me */ - goto skip_reset; - } else - DPRINTK("open failed: ret_code = %02X, retrying\n", - open_ret_code); - - if (ti->open_status != FAILURE) { - ibmtr_reset_timer(&(ti->tr_timer), dev); - } + DPRINTK("SRB resp: cmd=%02X rsp=%02X\n", readb(ti->srb), readb(ti->srb + offsetof(struct srb_xmit, ret_code))); +#endif - } - break; + switch (readb(ti->srb)) { /* SRB command check */ + case XMIT_DIR_FRAME:{ + unsigned char xmit_ret_code; + xmit_ret_code = readb(ti->srb + offsetof(struct srb_xmit, ret_code)); + if (xmit_ret_code != 0xff) { + DPRINTK("error on xmit_dir_frame request: %02X\n", xmit_ret_code); + if (ti->current_skb) { + dev_kfree_skb(ti->current_skb); + ti->current_skb = NULL; + } + dev->tbusy = 0; + if (ti->readlog_pending) + ibmtr_readlog(dev); + } + } + break; + case XMIT_UI_FRAME:{ + unsigned char xmit_ret_code; - case DIR_CLOSE_ADAPTER: + xmit_ret_code = readb(ti->srb + offsetof(struct srb_xmit, ret_code)); + if (xmit_ret_code != 0xff) { + DPRINTK("error on xmit_ui_frame request: %02X\n", xmit_ret_code); + if (ti->current_skb) { + dev_kfree_skb(ti->current_skb); + ti->current_skb = NULL; + } + dev->tbusy = 0; + if (ti->readlog_pending) + ibmtr_readlog(dev); + } + } + break; + case DIR_OPEN_ADAPTER:{ + unsigned char open_ret_code; + __u16 open_error_code; + ti->srb = ntohs(readw(ti->init_srb + offsetof(struct srb_open_response, srb_addr))); + ti->ssb = ntohs(readw(ti->init_srb + offsetof(struct srb_open_response, ssb_addr))); + ti->arb = ntohs(readw(ti->init_srb + offsetof(struct srb_open_response, arb_addr))); + ti->asb = ntohs(readw(ti->init_srb + offsetof(struct srb_open_response, asb_addr))); + if (ti->page_mask) { + ti->srb_page = (ti->srb >> 8) & ti->page_mask; + ti->srb &= ~(ti->page_mask << 8); + ti->ssb_page = (ti->ssb >> 8) & ti->page_mask; + ti->ssb &= ~(ti->page_mask << 8); + ti->arb_page = (ti->arb >> 8) & ti->page_mask; + ti->arb &= ~(ti->page_mask << 8); + ti->asb_page = (ti->asb >> 8) & ti->page_mask; + ti->asb &= ~(ti->page_mask << 8); + } + ti->srb += ti->sram_virt; + ti->ssb += ti->sram_virt; + ti->arb += ti->sram_virt; + ti->asb += ti->sram_virt; + + ti->current_skb = NULL; + open_ret_code = readb(ti->init_srb + offsetof(struct srb_open_response, ret_code)); + open_error_code = ntohs(readw(ti->init_srb + offsetof(struct srb_open_response, error_code))); + prior_open_status = ti->open_status; + if (!open_ret_code) { + if (ti->open_status == AUTOREOPEN) { + DPRINTK("Adapter reopened.\n"); + ti->retry_count = TR_RETRIES; + } + writeb(~(SRB_RESP_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); + writeb(~(CMD_IN_SRB), ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); + open_sap(EXTENDED_SAP, dev); + /* YdW probably hates me */ + goto skip_reset; + } else if (open_ret_code == 7) { + if (ti->open_status == CLOSED || ti->retry_count == 0) { + /* Don't delay the operating system */ + ti->open_status = FAILURE; + DPRINTK("Token Ring Adapter Open failed with adapter error"); + printk(" code 0x%x, Sianara\n until ifconfig tr up\n", open_error_code); + } else { + if (open_error_code == 0x24) { + if (!ti->auto_ringspeedsave) { + DPRINTK("Open failed: Adapter speed must match ring " + "speed if Automatic Ring Speed Save is disabled.\n"); + ti->open_status = FAILURE; + } else { + DPRINTK("Retrying open to adjust to ring speed.\n"); + } + } else if (open_error_code == 0x2d) { + DPRINTK("Physical Insertion: No Monitor Detected,"); + printk(" retrying after 30s delay...\n"); + } else if (open_error_code == 0x11) { + DPRINTK("Lobe Media Function Failure (0x11), "); + printk("retrying after 30s delay...\n"); + } else { + DPRINTK("TR Adapter misc open failure, error code = "); + printk("0x%x, retrying after 30s delay...\n", open_error_code); + } + } + } /*if open_ret_code==7 */ + else { + if (ti->open_status == CLOSED || ti->retry_count == 0) + /* Don't delay the operating system */ + ti->open_status = FAILURE; + DPRINTK("open failed: ret_code = %02X..., ", open_ret_code); + } + if (ti->retry_count) + ti->retry_count--; + if (ti->open_status != FAILURE) { + ibmtr_reset_timer(&(ti->tr_timer), dev); + } else { + if (prior_open_status == CLOSED) + wake_up(&ti->wait_for_reset); + else + ti->retry_count = TR_RETRIES; + } + } /*case DIR_OPEN_ADAPTER */ + break; + case DIR_CLOSE_ADAPTER: wake_up(&ti->wait_for_tok_int); break; - - case DLC_OPEN_SAP: - if (readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))) { - DPRINTK("open_sap failed: ret_code = %02X,retrying\n", - (int)readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))); + case DLC_OPEN_SAP: + if (readb(ti->srb + offsetof(struct dlc_open_sap, ret_code))) { + DPRINTK("open_sap failed: ret_code = %02X,retrying\n", (int) readb(ti->srb + offsetof(struct dlc_open_sap, ret_code))); ibmtr_reset_timer(&(ti->tr_timer), dev); } else { - ti->exsap_station_id= - readw(ti->srb+offsetof(struct dlc_open_sap, station_id)); - ti->open_status=SUCCESS; /* TR adapter is now available */ - wake_up(&ti->wait_for_reset); + ti->exsap_station_id = readw(ti->srb + offsetof(struct dlc_open_sap, station_id)); + prior_open_status = ti->open_status; + ti->open_status = SUCCESS; /* TR adapter is now available */ + /*debugprintk("tok_interrupt: ti->open_status=SUCCESS\n"); */ + /*BMS I moved these two lines from tok_open so I don't have to sleep */ + dev->tbusy = 0; + dev->start = 1; + if (prior_open_status == CLOSED) + wake_up(&ti->wait_for_reset); } break; - - case DIR_INTERRUPT: - case DIR_MOD_OPEN_PARAMS: - case DIR_SET_GRP_ADDR: - case DIR_SET_FUNC_ADDR: - case DLC_CLOSE_SAP: - if (readb(ti->srb+offsetof(struct srb_interrupt, ret_code))) - DPRINTK("error on %02X: %02X\n", - (int)readb(ti->srb+offsetof(struct srb_interrupt, command)), - (int)readb(ti->srb+offsetof(struct srb_interrupt, ret_code))); + case DIR_INTERRUPT: + case DIR_MOD_OPEN_PARAMS: + case DIR_SET_GRP_ADDR: + case DIR_SET_FUNC_ADDR: + case DLC_CLOSE_SAP: + if (readb(ti->srb + offsetof(struct srb_interrupt, ret_code))) + DPRINTK("error on %02X: %02X\n", + (int) readb(ti->srb + offsetof(struct srb_interrupt, command)), + (int) readb(ti->srb + offsetof(struct srb_interrupt, ret_code))); break; - - case DIR_READ_LOG: - if (readb(ti->srb+offsetof(struct srb_read_log, ret_code))) - DPRINTK("error on dir_read_log: %02X\n", - (int)readb(ti->srb+offsetof(struct srb_read_log, ret_code))); - else - if (IBMTR_DEBUG_MESSAGES) { - DPRINTK( - "Line errors %02X, Internal errors %02X, Burst errors %02X\n" + case DIR_READ_LOG: + if (readb(ti->srb + offsetof(struct srb_read_log, ret_code))) + DPRINTK("error on dir_read_log: %02X\n", (int) readb(ti->srb + offsetof(struct srb_read_log, ret_code))); + else if (IBMTR_DEBUG_MESSAGES) { + DPRINTK("Line errors %02X, Internal errors %02X, Burst errors %02X\n" "A/C errors %02X, Abort delimiters %02X, Lost frames %02X\n" "Receive congestion count %02X, Frame copied errors %02X\n" "Frequency errors %02X, Token errors %02X\n", - (int)readb(ti->srb+offsetof(struct srb_read_log, - line_errors)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - internal_errors)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - burst_errors)), - (int)readb(ti->srb+offsetof(struct srb_read_log, A_C_errors)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - abort_delimiters)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - lost_frames)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - recv_congest_count)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - frame_copied_errors)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - frequency_errors)), - (int)readb(ti->srb+offsetof(struct srb_read_log, - token_errors))); - } - dev->tbusy=0; + (int) readb(ti->srb + offsetof(struct srb_read_log, line_errors)), + (int) readb(ti->srb + offsetof(struct srb_read_log, internal_errors)), + (int) readb(ti->srb + offsetof(struct srb_read_log, burst_errors)), + (int) readb(ti->srb + offsetof(struct srb_read_log, A_C_errors)), + (int) readb(ti->srb + offsetof(struct srb_read_log, abort_delimiters)), + (int) readb(ti->srb + offsetof(struct srb_read_log, lost_frames)), + (int) readb(ti->srb + offsetof(struct srb_read_log, recv_congest_count)), + (int) readb(ti->srb + offsetof(struct srb_read_log, frame_copied_errors)), + (int) readb(ti->srb + offsetof(struct srb_read_log, frequency_errors)), + (int) readb(ti->srb + offsetof(struct srb_read_log, token_errors))); + } + dev->tbusy = 0; break; - - default: - DPRINTK("Unknown command %02X encountered\n", - (int)readb(ti->srb)); - - } /* SRB command check */ - + default: + DPRINTK("Unknown command %02X encountered\n", (int) readb(ti->srb)); + } /* end switch SRB command check */ writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - - skip_reset: - } /* SRB response */ - - if (status & ASB_FREE_INT) { /* ASB response */ - SET_PAGE(ti->asb_page); + skip_reset: + } /* if SRB response */ + if (status & ASB_FREE_INT) { /* ASB response */ + SET_PAGE(ti->asb_page); #if TR_VERBOSE - DPRINTK("ASB resp: cmd=%02X\n", readb(ti->asb)); + DPRINTK("ASB resp: cmd=%02X\n", readb(ti->asb)); #endif - switch(readb(ti->asb)) { /* ASB command check */ - - case REC_DATA: - case XMIT_UI_FRAME: - case XMIT_DIR_FRAME: + switch (readb(ti->asb)) { /* ASB command check */ + case REC_DATA: + case XMIT_UI_FRAME: + case XMIT_DIR_FRAME: break; - - default: - DPRINTK("unknown command in asb %02X\n", - (int)readb(ti->asb)); - - } /* ASB command check */ - - if (readb(ti->asb+2)!=0xff) /* checks ret_code */ - DPRINTK("ASB error %02X in cmd %02X\n", - (int)readb(ti->asb+2),(int)readb(ti->asb)); + default: + DPRINTK("unknown command in asb %02X\n", (int) readb(ti->asb)); + } /* switch ASB command check */ + if (readb(ti->asb + 2) != 0xff) /* checks ret_code */ + DPRINTK("ASB error %02X in cmd %02X\n", (int) readb(ti->asb + 2), (int) readb(ti->asb)); writeb(~ASB_FREE_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - - } /* ASB response */ - - if (status & ARB_CMD_INT) { /* ARB response */ - SET_PAGE(ti->arb_page); -#if TR_VERBOSE - DPRINTK("ARB resp: cmd=%02X rsp=%02X\n", - readb(ti->arb), - readb(ti->arb + offsetof(struct arb_dlc_status, status))); + } /* if ASB response */ + if (status & ARB_CMD_INT) { /* ARB response */ + SET_PAGE(ti->arb_page); +#if TR_VERBOSE + DPRINTK("ARB resp: cmd=%02X\n", readb(ti->arb)); #endif - switch (readb(ti->arb)) { /* ARB command check */ - - case DLC_STATUS: + switch (readb(ti->arb)) { /* ARB command check */ + case DLC_STATUS: DPRINTK("DLC_STATUS new status: %02X on station %02X\n", ntohs(readw(ti->arb + offsetof(struct arb_dlc_status, status))), - ntohs(readw(ti->arb - +offsetof(struct arb_dlc_status, station_id)))); + ntohs(readw(ti->arb + offsetof(struct arb_dlc_status, station_id)))); break; - - case REC_DATA: + case REC_DATA: tr_rx(dev); break; - - case RING_STAT_CHANGE: { - unsigned short ring_status; - - ring_status=ntohs(readw(ti->arb - +offsetof(struct arb_ring_stat_change, ring_status))); - - if (ring_status & (SIGNAL_LOSS | LOBE_FAULT)) { - - DPRINTK("Signal loss/Lobe fault\n"); - DPRINTK("We try to reopen the adapter.\n"); - ibmtr_reset_timer(&(ti->tr_timer), dev); - } else if (ring_status & (HARD_ERROR | XMIT_BEACON - | AUTO_REMOVAL | REMOVE_RECV | RING_RECOVER)) - DPRINTK("New ring status: %02X\n", ring_status); - - if (ring_status & LOG_OVERFLOW) { - if (dev->tbusy) - ti->readlog_pending = 1; - else - ibmtr_readlog(dev); - } - } - break; - - case XMIT_DATA_REQ: + case RING_STAT_CHANGE:{ + unsigned short ring_status; + ring_status = ntohs(readw(ti->arb + offsetof(struct arb_ring_stat_change, ring_status))); + if (ibmtr_debug_trace & TRC_INIT) + DPRINTK("Ring Status Change...(0x%x)\n", ring_status); + if (ring_status & (REMOVE_RECV | AUTO_REMOVAL | LOBE_FAULT)) { + DPRINTK("Remove received, or Auto-removal error, or Lobe fault\n"); + DPRINTK("We'll try to reopen the closed adapter after "); + printk("a 30 second delay.\n"); + /*we give this hint for tok_close; he need not do another close */ + /*BMS the following "if" could probably be replaced with "if 1" */ + /*BMS I was confused because I saw the ibmtr keep reopening but */ + /*BMS I forgot that with an RJ45 plugged into an RJ45/ICS adapter */ + /*BMS but that adapter not in the ring, the TR will successfully */ + /*BMS open, and then shortly afterwards close and come here. */ + if (ti->open_status != AUTOREOPEN) { + ti->open_status = AUTOREOPEN; + ibmtr_reset_timer(&(ti->tr_timer), dev); + } + } else { + if (ring_status & LOG_OVERFLOW) { + if (dev->tbusy) + ti->readlog_pending = 1; + else + ibmtr_readlog(dev); + } + } + } + break; + case XMIT_DATA_REQ: tr_tx(dev); break; - - default: - DPRINTK("Unknown command %02X in arb\n", - (int)readb(ti->arb)); + default: + DPRINTK("Unknown command %02X in arb\n", (int) readb(ti->arb)); break; - - } /* ARB command check */ - + } /* switch ARB command check */ writeb(~ARB_CMD_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - } /* ARB response */ - - if (status & SSB_RESP_INT) { /* SSB response */ + } /* if ARB response */ + if (status & SSB_RESP_INT) { /* SSB response */ unsigned char retcode; - SET_PAGE(ti->ssb_page); + SET_PAGE(ti->ssb_page); #if TR_VERBOSE - DPRINTK("SSB resp: cmd=%02X rsp=%02X\n", - readb(ti->ssb), readb(ti->ssb+2)); + DPRINTK("SSB resp: cmd=%02X rsp=%02X\n", readb(ti->ssb), readb(ti->ssb + 2)); #endif - switch (readb(ti->ssb)) { /* SSB command check */ - - case XMIT_DIR_FRAME: - case XMIT_UI_FRAME: - retcode = readb(ti->ssb+2); - if (retcode && (retcode != 0x22)) /* checks ret_code */ - DPRINTK("xmit ret_code: %02X xmit error code: %02X\n", - (int)retcode, (int)readb(ti->ssb+6)); - else ti->tr_stats.tx_packets++; - break; - case XMIT_XID_CMD: - DPRINTK("xmit xid ret_code: %02X\n", (int)readb(ti->ssb+2)); + switch (readb(ti->ssb)) { /* SSB command check */ + case XMIT_DIR_FRAME: + case XMIT_UI_FRAME: + retcode = readb(ti->ssb + 2); + if (retcode && (retcode != 0x22)) /* checks ret_code */ + DPRINTK("xmit ret_code: %02X xmit error code: %02X\n", (int) retcode, (int) readb(ti->ssb + 6)); + else + ti->tr_stats.tx_packets++; break; - - default: - DPRINTK("Unknown command %02X in ssb\n", (int)readb(ti->ssb)); - - } /* SSB command check */ - + case XMIT_XID_CMD: + DPRINTK("xmit xid ret_code: %02X\n", (int) readb(ti->ssb + 2)); + default: + DPRINTK("Unknown command %02X in ssb\n", (int) readb(ti->ssb)); + } /* SSB command check */ writeb(~SSB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - } /* SSB response */ - - } /* SRB, ARB, ASB or SSB response */ - - dev->interrupt=0; + } /* if SSB response */ + } /* if SRB, ARB, ASB or SSB response */ + dev->interrupt = 0; writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); break; - - case FIRST_INT: + case FIRST_INT: initial_tok_int(dev); break; - - default: + default: DPRINTK("Unexpected interrupt from tr adapter\n"); - } -#ifdef PCMCIA - return_point: -#endif #ifdef ENABLE_PAGING - writeb(save_srpr, ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN); + writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); #endif + spin_unlock(&(ti->lock)); -} +} /*tok_interrupt */ + +/*****************************************************************************/ static void initial_tok_int(struct device *dev) { @@ -1349,268 +1363,118 @@ __u32 encoded_addr; __u32 hw_encoded_addr; struct tok_info *ti; - ti=(struct tok_info *) dev->priv; - - ti->do_tok_int=NOT_FIRST; + ti = (struct tok_info *) dev->priv; -#ifndef TR_NEWFORMAT - DPRINTK("Initial tok int received\n"); -#endif + ti->do_tok_int = NOT_FIRST; /* we assign the shared-ram address for ISA devices */ - if(!ti->sram) { - writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN); - ti->sram=((__u32)ti->sram_base << 12); - } - ti->init_srb=ntohs((unsigned short)readw(ti->mmio+ ACA_OFFSET + WRBR_EVEN)); + writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN); +#ifndef PCMCIA + ti->sram_virt=((__u32)ti->sram_base << 12); +#endif + ti->init_srb = ntohs((unsigned short) readw(ti->mmio + ACA_OFFSET + WRBR_EVEN)); if (ti->page_mask) { - ti->init_srb_page=(ti->init_srb>>8)&ti->page_mask; - ti->init_srb &= ~(ti->page_mask<<8); + ti->init_srb_page = (ti->init_srb >> 8) & ti->page_mask; + ti->init_srb &= ~(ti->page_mask << 8); + } + ti->init_srb += ti->sram_virt; + if (ti->page_mask && ti->avail_shared_ram == 127) { + int last_512 = 0xfe00, i; + int last_512_page=0; + last_512_page=(last_512>>8)&ti->page_mask; + last_512 &= ~(ti->page_mask << 8); + /* initialize high section of ram (if necessary) */ + SET_PAGE(last_512_page); + for (i = 0; i < 512; i++) + writeb(0, ti->sram_virt + last_512 + i); } - ti->init_srb+=ti->sram; - - if (ti->avail_shared_ram == 127) { - int i; - int last_512=0xfe00; - if (ti->page_mask) { - last_512 &= ~(ti->page_mask<<8); - } - // initialize high section of ram (if necessary) - SET_PAGE(0xc0); - for (i=0; i<512; i++) { - writeb(0,ti->sram+last_512+i); - } - } SET_PAGE(ti->init_srb_page); - - dev->mem_start = ti->sram; - dev->mem_end = ti->sram + (ti->mapped_ram_size<<9) - 1; - + dev->mem_start = ti->sram_base << 12; + dev->mem_end = dev->mem_start + (ti->mapped_ram_size << 9) - 1; #if TR_VERBOSE { int i; - DPRINTK("init_srb(%lx):", (long)ti->init_srb); - for (i=0;i<17;i++) printk("%02X ", (int)readb(ti->init_srb+i)); + DPRINTK("ti->init_srb_page=0x%x\n", ti->init_srb_page); + DPRINTK("init_srb(%p):", ti->init_srb); + for (i = 0; i < 20; i++) + printk("%02X ", (int) readb(ti->init_srb + i)); printk("\n"); } #endif + hw_encoded_addr = readw(ti->init_srb + offsetof(struct srb_init_response, encoded_address)); + encoded_addr = ntohs(hw_encoded_addr); + ti->ring_speed = readb(ti->init_srb + offsetof(struct srb_init_response, init_status)) & 0x01 ? 16 : 4; + DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n", ti->ring_speed, (unsigned int)dev->mem_start); + ti->auto_ringspeedsave = readb(ti->init_srb + offsetof(struct srb_init_response, init_status_2)) & 0x4 ? TRUE : FALSE; + wake_up(&ti->wait_for_reset); +} /*initial_tok_int() */ - hw_encoded_addr = readw(ti->init_srb - + offsetof(struct srb_init_response, encoded_address)); - -#if !TR_NEWFORMAT - DPRINTK("srb_init_response->encoded_address: %04X\n", hw_encoded_addr); - DPRINTK("ntohs(srb_init_response->encoded_address): %04X\n", - ntohs(hw_encoded_addr)); -#endif - - encoded_addr=(ti->sram + ntohs(hw_encoded_addr)); - ti->ring_speed = readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01 ? 16 : 4; -#if !TR_NEWFORMAT - DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr, - ntohs(hw_encoded_addr), encoded_addr); -#else - DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n", - ti->ring_speed, ti->sram); -#endif - - ti->auto_ringspeedsave=readb(ti->init_srb - +offsetof(struct srb_init_response, init_status_2)) & 0x4 ? TRUE : FALSE; - -#if !TR_NEWFORMAT - for(i=0;idev_addr[i]=readb(encoded_addr + i); - printk("%02X%s", dev->dev_addr[i], (i==TR_ALEN-1) ? "" : ":" ); - } - printk("\n"); -#endif - - tok_open_adapter((unsigned long)dev); -} - -static int tok_init_card(struct device *dev) -{ - struct tok_info *ti; - short PIOaddr; - unsigned long i; - PIOaddr = dev->base_addr; - ti=(struct tok_info *) dev->priv; - - /* Special processing for first interrupt after reset */ - ti->do_tok_int=FIRST_INT; - - /* Reset adapter */ - dev->tbusy=1; /* nothing can be done before reset and open completed */ - - - writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); - -#if !TR_NEWFORMAT - DPRINTK("resetting card\n"); -#endif - - outb(0, PIOaddr+ADAPTRESET); - for (i=jiffies+TR_RESET_INTERVAL; time_before_eq(jiffies, i);); /* wait 50ms */ - outb(0,PIOaddr+ADAPTRESETREL); -#ifdef ENABLE_PAGING - if(ti->page_mask) - writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); -#endif - -#if !TR_NEWFORMAT - DPRINTK("card reset\n"); -#endif - - ti->open_status=IN_PROGRESS; - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - return 0; -} - -static void open_sap(unsigned char type,struct device *dev) -{ - int i; - struct tok_info *ti=(struct tok_info *) dev->priv; - - SET_PAGE(ti->srb_page); - for (i=0; isrb+i); - - writeb(DLC_OPEN_SAP, ti->srb + offsetof(struct dlc_open_sap, command)); - writew(htons(MAX_I_FIELD), - ti->srb + offsetof(struct dlc_open_sap, max_i_field)); - writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, - ti->srb + offsetof(struct dlc_open_sap, sap_options)); - writeb(SAP_OPEN_STATION_CNT, - ti->srb + offsetof(struct dlc_open_sap, station_count)); - writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value)); - - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - -} - -void tok_open_adapter(unsigned long dev_addr) -{ - - struct device *dev=(struct device *)dev_addr; - struct tok_info *ti; - int i; - - ti=(struct tok_info *) dev->priv; - -#if !TR_NEWFORMAT - DPRINTK("now opening the board...\n"); -#endif - - writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); - - for (i=0; iinit_srb+i); - - writeb(DIR_OPEN_ADAPTER, - ti->init_srb + offsetof(struct dir_open_adapter, command)); - writew(htons(OPEN_PASS_BCON_MAC), - ti->init_srb + offsetof(struct dir_open_adapter, open_options)); - if (ti->ring_speed == 16) { - writew(htons(ti->dhb_size16mb), - ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); - writew(htons(ti->rbuf_cnt16), - ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); - writew(htons(ti->rbuf_len16), - ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); - } else { - writew(htons(ti->dhb_size4mb), - ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); - writew(htons(ti->rbuf_cnt4), - ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); - writew(htons(ti->rbuf_len4), - ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); - } - writeb(NUM_DHB, /* always 2 */ - ti->init_srb + offsetof(struct dir_open_adapter, num_dhb)); - writeb(DLC_MAX_SAP, - ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap)); - writeb(DLC_MAX_STA, - ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta)); - - ti->srb=ti->init_srb; /* We use this one in the interrupt handler */ - ti->srb_page=ti->init_srb_page; - DPRINTK("Opend adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n", - readb(ti->init_srb+offsetof(struct dir_open_adapter,num_dhb)), - ntohs(readw(ti->init_srb+offsetof(struct dir_open_adapter,dhb_length))), - ntohs(readw(ti->init_srb+offsetof(struct dir_open_adapter,num_rcv_buf))), - ntohs(readw(ti->init_srb+offsetof(struct dir_open_adapter,rcv_buf_len))) ); - - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - -} +/*****************************************************************************/ static void tr_tx(struct device *dev) { - struct tok_info *ti=(struct tok_info *) dev->priv; - struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data; + struct tok_info *ti = (struct tok_info *) dev->priv; + struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data; unsigned int hdr_len; - __u32 dhb; + __u32 dhb=0,dhb_base; unsigned char xmit_command; - int i; - struct trllc *llc; - struct srb_xmit xsrb; - __u8 dhb_page=0; - __u8 llc_ssap; - + int i,dhb_len=0x4000,src_len,src_offset; + struct trllc *llc; + struct srb_xmit xsrb; + __u8 dhb_page = 0; + __u8 llc_ssap; + SET_PAGE(ti->asb_page); - if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF) - DPRINTK("ASB not free !!!\n"); + if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code)) != 0xFF) + DPRINTK("ASB not free !!!\n"); /* in providing the transmit interrupts, is telling us it is ready for data and providing a shared memory address for us to stuff with data. Here we compute the - effective address where we will place data.*/ - SET_PAGE(ti->arb_page); - dhb=ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address))); - if (ti->page_mask) { - dhb_page=(dhb >> 8) & ti->page_mask; - dhb &= ~(ti->page_mask << 8); - } - dhb+=ti->sram; - + effective address where we will place data. */ + SET_PAGE(ti->arb_page); + dhb=dhb_base=ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address))); + if (ti->page_mask) { + dhb_page = (dhb_base >> 8) & ti->page_mask; + dhb=dhb_base & ~(ti->page_mask << 8); + } + dhb += ti->sram_virt; + /* Figure out the size of the 802.5 header */ - if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */ - hdr_len=sizeof(struct trh_hdr)-TR_MAXRIFLEN; - else - hdr_len=((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK)>>8) - +sizeof(struct trh_hdr)-TR_MAXRIFLEN; - - llc = (struct trllc *)(ti->current_skb->data + hdr_len); - - llc_ssap=llc->ssap; - SET_PAGE(ti->srb_page); - memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb)); - SET_PAGE(ti->asb_page); - xmit_command=xsrb.command; + if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */ + hdr_len = sizeof(struct trh_hdr) - TR_MAXRIFLEN; + else + hdr_len = ((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK) >> 8) + + sizeof(struct trh_hdr) - TR_MAXRIFLEN; + + llc = (struct trllc *) (ti->current_skb->data + hdr_len); + + llc_ssap = llc->ssap; + SET_PAGE(ti->srb_page); + memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb)); + SET_PAGE(ti->asb_page); + xmit_command = xsrb.command; writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command)); - writew(xsrb.station_id, - ti->asb + offsetof(struct asb_xmit_resp, station_id)); + writew(xsrb.station_id, ti->asb + offsetof(struct asb_xmit_resp, station_id)); writeb(llc_ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value)); - writeb(xsrb.cmd_corr, - ti->asb + offsetof(struct asb_xmit_resp, cmd_corr)); + writeb(xsrb.cmd_corr, ti->asb + offsetof(struct asb_xmit_resp, cmd_corr)); writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code)); - if ((xmit_command==XMIT_XID_CMD) || (xmit_command==XMIT_TEST_CMD)) { + if ((xmit_command == XMIT_XID_CMD) || (xmit_command == XMIT_TEST_CMD)) { - writew(htons(0x11), - ti->asb + offsetof(struct asb_xmit_resp, frame_length)); + writew(htons(0x11), ti->asb + offsetof(struct asb_xmit_resp, frame_length)); writeb(0x0e, ti->asb + offsetof(struct asb_xmit_resp, hdr_length)); SET_PAGE(dhb_page); writeb(AC, dhb); - writeb(LLC_FRAME, dhb+1); + writeb(LLC_FRAME, dhb + 1); - for (i=0; immio + ACA_OFFSET + ACA_SET + ISRA_ODD); return; @@ -1622,80 +1486,102 @@ * buffer identified in the command data received with the interrupt. */ writeb(hdr_len, ti->asb + offsetof(struct asb_xmit_resp, hdr_length)); - writew(htons(ti->current_skb->len), - ti->asb + offsetof(struct asb_xmit_resp, frame_length)); + writew(htons(ti->current_skb->len), ti->asb + offsetof(struct asb_xmit_resp, frame_length)); + + src_len=ti->current_skb->len; + src_offset=0; + dhb=dhb_base; + while(1) { + if (ti->page_mask) { + dhb_page=(dhb >> 8) & ti->page_mask; + dhb=dhb & ~(ti->page_mask << 8); + dhb_len=0x4000-dhb; /* remaining size of this page */ + } + dhb+=ti->sram_virt; + SET_PAGE(dhb_page); + if (src_len > dhb_len) { + memcpy_toio(dhb, &ti->current_skb->data[src_offset], dhb_len); + src_len -= dhb_len; + src_offset += dhb_len; + dhb_base+=dhb_len; + dhb=dhb_base; + } else { + memcpy_toio(dhb, &ti->current_skb->data[src_offset], src_len); + break; + } + } - memcpy_toio(dhb, ti->current_skb->data, ti->current_skb->len); writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - ti->tr_stats.tx_bytes+=ti->current_skb->len; - dev->tbusy=0; + ti->tr_stats.tx_bytes += ti->current_skb->len; + dev->tbusy = 0; dev_kfree_skb(ti->current_skb); - ti->current_skb=NULL; + ti->current_skb = NULL; mark_bh(NET_BH); - if (ti->readlog_pending) ibmtr_readlog(dev); -} + if (ti->readlog_pending) + ibmtr_readlog(dev); +} /*tr_tx */ + +/*****************************************************************************/ static void tr_rx(struct device *dev) { - struct tok_info *ti=(struct tok_info *) dev->priv; + struct tok_info *ti = (struct tok_info *) dev->priv; __u32 rbuffer, rbufdata; - __u8 rbuffer_page=0; + __u8 rbuffer_page = 0; __u32 llc; unsigned char *data; unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length; + unsigned char dlc_hdr_len; struct sk_buff *skb; unsigned int skb_size = 0; - int IPv4_p = 0; + int IPv4_p = 0; unsigned int chksum = 0; struct iphdr *iph; struct arb_rec_req rarb; SET_PAGE(ti->arb_page); - memcpy_fromio(&rarb, ti->arb, sizeof(rarb)); - rbuffer=ntohs(rarb.rec_buf_addr)+2; + memcpy_fromio(&rarb, ti->arb, sizeof(rarb)); + rbuffer = ntohs(rarb.rec_buf_addr) + 2; if (ti->page_mask) { - rbuffer_page=(rbuffer >> 8) & ti->page_mask; - rbuffer &= ~(ti->page_mask<<8); + rbuffer_page = (rbuffer >> 8) & ti->page_mask; + rbuffer &= ~(ti->page_mask << 8); } - rbuffer += ti->sram; - + rbuffer += ti->sram_virt; + SET_PAGE(ti->asb_page); - - if(readb(ti->asb + offsetof(struct asb_rec, ret_code))!=0xFF) - DPRINTK("ASB not free !!!\n"); - - writeb(REC_DATA, - ti->asb + offsetof(struct asb_rec, command)); - writew(rarb.station_id, - ti->asb + offsetof(struct asb_rec, station_id)); - writew(rarb.rec_buf_addr, - ti->asb + offsetof(struct asb_rec, rec_buf_addr)); - lan_hdr_len=rarb.lan_hdr_len; + if (readb(ti->asb + offsetof(struct asb_rec, ret_code)) != 0xFF) + DPRINTK("ASB not free !!!\n"); + + writeb(REC_DATA, ti->asb + offsetof(struct asb_rec, command)); + writew(rarb.station_id, ti->asb + offsetof(struct asb_rec, station_id)); + writew(rarb.rec_buf_addr, ti->asb + offsetof(struct asb_rec, rec_buf_addr)); + + lan_hdr_len = rarb.lan_hdr_len; + if (lan_hdr_len > sizeof(struct trh_hdr)) { + DPRINTK("Linux cannot handle greater than 18 bytes RIF\n"); + return; + } /*BMS I added this above just to be very safe */ + dlc_hdr_len = readb(ti->arb + offsetof(struct arb_rec_req, dlc_hdr_len)); hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr); - + SET_PAGE(rbuffer_page); - llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len); + llc = (rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len); #if TR_VERBOSE - DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n", - (unsigned int)offsetof(struct rec_buf,data), (unsigned int)lan_hdr_len); - DPRINTK("llc: %08X rec_buf_addr: %04X ti->sram: %lx\n", llc, - ntohs(rarb.rec_buf_addr), - (long)ti->sram); + DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n", (unsigned int) offsetof(struct rec_buf, data), (unsigned int) lan_hdr_len); + DPRINTK("llc: %08X rec_buf_addr: %04X dev->mem_start: %p\n", llc, ntohs(rarb.rec_buf_addr), dev->mem_start); DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, " "ethertype: %04X\n", - (int)readb(llc + offsetof(struct trllc, dsap)), - (int)readb(llc + offsetof(struct trllc, ssap)), - (int)readb(llc + offsetof(struct trllc, llc)), - (int)readb(llc + offsetof(struct trllc, protid)), - (int)readb(llc + offsetof(struct trllc, protid)+1), - (int)readb(llc + offsetof(struct trllc, protid)+2), - (int)readw(llc + offsetof(struct trllc, ethertype))); + (int) readb(llc + offsetof(struct trllc, dsap)), + (int) readb(llc + offsetof(struct trllc, ssap)), + (int) readb(llc + offsetof(struct trllc, llc)), + (int) readb(llc + offsetof(struct trllc, protid)), + (int) readb(llc + offsetof(struct trllc, protid) + 1), (int) readb(llc + offsetof(struct trllc, protid) + 2), (int) readw(llc + offsetof(struct trllc, ethertype))); #endif - if (readb(llc + offsetof(struct trllc, llc))!=UI_CMD) { - SET_PAGE(ti->asb_page); + if (readb(llc + offsetof(struct trllc, llc)) != UI_CMD) { + SET_PAGE(ti->asb_page); writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); ti->tr_stats.rx_dropped++; writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); @@ -1703,62 +1589,60 @@ } length = ntohs(rarb.frame_len); - if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) && - (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) && - (length>=hdr_len)) { - IPv4_p = 1; - } - + if ((readb(llc + offsetof(struct trllc, dsap)) == EXTENDED_SAP) && (readb(llc + offsetof(struct trllc, ssap)) == EXTENDED_SAP) && (length >= hdr_len)) { + IPv4_p = 1; + } #if TR_VERBOSE - if (!IPv4_p){ + if (!IPv4_p) { - __u32 trhhdr; + __u32 trhhdr; - trhhdr=(rbuffer+offsetof(struct rec_buf,data)); + trhhdr = (rbuffer + offsetof(struct rec_buf, data)); - DPRINTK("Probably non-IP frame received.\n"); - DPRINTK("ssap: %02X dsap: %02X saddr: %02X:%02X:%02X:%02X:%02X:%02X " - "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n", - (int)readb(llc + offsetof(struct trllc, ssap)), - (int)readb(llc + offsetof(struct trllc, dsap)), - (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)), - (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+1), - (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+2), - (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+3), - (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+4), - (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+5), - (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)), - (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+1), - (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+2), - (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+3), - (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+4), - (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+5)); - } -#endif - - skb_size = length; - - if (!(skb=dev_alloc_skb(skb_size))) { - DPRINTK("out of memory. frame dropped.\n"); - ti->tr_stats.rx_dropped++; - writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); - writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - return; - } - - skb_put(skb, length); - skb_reserve(skb, sizeof(struct trh_hdr)-lan_hdr_len+sizeof(struct trllc)); - skb->dev=dev; - data=skb->data; - rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))); - rbufdata = rbuffer + offsetof(struct rec_buf,data); + DPRINTK("Probably non-IP frame received.\n"); + DPRINTK("ssap: %02X dsap: %02X saddr: %02X:%02X:%02X:%02X:%02X:%02X " + "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n", + (int) readb(llc + offsetof(struct trllc, ssap)), + (int) readb(llc + offsetof(struct trllc, dsap)), + (int) readb(trhhdr + offsetof(struct trh_hdr, saddr)), + (int) readb(trhhdr + offsetof(struct trh_hdr, saddr) + 1), + (int) readb(trhhdr + offsetof(struct trh_hdr, saddr) + 2), + (int) readb(trhhdr + offsetof(struct trh_hdr, saddr) + 3), + (int) readb(trhhdr + offsetof(struct trh_hdr, saddr) + 4), + (int) readb(trhhdr + offsetof(struct trh_hdr, saddr) + 5), + (int) readb(trhhdr + offsetof(struct trh_hdr, daddr)), + (int) readb(trhhdr + offsetof(struct trh_hdr, daddr) + 1), + (int) readb(trhhdr + offsetof(struct trh_hdr, daddr) + 2), + (int) readb(trhhdr + offsetof(struct trh_hdr, daddr) + 3), + (int) readb(trhhdr + offsetof(struct trh_hdr, daddr) + 4), (int) readb(trhhdr + offsetof(struct trh_hdr, daddr) + 5)); + } +#endif + + /*BMS handle the case she comes in with few hops but leaves with many */ + skb_size=length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc); + + if (!(skb = dev_alloc_skb(skb_size))) { + DPRINTK("out of memory. frame dropped.\n"); + ti->tr_stats.rx_dropped++; + SET_PAGE(ti->asb_page); + writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); + writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + return; + } + /*BMS again, if she comes in with few but leaves with many */ + skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len); + skb_put(skb, length); + skb->dev = dev; + data = skb->data; + rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))); + rbufdata = rbuffer + offsetof(struct rec_buf, data); if (IPv4_p) { - /* Copy the headers without checksumming */ + /* Copy the headers without checksumming */ memcpy_fromio(data, rbufdata, hdr_len); /* Watch for padded packets and bogons */ - iph=(struct iphdr*)(data + lan_hdr_len + sizeof(struct trllc)); + iph = (struct iphdr *) (data + lan_hdr_len + sizeof(struct trllc)); ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr); length -= hdr_len; if ((ip_len <= length) && (ip_len > 7)) @@ -1766,14 +1650,14 @@ data += hdr_len; rbuffer_len -= hdr_len; rbufdata += hdr_len; - } + } /* Copy the payload... */ for (;;) { - if (IPv4_p) - chksum = csum_partial_copy(bus_to_virt(rbufdata), data, - length < rbuffer_len ? length : rbuffer_len, - chksum); + if (ibmtr_debug_trace && length < rbuffer_len) + DPRINTK("CURIOUS, length=%d < rbuffer_len=%d\n",length,rbuffer_len); + /*BMS*/ if (IPv4_p) + chksum = csum_partial_copy(bus_to_virt(rbufdata), data, length < rbuffer_len ? length : rbuffer_len, chksum); else memcpy_fromio(data, rbufdata, rbuffer_len); rbuffer = ntohs(readw(rbuffer)); @@ -1782,105 +1666,79 @@ length -= rbuffer_len; data += rbuffer_len; if (ti->page_mask) { - rbuffer_page=(rbuffer>>8) & ti->page_mask; - rbuffer &= ~(ti->page_mask << 8); + rbuffer_page = (rbuffer >> 8) & ti->page_mask; + rbuffer &= ~(ti->page_mask << 8); } - rbuffer += ti->sram; + rbuffer += ti->sram_virt; SET_PAGE(rbuffer_page); rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))); rbufdata = rbuffer + offsetof(struct rec_buf, data); } SET_PAGE(ti->asb_page); - writeb(0, ti->asb + offsetof(struct asb_rec, ret_code)); + writeb(0, ti->asb + offsetof(struct asb_rec, ret_code)); - writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); ti->tr_stats.rx_bytes += skb->len; - ti->tr_stats.rx_packets++; + ti->tr_stats.rx_packets++; - skb->protocol = tr_type_trans(skb,dev); - if (IPv4_p){ - skb->csum = chksum; + skb->protocol = tr_type_trans(skb, dev); + if (IPv4_p) { + skb->csum = chksum; skb->ip_summed = 1; } netif_rx(skb); -} +} /*tr_rx */ -static int tok_send_packet(struct sk_buff *skb, struct device *dev) -{ - struct tok_info *ti; - ti=(struct tok_info *) dev->priv; - - if (dev->tbusy) { - int ticks_waited; +/*****************************************************************************/ - ticks_waited=jiffies - dev->trans_start; - if (ticks_waitedtrans_start+=5; /* we fake the transmission start time... */ - return 1; - } - - if (test_and_set_bit(0,(void *)&dev->tbusy)!=0) - DPRINTK("Transmitter access conflict\n"); - else { - int flags; - - /* lock against other CPUs */ - spin_lock_irqsave(&(ti->lock), flags); - - /* Save skb; we'll need it when the adapter asks for the data */ - ti->current_skb=skb; - SET_PAGE(ti->srb_page); - writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command)); - writew(ti->exsap_station_id, ti->srb - +offsetof(struct srb_xmit, station_id)); - writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD)); - spin_unlock_irqrestore(&(ti->lock), flags); - - dev->trans_start=jiffies; - } - - return 0; -} - -void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev) { - tmr->expires = jiffies + TR_RETRY_INTERVAL; - tmr->data = (unsigned long) dev; +void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev) +{ + /*debugprintk("IBMTR_RESET_TIMER: adding an object\n"); */ + tmr->expires = jiffies + TR_RETRY_INTERVAL; + tmr->data = (unsigned long) dev; tmr->function = tok_open_adapter; init_timer(tmr); add_timer(tmr); } -void ibmtr_readlog(struct device *dev) { - struct tok_info *ti; - ti=(struct tok_info *) dev->priv; - - ti->readlog_pending = 0; - SET_PAGE(ti->srb_page); - writeb(DIR_READ_LOG, ti->srb); - writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - dev->tbusy=1; /* really srb busy... */ +/*****************************************************************************/ + +void ibmtr_readlog(struct device *dev) +{ + struct tok_info *ti; + ti = (struct tok_info *) dev->priv; + + ti->readlog_pending = 0; + SET_PAGE(ti->srb_page); + writeb(DIR_READ_LOG, ti->srb); + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + dev->tbusy = 1; /* really srb busy... */ } +/*****************************************************************************/ + /* tok_get_stats(): Basically a scaffold routine which will return the address of the tr_statistics structure associated with this device -- the tr.... structure is an ethnet look-alike so at least for this iteration may suffice. */ -static struct net_device_stats * tok_get_stats(struct device *dev) { +static struct net_device_stats *tok_get_stats(struct device *dev) +{ struct tok_info *toki; - toki=(struct tok_info *) dev->priv; + toki = (struct tok_info *) dev->priv; return (struct net_device_stats *) &toki->tr_stats; } -int ibmtr_change_mtu(struct device *dev, int mtu) { +/*****************************************************************************/ + +int ibmtr_change_mtu(struct device *dev, int mtu) +{ struct tok_info *ti = (struct tok_info *) dev->priv; - + if (ti->ring_speed == 16 && mtu > ti->maxmtu16) return -EINVAL; if (ti->ring_speed == 4 && mtu > ti->maxmtu4) @@ -1889,13 +1747,14 @@ return 0; } +/*****************************************************************************/ #ifdef MODULE /* 3COM 3C619C supports 8 interrupts, 32 I/O ports */ -static struct device* dev_ibmtr[IBMTR_MAX_ADAPTERS]; -static int io[IBMTR_MAX_ADAPTERS] = {0xa20,0xa24}; -static int irq[IBMTR_MAX_ADAPTERS] = {0,0}; -static int mem[IBMTR_MAX_ADAPTERS] = {0,0}; +static struct device *dev_ibmtr[IBMTR_MAX_ADAPTERS]; +static int io[IBMTR_MAX_ADAPTERS] = { 0xa20, 0xa24 }; +static int irq[IBMTR_MAX_ADAPTERS] = { 0, 0 }; +static int mem[IBMTR_MAX_ADAPTERS] = { 0, 0 }; MODULE_PARM(io, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i"); @@ -1903,46 +1762,46 @@ int init_module(void) { - int i; - for (i = 0; io[i] && (ibase_addr = io[i]; - dev_ibmtr[i]->irq = irq[i]; + dev_ibmtr[i]->base_addr = io[i]; + dev_ibmtr[i]->irq = irq[i]; dev_ibmtr[i]->mem_start = mem[i]; - dev_ibmtr[i]->init = &ibmtr_probe; + dev_ibmtr[i]->init = &ibmtr_probe; - if (register_trdev(dev_ibmtr[i]) != 0) { + if (register_trdev(dev_ibmtr[i]) != 0) { kfree_s(dev_ibmtr[i], sizeof(struct device)); dev_ibmtr[i] = NULL; - if (i == 0) { - printk("ibmtr: register_trdev() returned non-zero.\n"); - return -EIO; + if (i == 0) { + printk("ibmtr: register_trdev() returned non-zero.\n"); + return -EIO; } else { - return 0; + return 0; } - } + } } return 0; -} +} /*init_module */ void cleanup_module(void) { - int i; + int i; - for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) - if (dev_ibmtr[i]) { - unregister_trdev(dev_ibmtr[i]); - free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); - release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); - kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info)); - kfree_s(dev_ibmtr[i], sizeof(struct device)); - dev_ibmtr[i] = NULL; - } + for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) + if (dev_ibmtr[i]) { + unregister_trdev(dev_ibmtr[i]); + free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); + release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); + kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info)); + kfree_s(dev_ibmtr[i], sizeof(struct device)); + dev_ibmtr[i] = NULL; + } } -#endif /* MODULE */ +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ibmtr.h linux/drivers/net/ibmtr.h --- v2.2.17/drivers/net/ibmtr.h Sun Jun 11 21:44:14 2000 +++ linux/drivers/net/ibmtr.h Sat Oct 28 11:27:54 2000 @@ -3,11 +3,12 @@ /* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */ -#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */ +#define TR_RETRY_INTERVAL (/*5BMS*/30*HZ) /* seconds * ticks/second */ #define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */ #define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ #define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ -#define TR_RETRIES 6 /* number of open retries */ +/*BMS I changed from 6 retries to 30 days of retries. Forever would be OK. */ +#define TR_RETRIES (30*24*60*60* HZ/TR_RETRY_INTERVAL) #define TR_ISA 1 #define TR_MCA 2 @@ -32,8 +33,20 @@ #define AIP16MBDHB 0X1FAC #define AIPFID 0X1FBA +#define ADAPT_PRIVATE 1416 /* Adapter Private Vars */ +#define ARBLENGTH 28 /* Adapter Request Block */ +#define SSBLENGTH 20 /* System Status Block */ +#define SAPLENGTH 64 /* Service Access Point */ +#define STALENGTH 144 /* Station Control Block */ +#define SRBLENGTH 28 /* System Request Block */ +#define ASBLENGTH 12 /* Adapter Status Block */ +#define BLOCKSZ 512 + /* Note, 0xA20 == 0x220 since motherboard decodes 10 bits. I left everything - the way my documentation had it, ie: 0x0A20. */ + the way my documentation had it, ie: 0x0A20. + * BMS motherboard and TR decode 16 bits. Some sound cards only decode 10 bits, + causing a potential conflict with a sound card addressed at 0x220. +*/ #define ADAPTINTCNTRL 0x02f0 /* Adapter interrupt control */ #define ADAPTRESET 0x1 /* Control Adapter reset (add to base) */ #define ADAPTRESETREL 0x2 /* Release Adapter from reset ( """) */ @@ -168,7 +181,7 @@ #define SET_PAGE(x) #endif -typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state; +typedef enum { CLOSED, SUCCESS, FAILURE, AUTOREOPEN } open_state; /* do_tok_int possible values */ #define FIRST_INT 1 @@ -199,8 +212,8 @@ /* Additions by Peter De Schrijver */ unsigned char page_mask; /* mask to select RAM page to Map*/ unsigned char mapped_ram_size; /* size of RAM page */ - __u32 sram; /* Shared memory base address */ - __u32 init_srb; /* Initial System Request Block address */ + __u32 sram_virt; /* Shared memory base address */ + __u32 init_srb; /* Initial System Request Block address */ __u32 srb; /* System Request Block address */ __u32 ssb; /* System Status Block address */ __u32 arb; /* Adapter Request Block address */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ipddp.c linux/drivers/net/ipddp.c --- v2.2.17/drivers/net/ipddp.c Fri Apr 21 12:46:17 2000 +++ linux/drivers/net/ipddp.c Thu Aug 31 15:19:44 2000 @@ -242,7 +242,10 @@ rt->next = NULL; rt->dev = atrtr_get_dev(&rt->at); if(rt->dev == NULL) + { + kfree(rt); return (-ENETUNREACH); + } test = ipddp_find_route(rt); if(test != NULL) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.2.17/drivers/net/irda/toshoboe.c Sun Jun 11 21:44:14 2000 +++ linux/drivers/net/irda/toshoboe.c Sat Sep 30 18:10:07 2000 @@ -902,7 +902,7 @@ /*FIXME: can't sleep here wait one second */ while ((i--) && (self->txpending)) - udelay (100000); + mdelay (100); toshoboe_stopchip (self); toshoboe_disablebm (self); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/lmc/lmc_main.c linux/drivers/net/lmc/lmc_main.c --- v2.2.17/drivers/net/lmc/lmc_main.c Sat Sep 9 18:42:38 2000 +++ linux/drivers/net/lmc/lmc_main.c Sat Nov 18 18:01:24 2000 @@ -640,7 +640,7 @@ /* Make sure the tx jabber and rx watchdog are off, - * and the transmit and recieve processes are running. + * and the transmit and receive processes are running. */ LMC_CSR_WRITE (sc, csr_15, cpu_to_le32(0x00000011)); @@ -2139,7 +2139,7 @@ lmc_trace(sc->lmc_device, "lmc_softreset in"); - /* Initialize the recieve rings and buffers. */ + /* Initialize the receive rings and buffers. */ sc->lmc_txfull = 0; sc->lmc_next_rx = 0; sc->lmc_next_tx = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.2.17/drivers/net/ltpc.c Fri Apr 21 12:46:18 2000 +++ linux/drivers/net/ltpc.c Sat Sep 30 15:55:35 2000 @@ -353,13 +353,12 @@ /* returns true if it stayed c */ /* this uses base+6, but it's ok */ int i; - int timeout; /* twenty second or so total */ - for(i=0;i<20000;i++) { + for(i=0;i<200000;i++) { if ( c != inb_p(dev->base_addr+6) ) return 0; - for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ; + udelay(100); } return 1; /* timed out */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/mac8390.c linux/drivers/net/mac8390.c --- v2.2.17/drivers/net/mac8390.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/mac8390.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,612 @@ +/* mac8390.c: New driver for 8390-based Nubus (or Nubus-alike) + Ethernet cards on Linux */ +/* Based on the former daynaport.c driver, by Alan Cox. Some code + taken from or inspired by skeleton.c by Donald Becker, acenic.c by + Jes Sorensen, and ne2k-pci.c by Donald Becker and Paul Gortmaker. + + This software may be used and distributed according to the terms of + the GNU Public License, incorporated herein by reference. */ + +/* 2000-02-28: support added for Dayna and Kinetics cards by + A.G.deWijn@phys.uu.nl */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "8390.h" + +#if (LINUX_VERSION_CODE < 0x02030e) +#define net_device device +#endif + +#define WD_START_PG 0x00 /* First page of TX buffer */ +#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */ +#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ +#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */ + +/* Unfortunately it seems we have to hardcode these for the moment */ +/* Shouldn't the card know about this? Does anyone know where to read it off the card? Do we trust the data provided by the card? */ +#define APPLE_8390_BASE 0xE0000 + +#define DAYNA_8390_BASE 0x80000 +#define DAYNA_8390_MEM 0x00000 + +#define KINETICS_8390_BASE 0x80000 +#define KINETICS_8390_MEM 0x00000 + +#define CABLETRON_8390_BASE 0x90000 + +enum mac8390_type { + MAC8390_NONE = -1, + MAC8390_APPLE, + MAC8390_ASANTE, + MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */ + MAC8390_CABLETRON, + MAC8390_DAYNA, + MAC8390_INTERLAN, + MAC8390_KINETICS, + MAC8390_FOCUS, + MAC8390_SONICSYS +}; + +static const char * cardname[] = { + "apple", + "asante", + "farallon", + "cabletron", + "dayna", + "interlan", + "kinetics", + "focus", + "sonic systems" +}; + +static int word16[] = { + 1, /* apple */ + 1, /* asante */ + 1, /* farallon */ + 1, /* cabletron */ + 0, /* dayna */ + 1, /* interlan */ + 0, /* kinetics */ + 1, /* focus (??) */ + 1 /* sonic systems (??) */ +}; + +/* on which cards do we use NuBus resources? */ +static int useresources[] = { + 1, /* apple */ + 1, /* asante */ + 1, /* farallon */ + 0, /* cabletron */ + 0, /* dayna */ + 0, /* interlan */ + 0, /* kinetics */ + 0, /* focus (??) */ + 0 /* sonic systems (??) */ +}; + +static const char __initdata * version = + "mac8390.c: v0.2 2000-03-25 David Huggins-Daines and others\n"; + +extern int mac8390_probe(struct net_device * dev); +extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); +extern int mac8390_memsize(unsigned long membase); +extern int mac8390_promaddr(struct net_device * dev); +extern int mac8390_memtest(struct net_device * dev); +extern int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, + enum mac8390_type type); + +static int mac8390_open(struct net_device * dev); +static int mac8390_close(struct net_device * dev); +static void mac8390_no_reset(struct device *dev); + +/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/ +static void sane_get_8390_hdr(struct device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); +static void sane_block_input(struct net_device * dev, int count, + struct sk_buff * skb, int ring_offset); +static void sane_block_output(struct net_device * dev, int count, + const unsigned char * buf, const int start_page); + +/* dayna_memcpy to and from card */ +static void dayna_memcpy_fromcard(struct device *dev, void *to, + int from, int count); +static void dayna_memcpy_tocard(struct device *dev, int to, + const void *from, int count); + +/* Dayna - Dayna/Kinetics use this */ +static void dayna_get_8390_hdr(struct device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); +static void dayna_block_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void dayna_block_output(struct device *dev, int count, + const unsigned char *buf, int start_page); + +enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) +{ + if (dev->dr_sw == NUBUS_DRSW_ASANTE) + return MAC8390_ASANTE; + if (dev->dr_sw == NUBUS_DRSW_FARALLON) + return MAC8390_FARALLON; + if (dev->dr_sw == NUBUS_DRSW_KINETICS) + return MAC8390_KINETICS; + if (dev->dr_sw == NUBUS_DRSW_DAYNA) + return MAC8390_DAYNA; + return MAC8390_NONE; +} + +int __init mac8390_memsize(unsigned long membase) +{ + unsigned long flags; + int i, j; + + save_flags(flags); cli(); + /* Check up to 32K in 4K increments */ + for (i = 0; i < 8; i++) { + volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000)); + + /* Unwriteable - we have a fully decoded card and the + RAM end located */ + if (hwreg_present(m) == 0) + break; + + /* write a distinctive byte */ + *m = 0xA5A0 | i; + /* check that we read back what we wrote */ + if (*m != (0xA5A0 | i)) + break; + + /* check for partial decode and wrap */ + for (j = 0; j < i; j++) { + volatile unsigned short *p = (unsigned short *) (membase + (j * 0x1000)); + if (*p != (0xA5A0 | j)) + break; + } + } + restore_flags(flags); + /* in any case, we stopped once we tried one block too many, + or once we reached 32K */ + return i * 0x1000; +} + +int __init mac8390_promaddr(struct net_device * dev) +{ + /* XXX: lame, figure out how to do this eventually */ + return -1; +} + +static int probed __initdata = 0; + +int __init mac8390_probe(struct net_device * dev) +{ + int boards_found = 0; + int version_disp = 0; + struct nubus_dev * ndev = NULL; + + struct nubus_dir dir; + struct nubus_dirent ent; + int offset; + + enum mac8390_type cardtype; + + if (probed) + return -ENODEV; + probed++; + + /* probably should check for Nubus instead */ + + if (!MACH_IS_MAC) + return -ENODEV; + + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { + + dev = NULL; + + if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + continue; + + dev = init_etherdev(dev, 0); + if (dev == NULL) { + printk(KERN_ERR "Unable to allocate etherdev" + "structure!\n"); + return -ENOMEM; + } + + if (version_disp == 0) { + version_disp = 1; + printk(version); + } + + dev->irq = SLOT2IRQ(ndev->board->slot); + /* This is getting to be a habit */ + dev->base_addr = ndev->board->slot_addr | ((ndev->board->slot&0xf) << 20); + + /* Get some Nubus info - we will trust the card's idea + of where its memory and registers are. */ + + if (nubus_get_func_dir(ndev, &dir) == -1) { + printk(KERN_ERR "%s: Unable to get Nubus functional" + " directory for slot %X!\n", + dev->name, ndev->board->slot); + continue; + } + if (useresources[cardtype] == 1) { + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) { + printk(KERN_ERR "%s: Memory offset resource" + " for slot %X not found!\n", + dev->name, ndev->board->slot); + continue; + } + nubus_get_rsrc_mem(&offset, &ent, 4); + dev->mem_start = dev->base_addr + offset; + /* yes, this is how the Apple driver does it */ + dev->base_addr = dev->mem_start + 0x10000; + nubus_rewinddir(&dir); + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) { + printk(KERN_INFO "%s: Memory length resource" + " for slot %X not found" + ", probing\n", + dev->name, ndev->board->slot); + offset = mac8390_memsize(dev->mem_start); + } else { + nubus_get_rsrc_mem(&offset, &ent, 4); + } + dev->mem_end = dev->mem_start + offset; + } else { + switch (cardtype) { + case MAC8390_KINETICS: + case MAC8390_DAYNA: /* it's the same */ + dev->base_addr = + (int)(ndev->board->slot_addr + + DAYNA_8390_BASE); + dev->mem_start = + (int)(ndev->board->slot_addr + + DAYNA_8390_MEM); + dev->mem_end = + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + default: + printk(KERN_ERR "Card type %s is" + " unsupported, sorry\n", + cardname[cardtype]); + return -ENODEV; + } + } + + /* Get the MAC address */ + nubus_rewinddir(&dir); + if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) { + printk(KERN_INFO "%s: Ethernet address not in resources" + ", probing\n", + dev->name); + if ((mac8390_promaddr(dev)) == -1) { + printk(KERN_ERR "%s: Couldn't get MAC" + " address!\n", + dev->name); + continue; + } + } else { + nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); + } + + /* Do the nasty 8390 stuff */ + if (mac8390_initdev(dev, ndev, cardtype)) + continue; + boards_found++; + } + + /* We're outta here */ + if (boards_found > 0) + return 0; + else + return -ENODEV; +} + +#ifdef MODULE +#if LINUX_VERSION_CODE > 0x20118 +MODULE_AUTHOR("David Huggins-Daines and others"); +MODULE_DESCRIPTION("Macintosh NS8390-based Nubus Ethernet driver"); +#endif + +int init_module(void) +{ + if (mac8390_probe(NULL)) { + printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n"); + return -ENODEV; + } + lock_8390_module(); + return 0; +} + +void cleanup_module(void) +{ + /* FIXME: should probably keep track of net_device structs + somewhere and unregister them here? */ + unlock_8390_module(); +} + +#endif /* MODULE */ + +int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, + enum mac8390_type type) +{ + static u32 fwrd4_offsets[16]={ + 0, 4, 8, 12, + 16, 20, 24, 28, + 32, 36, 40, 44, + 48, 52, 56, 60 + }; + static u32 back4_offsets[16]={ + 60, 56, 52, 48, + 44, 40, 36, 32, + 28, 24, 20, 16, + 12, 8, 4, 0 + }; +/* Cabletron cards use this, but they aren't supported in mac8390.c */ +#if 0 + static u32 fwrd2_offsets[16]={ + 0, 2, 4, 6, + 8, 10, 12, 14, + 16, 18, 20, 22, + 24, 26, 28, 30 + }; +#endif /* 0 */ + + /* 8390 specific init for dev - allocates dev->priv */ + if (ethdev_init(dev)) { + printk(KERN_ERR "%s: Unable to allocate memory for dev->priv!\n", dev->name); + return -ENOMEM; + } + + /* Now fill in our stuff */ + dev->open = &mac8390_open; + dev->stop = &mac8390_close; + + /* GAR, ei_status is actually a macro even though it looks global */ + ei_status.name = cardname[type]; + ei_status.word16 = word16[type]; + + /* Cabletron's TX/RX buffers are backwards */ + if (type == MAC8390_CABLETRON) { + ei_status.tx_start_page = CABLETRON_TX_START_PG; + ei_status.rx_start_page = CABLETRON_RX_START_PG; + ei_status.stop_page = CABLETRON_RX_STOP_PG; + dev->rmem_start = dev->mem_start; + dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; + } else { + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->rmem_end = dev->mem_end; + } + + /* Fill in model-specific information and functions */ + switch(type) { + case MAC8390_APPLE: + case MAC8390_ASANTE: + case MAC8390_FARALLON: + /* 32 bit card, register map is reversed */ + /* sane */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + break; + case MAC8390_DAYNA: + case MAC8390_KINETICS: + /* 16 bit memory */ + /* dayna and similar */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &dayna_block_input; + ei_status.block_output = &dayna_block_output; + ei_status.get_8390_hdr = &dayna_get_8390_hdr; + ei_status.reg_offset = fwrd4_offsets; + break; + default: + printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]); + return -ENODEV; + } + + NS8390_init(dev, 0); + + /* Good, done, now spit out some messages */ + printk(KERN_INFO "%s: %s in slot %X (type %s)\n", + dev->name, ndev->board->name, ndev->board->slot, cardname[type]); + printk(KERN_INFO "MAC "); + { + int i; + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + } + printk(" IRQ %d, shared memory at %#lx-%#lx.\n", + dev->irq, dev->mem_start, dev->mem_end-1); + return 0; +} + +static int mac8390_open(struct device *dev) +{ + ei_open(dev); + if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) { + printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return -EAGAIN; + } + MOD_INC_USE_COUNT; + return 0; +} + +static int mac8390_close(struct device *dev) +{ + free_irq(dev->irq, dev); + ei_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +static void mac8390_no_reset(struct device *dev) +{ + ei_status.txing = 0; + if (ei_debug > 1) + printk("reset not supported\n"); + return; +} + +/* dayna_memcpy_fromio/dayna_memcpy_toio */ +/* directly from daynaport.c by Alan Cox */ +static void dayna_memcpy_fromcard(struct device *dev, void *to, int from, int count) +{ + volatile unsigned short *ptr; + unsigned short *target=to; + from<<=1; /* word, skip overhead */ + ptr=(unsigned short *)(dev->mem_start+from); + /* Leading byte? */ + if (from&2) { + *((char *)target)++ = *(((char *)ptr++)-1); + count--; + } + while(count>=2) + { + *target++=*ptr++; /* Copy and */ + ptr++; /* skip cruft */ + count-=2; + } + /* Trailing byte? */ + if(count) + { + /* Big endian */ + unsigned short v=*ptr; + *((char *)target)=v>>8; + } +} + +static void dayna_memcpy_tocard(struct device *dev, int to, const void *from, int count) +{ + volatile unsigned short *ptr; + const unsigned short *src=from; + to<<=1; /* word, skip overhead */ + ptr=(unsigned short *)(dev->mem_start+to); + /* Leading byte? */ + if (to&2) { /* avoid a byte write (stomps on other data) */ + ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++; + ptr++; + count--; + } + while(count>=2) + { + *ptr++=*src++; /* Copy and */ + ptr++; /* skip cruft */ + count-=2; + } + /* Trailing byte? */ + if(count) + { + /* Big endian */ + unsigned short v=*src; + /* card doesn't like byte writes */ + *ptr=(*ptr&0x00FF)|(v&0xFF00); + } +} + +/* sane block input/output */ +static void sane_get_8390_hdr(struct device *dev, + struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + memcpy_fromio((void *)hdr, (char *)dev->mem_start + hdr_start, 4); + /* Fix endianness */ + hdr->count = swab16(hdr->count); +} + +static void sane_block_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base + dev->mem_start; + + if (xfer_start + count > dev->rmem_end) { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count); + count -= semi_count; + memcpy_toio(skb->data + semi_count, (char *)dev->rmem_start, count); + } else { + memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count); + } +} + +static void sane_block_output(struct device *dev, int count, + const unsigned char *buf, int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + memcpy_toio((char *)dev->mem_start + shmem, buf, count); +} + +/* dayna block input/output */ +static void dayna_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + + dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4); + /* Fix endianness */ + hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); +} + +static void dayna_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base+dev->mem_start; + + /* Note the offset math is done in card memory space which is word + per long onto our space. */ + + if (xfer_start + count > dev->rmem_end) + { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count); + count -= semi_count; + dayna_memcpy_fromcard(dev, skb->data + semi_count, + dev->rmem_start - dev->mem_start, count); + } + else + { + dayna_memcpy_fromcard(dev, skb->data, xfer_base, count); + } +} + +static void dayna_block_output(struct device *dev, int count, const unsigned char *buf, + int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + dayna_memcpy_tocard(dev, shmem, buf, count); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/mac89x0.c linux/drivers/net/mac89x0.c --- v2.2.17/drivers/net/mac89x0.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/mac89x0.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,679 @@ +/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ +/* + Written 1996 by Russell Nelson, with reference to skeleton.c + written 1993-1994 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + The author may be reached at nelson@crynwr.com, Crynwr + Software, 11 Grant St., Potsdam, NY 13676 + + Changelog: + + Mike Cruse : mcruse@cti-ltd.com + : Changes for Linux 2.0 compatibility. + : Added dev_id parameter in net_interrupt(), + : request_irq() and free_irq(). Just NULL for now. + + Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros + : in net_open() and net_close() so kerneld would know + : that the module is in use and wouldn't eject the + : driver prematurely. + + Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c + : as an example. Disabled autoprobing in init_module(), + : not a good thing to do to other devices while Linux + : is running from all accounts. + + Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + David Huggins-Daines + + Split this off into mac89x0.c, and gutted it of all parts which are + not relevant to the existing CS8900 cards on the Macintosh + (i.e. basically the Daynaport CS and LC cards). To be precise: + + * Removed all the media-detection stuff, because these cards are + TP-only. + + * Lobotomized the ISA interrupt bogosity, because these cards use + a hardwired NuBus interrupt and a magic ISAIRQ value in the card. + + * Basically eliminated everything not relevant to getting the + cards minimally functioning on the Macintosh. + + I might add that these cards are badly designed even from the Mac + standpoint, in that Dayna, in their infinite wisdom, used NuBus slot + I/O space and NuBus interrupts for these cards, but neglected to + provide anything even remotely resembling a NuBus ROM. Therefore we + have to probe for them in a brain-damaged ISA-like fashion. +*/ + +static char *version = +"cs89x0.c:v1.02 11/26/96 Russell Nelson \n"; + +/* ======================= configure the driver here ======================= */ + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* ======================= end of configuration ======================= */ + + +/* Always include 'config.h' first in case the user wants to turn on + or override something. */ +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#define PRINTK(x) printk x + +/* + Sources: + + Crynwr packet driver epktisa. + + Crystal Semiconductor data sheets. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "cs89x0.h" + +static unsigned int net_debug = NET_DEBUG; + +/* Information that need to be kept for each board. */ +struct net_local { + struct net_device_stats stats; + int chip_type; /* one of: CS8900, CS8920, CS8920M */ + char chip_revision; /* revision letter of the chip ('A'...) */ + int send_cmd; /* the propercommand used to send a packet. */ + int rx_mode; + int curr_rx_cfg; + int send_underrun; /* keep track of how many underruns in a row we get */ + struct sk_buff *skb; +}; + +/* Index to functions, as function prototypes. */ + +extern int mac89x0_probe(struct device *dev); +extern void reset_chip(struct device *dev); +static int net_open(struct device *dev); +static int net_send_packet(struct sk_buff *skb, struct device *dev); +static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void set_multicast_list(struct device *dev); +static void net_rx(struct device *dev); +static int net_close(struct device *dev); +static struct net_device_stats *net_get_stats(struct device *dev); +static int set_mac_address(struct device *dev, void *addr); + + +/* Example routines you must write ;->. */ +#define tx_done(dev) 1 + +/* For reading/writing registers ISA-style */ +static int inline +readreg_io(struct device *dev, int portno) +{ + writew(swab16(portno), dev->base_addr + ADD_PORT); + return swab16(readw(dev->base_addr + DATA_PORT)); +} + +static void inline +writereg_io(struct device *dev, int portno, int value) +{ + writew(swab16(portno), dev->base_addr + ADD_PORT); + writew(swab16(value), dev->base_addr + DATA_PORT); +} + +/* These are for reading/writing registers in shared memory */ +static int inline +readreg(struct device *dev, int portno) +{ + return swab16(readw(dev->mem_start + portno)); +} + +static void inline +writereg(struct device *dev, int portno, int value) +{ + writew(swab16(value), dev->mem_start + portno); +} + +/* Probe for the CS8900 card in slot E. We won't bother looking + anywhere else until we have a really good reason to do so. */ +__initfunc(int mac89x0_probe(struct device *dev)) +{ + static int once_is_enough = 0; + struct net_local *lp; + static unsigned version_printed = 0; + int i, slot; + unsigned rev_type = 0; + unsigned long ioaddr; + unsigned short sig; + + if (once_is_enough) + return ENODEV; + once_is_enough = 1; + + /* We might have to parameterize this later */ + slot = 0xE; + /* Get out now if there's a real NuBus card in slot E */ + if (nubus_find_slot(slot, NULL) != NULL) + return ENODEV; + + /* The pseudo-ISA bits always live at offset 0x300 (gee, + wonder why...) */ + ioaddr = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE); + { + unsigned long flags; + int card_present; + + save_flags(flags); + cli(); + card_present = hwreg_present((void*) ioaddr+4) + && hwreg_present((void*) ioaddr + DATA_PORT); + restore_flags(flags); + + if (!card_present) + return ENODEV; + } + + writew(0, ioaddr + ADD_PORT); + sig = readw(ioaddr + DATA_PORT); + if (sig != swab16(CHIP_EISA_ID_SIG)) + return ENODEV; + + /* Initialize the device structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct net_local)); + } + lp = (struct net_local *)dev->priv; + + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + dev->mem_start = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE); + dev->mem_end = dev->mem_start + 0x1000; + + /* Turn on shared memory */ + writereg_io(dev, PP_BusCTL, MEMORY_ON); + + /* get the chip type */ + rev_type = readreg(dev, PRODUCT_ID_ADD); + lp->chip_type = rev_type &~ REVISON_BITS; + lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + /* Check the chip type and revision in order to set the correct send command + CS8920 revision C and CS8900 revision F can use the faster send. */ + lp->send_cmd = TX_AFTER_381; + if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') + lp->send_cmd = TX_NOW; + if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') + lp->send_cmd = TX_NOW; + + if (net_debug && version_printed++ == 0) + printk(version); + + printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx", + dev->name, + lp->chip_type==CS8900?'0':'2', + lp->chip_type==CS8920M?"M":"", + lp->chip_revision, + dev->base_addr); + + /* Try to read the MAC address */ + if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { + printk("\nmac89x0: No EEPROM, giving up now.\n"); + return ENODEV; + } else { + for (i = 0; i < ETH_ALEN; i += 2) { + /* Big-endian (why??!) */ + unsigned short s = readreg(dev, PP_IA + i); + dev->dev_addr[i] = s >> 8; + dev->dev_addr[i+1] = s & 0xff; + } + } + + dev->irq = SLOT2IRQ(slot); + printk(" IRQ %d ADDR ", dev->irq); + + /* print the ethernet address. */ + for (i = 0; i < ETH_ALEN; i++) + printk("%2.2x%s", dev->dev_addr[i], + ((i < ETH_ALEN-1) ? ":" : "")); + + dev->open = net_open; + dev->stop = net_close; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->set_mac_address = &set_mac_address; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + printk("\n"); + return 0; +} + +/* This is useful for something, but I don't know what yet. */ +__initfunc(void +reset_chip(struct device *dev)) +{ + int reset_start_time; + + writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); + + /* wait 30 ms */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(30*HZ/1000); + + /* Wait until the chip is reset */ + reset_start_time = jiffies; + while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) + ; +} + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine should set everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + */ +static int +net_open(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int i; + + /* Disable the interrupt for now */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ); + + /* Grab the interrupt */ + if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) + return -EAGAIN; + + /* Set up the IRQ - Apparently magic */ + if (lp->chip_type == CS8900) + writereg(dev, PP_CS8900_ISAINT, 0); + else + writereg(dev, PP_CS8920_ISAINT, 0); + + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + /* Turn on both receive and transmit operations */ + writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); + + /* Receive only error free packets addressed to this card */ + lp->rx_mode = 0; + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); + + lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; + + writereg(dev, PP_RxCFG, lp->curr_rx_cfg); + + writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | + TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + + writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | + TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); + + /* now that we've got our act together, enable everything */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + MOD_INC_USE_COUNT; + return 0; +} + +static int +net_send_packet(struct sk_buff *skb, struct device *dev) +{ + if (dev->tbusy) { + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict" : "network cable problem"); + /* Try to restart the adaptor. */ + dev->tbusy=0; + dev->trans_start = jiffies; + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + else { + struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + + if (net_debug > 3) + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + /* keep the upload from being interrupted, since we + ask the chip to start transmitting before the + whole packet has been completely uploaded. */ + save_flags(flags); + cli(); + + /* initiate a transmit sequence */ + writereg(dev, PP_TxCMD, lp->send_cmd); + writereg(dev, PP_TxLength, skb->len); + + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* Gasp! It hasn't. But that shouldn't happen since + we're waiting for TxOk, so return 1 and requeue this packet. */ + restore_flags(flags); + return 1; + } + + /* Write the contents of the packet */ + memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); + + restore_flags(flags); + dev->trans_start = jiffies; + } + dev_kfree_skb (skb); + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct device *dev = dev_id; + struct net_local *lp; + int ioaddr, status; + + if (dev == NULL) { + printk ("net_interrupt(): irq %d for unknown device.\n", irq); + return; + } + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + /* we MUST read all the events out of the ISQ, otherwise we'll never + get interrupted again. As a consequence, we can't have any limit + on the number of times we loop in the interrupt handler. The + hardware guarantees that eventually we'll run out of events. Of + course, if you're on a slow machine, and packets are arriving + faster than you can read them off, you're screwed. Hasta la + vista, baby! */ + while ((status = swab16(readw(dev->base_addr + ISQ_PORT)))) { + if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); + switch(status & ISQ_EVENT_MASK) { + case ISQ_RECEIVER_EVENT: + /* Got a packet(s). */ + net_rx(dev); + break; + case ISQ_TRANSMITTER_EVENT: + lp->stats.tx_packets++; + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + if ((status & TX_OK) == 0) lp->stats.tx_errors++; + if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; + if (status & TX_LATE_COL) lp->stats.tx_window_errors++; + if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + break; + case ISQ_BUFFER_EVENT: + if (status & READY_FOR_TX) { + /* we tried to transmit a packet earlier, + but inexplicably ran out of buffers. + That shouldn't happen since we only ever + load one packet. Shrug. Do the right + thing anyway. */ + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + if (status & TX_UNDERRUN) { + if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); + lp->send_underrun++; + if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; + else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; + } + break; + case ISQ_RX_MISS_EVENT: + lp->stats.rx_missed_errors += (status >>6); + break; + case ISQ_TX_COL_EVENT: + lp->stats.collisions += (status >>6); + break; + } + } + dev->interrupt = 0; + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +net_rx(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + int status, length; + + status = readreg(dev, PP_RxStatus); + if ((status & RX_OK) == 0) { + lp->stats.rx_errors++; + if (status & RX_RUNT) lp->stats.rx_length_errors++; + if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; + if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) + /* per str 172 */ + lp->stats.rx_crc_errors++; + if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + return; + } + + length = readreg(dev, PP_RxLength); + /* Malloc up new buffer. */ + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + return; + } + skb->len = length; + skb->dev = dev; + + memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length); + + if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + lp->stats.rx_bytes+=skb->len; + return; +} + +/* The inverse routine to net_open(). */ +static int +net_close(struct device *dev) +{ + + writereg(dev, PP_RxCFG, 0); + writereg(dev, PP_TxCFG, 0); + writereg(dev, PP_BufCFG, 0); + writereg(dev, PP_BusCTL, 0); + + dev->start = 0; + + free_irq(dev->irq, dev); + + /* Update the statistics here. */ + + MOD_DEC_USE_COUNT; + return 0; + +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct net_device_stats * +net_get_stats(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + cli(); + /* Update the statistics from the device registers. */ + lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); + lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); + sti(); + + return &lp->stats; +} + +static void set_multicast_list(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if(dev->flags&IFF_PROMISC) + { + lp->rx_mode = RX_ALL_ACCEPT; + } + else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) + { + /* The multicast-accept list is initialized to accept-all, and we + rely on higher-level filtering for now. */ + lp->rx_mode = RX_MULTCAST_ACCEPT; + } + else + lp->rx_mode = 0; + + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); + + /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ + writereg(dev, PP_RxCFG, lp->curr_rx_cfg | + (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); +} + + +static int set_mac_address(struct device *dev, void *addr) +{ + int i; + if (dev->start) + return -EBUSY; + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(".\n"); + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + return 0; +} + +#ifdef MODULE + +static char namespace[16] = ""; +static struct device dev_cs89x0 = { + NULL, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL }; + +static int debug=0; + +MODULE_PARM(debug, "i"); + +EXPORT_NO_SYMBOLS; + +int +init_module(void) +{ + struct net_local *lp; + + net_debug = debug; + dev_cs89x0.name = namespace; + dev_cs89x0.init = mac89x0_probe; + dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); + lp = (struct net_local *)dev_cs89x0.priv; + + if (register_netdev(&dev_cs89x0) != 0) { + printk(KERN_WARNING "mac89x0.c: No card found\n"); + return -ENXIO; + } + return 0; +} + +void +cleanup_module(void) +{ + +#endif +#ifdef MODULE + writew(0, dev_cs89x0.base_addr + ADD_PORT); +#endif +#ifdef MODULE + + if (dev_cs89x0.priv != NULL) { + /* Free up the private structure, or leak memory :-) */ + unregister_netdev(&dev_cs89x0); + kfree(dev_cs89x0.priv); + dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ + } +} +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/macmace.c linux/drivers/net/macmace.c --- v2.2.17/drivers/net/macmace.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/macmace.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,793 @@ +/* + * Driver for the Macintosh 68K onboard MACE controller with PSC + * driven DMA. The MACE driver code is derived from mace.c. The + * Mac68k theory of operation is courtesy of the MacBSD wizards. + * + * 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. + * + * Copyright (C) 1996 Paul Mackerras. + * Copyright (C) 1998 Alan Cox + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mace.h" + +#define N_RX_RING 8 +#define N_TX_RING 2 +#define MAX_TX_ACTIVE 1 +#define NCMDS_TX 1 /* dma commands per element in tx ring */ +#define RX_BUFLEN (ETH_FRAME_LEN + 8) +#define TX_TIMEOUT HZ /* 1 second */ + +/* Bits in transmit DMA status */ +#define TX_DMA_ERR 0x80 + +/* The MACE is simply wired down on a Mac68K box */ + +#define MACE_BASE (void *)(0x50F1C000) +#define MACE_PROM (void *)(0x50F08001) + +struct mace68k_data +{ + volatile struct mace *mace; + volatile unsigned char *tx_ring; + volatile unsigned char *rx_ring; + int dma_intr; + unsigned char maccc; + struct net_device_stats stats; + struct timer_list tx_timeout; + int timeout_active; + int rx_slot, rx_done; + int tx_slot, tx_count; +}; + +struct mace_frame +{ + u16 len; + u16 status; + u16 rntpc; + u16 rcvcc; + u32 pad1; + u32 pad2; + u8 data[1]; + /* And frame continues.. */ +}; + +#define PRIV_BYTES sizeof(struct mace68k_data) + +static int mace68k_open(struct device *dev); +static int mace68k_close(struct device *dev); +static int mace68k_xmit_start(struct sk_buff *skb, struct device *dev); +static struct net_device_stats *mace68k_stats(struct device *dev); +static void mace68k_set_multicast(struct device *dev); +static void mace68k_reset(struct device *dev); +static int mace68k_set_address(struct device *dev, void *addr); +static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs); +static void mace68k_set_timeout(struct device *dev); +static void mace68k_tx_timeout(unsigned long data); + +/* + * PSC DMA engine control. As you'd expect on a macintosh its + * more like a lawnmower engine supplied without instructions + * + * The basic theory of operation appears to be as follows. + * + * There are two sets of receive DMA registers and two sets + * of transmit DMA registers. Instead of the more traditional + * "ring buffer" approach the Mac68K DMA engine expects you + * to be loading one chain while the other runs, and then + * to flip register set. Each entry in the chain is a fixed + * length. + */ + +/* + * Load a receive DMA channel with a base address and ring length + */ + +static void psc_load_rxdma_base(int set, void *base) +{ + psc_write_word(PSC_ENETRD_CMD + set, 0x0100); + psc_write_long(PSC_ENETRD_ADDR + set, (u32)base); + psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING); + psc_write_word(PSC_ENETRD_CMD + set, 0x9800); +} + +/* + * Reset the receive DMA subsystem + */ + +static void mace68k_rxdma_reset(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mace = mp->mace; + u8 mcc = mace->maccc; + + /* + * Turn off receive + */ + + mcc&=~ENRCV; + mace->maccc=mcc; + + /* + * Program the DMA + */ + + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_load_rxdma_base(0x0, (void *)virt_to_bus(mp->rx_ring)); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_load_rxdma_base(0x10, (void *)virt_to_bus(mp->rx_ring)); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + mace->maccc=mcc|ENRCV; + + psc_write_word(PSC_ENETRD_CTL, 0x9800); + psc_write_word(PSC_ENETRD_CTL+0x10, 0x9800); +} + +/* + * Reset the transmit DMA subsystem + */ + +static void mace68k_txdma_reset(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mace = mp->mace; + u8 mcc = mace->maccc; + + psc_write_word(PSC_ENETWR_CTL,0x8800); + + mace->maccc = mcc&~ENXMT; + psc_write_word(PSC_ENETWR_CTL,0x400); + mace->maccc = mcc; +} + +/* + * Disable DMA + */ + +static void mace68k_dma_off(struct device *dev) +{ + psc_write_word(PSC_ENETRD_CTL, 0x8800); + psc_write_word(PSC_ENETRD_CTL, 0x1000); + psc_write_word(PSC_ENETRD_CMD, 0x1100); + psc_write_word(PSC_ENETRD_CMD+0x10, 0x1100); + + psc_write_word(PSC_ENETWR_CTL, 0x8800); + psc_write_word(PSC_ENETWR_CTL, 0x1000); + psc_write_word(PSC_ENETWR_CMD, 0x1100); + psc_write_word(PSC_ENETWR_CMD+0x10, 0x1100); +} + +/* Bit-reverse one byte of an ethernet hardware address. */ + +static int +bitrev(int b) +{ + int d = 0, i; + + for (i = 0; i < 8; ++i, b >>= 1) + d = (d << 1) | (b & 1); + return d; +} + +/* + * Not really much of a probe. The hardware table tells us if this + * model of Macintrash has a MACE (AV macintoshes) + */ + +int mace68k_probe(struct device *unused) +{ + int j; + static int once=0; + struct mace68k_data *mp; + unsigned char *addr; + struct device *dev; + unsigned char checksum = 0; + + /* + * There can be only one... + */ + + if (once) return -ENODEV; + + once = 1; + + if (macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; + + printk("MACE ethernet should be present "); + + dev = init_etherdev(0, PRIV_BYTES); + if(dev==NULL) + { + printk("no free memory.\n"); + return -ENOMEM; + } + mp = (struct mace68k_data *) dev->priv; + dev->base_addr = (u32)MACE_BASE; + mp->mace = (volatile struct mace *) MACE_BASE; + + printk("at 0x%p", mp->mace); + + /* + * 16K RX ring and 4K TX ring should do nicely + */ + + mp->rx_ring=(void *)__get_free_pages(GFP_KERNEL, 2); + mp->tx_ring=(void *)__get_free_page(GFP_KERNEL); + + printk("."); + + if(mp->tx_ring==NULL || mp->rx_ring==NULL) + { + if(mp->tx_ring) + free_page((u32)mp->tx_ring); +// if(mp->rx_ring) +// __free_pages(mp->rx_ring,2); + printk("\nNo memory for ring buffers.\n"); + return -ENOMEM; + } + + /* We want the receive data to be uncached. We dont care about the + byte reading order */ + + printk("."); + kernel_set_cachemode((void *)mp->rx_ring, 16384, IOMAP_NOCACHE_NONSER); + + printk("."); + /* The transmit buffer needs to be write through */ + kernel_set_cachemode((void *)mp->tx_ring, 4096, IOMAP_WRITETHROUGH); + + printk(" Ok\n"); + dev->irq = IRQ_MAC_MACE; + printk(KERN_INFO "%s: MACE at", dev->name); + + /* + * The PROM contains 8 bytes which total 0xFF when XOR'd + * together. Due to the usual peculiar apple brain damage + * the bytes are spaced out in a strange boundary and the + * bits are reversed. + */ + + addr = (void *)MACE_PROM; + + for (j = 0; j < 6; ++j) + { + u8 v=bitrev(addr[j<<4]); + checksum^=v; + dev->dev_addr[j] = v; + printk("%c%.2x", (j ? ':' : ' '), dev->dev_addr[j]); + } + for (; j < 8; ++j) + { + checksum^=bitrev(addr[j<<4]); + } + + if(checksum!=0xFF) + { + printk(" (invalid checksum)\n"); + return -ENODEV; + } + printk("\n"); + + memset(&mp->stats, 0, sizeof(mp->stats)); + init_timer(&mp->tx_timeout); + mp->timeout_active = 0; + + dev->open = mace68k_open; + dev->stop = mace68k_close; + dev->hard_start_xmit = mace68k_xmit_start; + dev->get_stats = mace68k_stats; + dev->set_multicast_list = mace68k_set_multicast; + dev->set_mac_address = mace68k_set_address; + + ether_setup(dev); + + mp = (struct mace68k_data *) dev->priv; + mp->maccc = ENXMT | ENRCV; + mp->dma_intr = IRQ_MAC_MACE_DMA; + + psc_write_word(PSC_ENETWR_CTL, 0x9000); + psc_write_word(PSC_ENETRD_CTL, 0x9000); + psc_write_word(PSC_ENETWR_CTL, 0x0400); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + + mace68k_dma_off(dev); + + return 0; +} + +/* + * Reset a MACE controller + */ + +static void mace68k_reset(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i; + + /* soft-reset the chip */ + mb->biucc = SWRST; + udelay(100); + + mb->biucc = XMTSP_64; + mb->imr = 0xff; /* disable all intrs for now */ + i = mb->ir; + mb->maccc = 0; /* turn off tx, rx */ + mb->utr = RTRD; + mb->fifocc = RCVFW_64; + mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ + + /* load up the hardware address */ + + mb->iac = ADDRCHG | PHYADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i]; + + /* clear the multicast filter */ + mb->iac = ADDRCHG | LOGADDR; + + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 8; ++i) + mb->ladrf = 0; + + mb->plscc = PORTSEL_GPSI + ENPLSIO; +} + +/* + * Load the address on a mace controller. + */ + +static int mace68k_set_address(struct device *dev, void *addr) +{ + unsigned char *p = addr; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* load up the hardware address */ + mb->iac = ADDRCHG | PHYADDR; + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i] = p[i]; + /* note: setting ADDRCHG clears ENRCV */ + mb->maccc = mp->maccc; + restore_flags(flags); + return 0; +} + +/* + * Open the Macintosh MACE. Most of this is playing with the DMA + * engine. The ethernet chip is quite friendly. + */ + +static int mace68k_open(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + + /* reset the chip */ + mace68k_reset(dev); + + mp->rx_done = 0; + mace68k_rxdma_reset(dev); + + /* + * The interrupt is fixed and comes off the PSC. + */ + + if (request_irq(dev->irq, mace68k_interrupt, 0, "68K MACE", dev)) + { + printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + /* + * Ditto the DMA interrupt. + */ + + if (request_irq(IRQ_MAC_MACE_DMA, mace68k_dma_intr, 0, "68K MACE DMA", + dev)) + { + printk(KERN_ERR "MACE: can't get irq %d\n", IRQ_MAC_MACE_DMA); + return -EAGAIN; + } + + /* Activate the Mac DMA engine */ + + mp->tx_slot = 0; /* Using register set 0 */ + mp->tx_count = 1; /* 1 Buffer ready for use */ + mace68k_txdma_reset(dev); + + /* turn it on! */ + mb->maccc = mp->maccc; + /* enable all interrupts except receive interrupts */ + mb->imr = RCVINT; + return 0; +} + +/* + * Shut down the mace and its interrupt channel + */ + +static int mace68k_close(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + + /* disable rx and tx */ + mb->maccc = 0; + mb->imr = 0xff; /* disable all intrs */ + + /* disable rx and tx dma */ + + mace68k_dma_off(dev); + + free_irq(dev->irq, dev); + free_irq(IRQ_MAC_MACE_DMA, dev); + return 0; +} + +static inline void mace68k_set_timeout(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + unsigned long flags; + + save_flags(flags); + cli(); + if (mp->timeout_active) + del_timer(&mp->tx_timeout); + mp->tx_timeout.expires = jiffies + TX_TIMEOUT; + mp->tx_timeout.function = mace68k_tx_timeout; + mp->tx_timeout.data = (unsigned long) dev; + add_timer(&mp->tx_timeout); + mp->timeout_active = 1; + restore_flags(flags); +} + +/* + * Transmit a frame + */ + +static int mace68k_xmit_start(struct sk_buff *skb, struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + /* + * This may need atomic types ??? + */ + if(mp->tx_count == 0) + { + dev->tbusy=1; + return 1; + } + mp->tx_count--; + + /* + * FIXME: + * This is hackish. The memcpy probably isnt needed but + * the rules for alignment are not known. Ideally we'd like + * to just blast the skb directly to ethernet. We also don't + * use the ring properly - just a one frame buffer. That + * also requires cache pushes ;). + */ + memcpy((void *)mp->tx_ring, skb, skb->len); + psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, virt_to_bus(mp->tx_ring)); + psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len); + psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800); + mp->stats.tx_packets++; + mp->stats.tx_bytes+=skb->len; + dev_kfree_skb(skb); + return 0; +} + +static struct net_device_stats *mace68k_stats(struct device *dev) +{ + struct mace68k_data *p = (struct mace68k_data *) dev->priv; + return &p->stats; +} + +/* + * CRC polynomial - used in working out multicast filter bits. + */ +#define CRC_POLY 0xedb88320 + +static void mace68k_set_multicast(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + int i, j, k, b; + unsigned long crc; + + mp->maccc &= ~PROM; + if (dev->flags & IFF_PROMISC) + { + mp->maccc |= PROM; + } else + { + unsigned char multicast_filter[8]; + struct dev_mc_list *dmi = dev->mc_list; + + if (dev->flags & IFF_ALLMULTI) + { + for (i = 0; i < 8; i++) + multicast_filter[i] = 0xff; + } else + { + for (i = 0; i < 8; i++) + multicast_filter[i] = 0; + for (i = 0; i < dev->mc_count; i++) + { + crc = ~0; + for (j = 0; j < 6; ++j) + { + b = dmi->dmi_addr[j]; + for (k = 0; k < 8; ++k) + { + if ((crc ^ b) & 1) + crc = (crc >> 1) ^ CRC_POLY; + else + crc >>= 1; + b >>= 1; + } + } + j = crc >> 26; /* bit number in multicast_filter */ + multicast_filter[j >> 3] |= 1 << (j & 7); + dmi = dmi->next; + } + } +#if 0 + printk("Multicast filter :"); + for (i = 0; i < 8; i++) + printk("%02x ", multicast_filter[i]); + printk("\n"); +#endif + + mb->iac = ADDRCHG | LOGADDR; + while ((mb->iac & ADDRCHG) != 0); + + for (i = 0; i < 8; ++i) + mb->ladrf = multicast_filter[i]; + } + /* reset maccc */ + mb->maccc = mp->maccc; +} + +/* + * Miscellaneous interrupts are handled here. We may end up + * having to bash the chip on the head for bad errors + */ + +static void mace68k_handle_misc_intrs(struct mace68k_data *mp, int intr) +{ + volatile struct mace *mb = mp->mace; + static int mace68k_babbles, mace68k_jabbers; + + if (intr & MPCO) + mp->stats.rx_missed_errors += 256; + mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + if (intr & RNTPCO) + mp->stats.rx_length_errors += 256; + mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + if (intr & CERR) + ++mp->stats.tx_heartbeat_errors; + if (intr & BABBLE) + if (mace68k_babbles++ < 4) + printk(KERN_DEBUG "mace: babbling transmitter\n"); + if (intr & JABBER) + if (mace68k_jabbers++ < 4) + printk(KERN_DEBUG "mace: jabbering transceiver\n"); +} + +/* + * A transmit error has occured. (We kick the transmit side from + * the DMA completion) + */ + +static void mace68k_xmit_error(struct device *dev) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + u8 xmtfs, xmtrc; + + xmtfs = mb->xmtfs; + xmtrc = mb->xmtrc; + + if(xmtfs & XMTSV) + { + if(xmtfs & UFLO) + { + printk("%s: DMA underrun.\n", dev->name); + mp->stats.tx_errors++; + mp->stats.tx_fifo_errors++; + mace68k_reset(dev); + } + if(xmtfs & RTRY) + mp->stats.collisions++; + } + mark_bh(NET_BH); +} + +/* + * A receive interrupt occured. + */ + +static void mace68k_recv_interrupt(struct device *dev) +{ +// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +// volatile struct mace *mb = mp->mace; +} + +/* + * Process the chip interrupt + */ + +static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + volatile struct mace *mb = mp->mace; + u8 ir; + + ir = mb->ir; + mace68k_handle_misc_intrs(mp, ir); + + if(ir&XMTINT) + mace68k_xmit_error(dev); + if(ir&RCVINT) + mace68k_recv_interrupt(dev); +} + +static void mace68k_tx_timeout(unsigned long data) +{ +// struct device *dev = (struct device *) data; +// struct mace68k_data *mp = (struct mace68k_data *) dev->priv; +// volatile struct mace *mb = mp->mace; +} + +/* + * Handle a newly arrived frame + */ + +static void mace_dma_rx_frame(struct device *dev, struct mace_frame *mf) +{ + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + struct sk_buff *skb; + + if(mf->status&RS_OFLO) + { + printk("%s: fifo overflow.\n", dev->name); + mp->stats.rx_errors++; + mp->stats.rx_fifo_errors++; + } + if(mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) + mp->stats.rx_errors++; + + if(mf->status&RS_CLSN) + mp->stats.collisions++; + if(mf->status&RS_FRAMERR) + mp->stats.rx_frame_errors++; + if(mf->status&RS_FCSERR) + mp->stats.rx_crc_errors++; + + skb = dev_alloc_skb(mf->len+2); + if(skb==NULL) + { + mp->stats.rx_dropped++; + return; + } + skb_reserve(skb,2); + memcpy(skb_put(skb, mf->len), mf->data, mf->len); + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + mp->stats.rx_packets++; + mp->stats.rx_bytes+=mf->len; +} + +/* + * The PSC has passed us a DMA interrupt event. + */ + +static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct mace68k_data *mp = (struct mace68k_data *) dev->priv; + + u32 psc_status; + + /* It seems this must be allowed to stabilise ?? */ + + while((psc_status=psc_read_long(0x0804))!=psc_read_long(0x0804)); + + /* + * Was this an ethernet event ? + */ + + if(psc_status&0x60000000) + { + /* + * Process the read queue + */ + + u16 psc_status = psc_read_word(PSC_ENETRD_CTL); + + if(psc_status&0x2000) + { + mace68k_rxdma_reset(dev); + mp->rx_done = 0; + } + + else if(psc_status&0x100) + { + int left; + + psc_write_word(PSC_ENETRD_CMD+mp->rx_slot, 0x1100); + left=psc_read_long(PSC_ENETRD_LEN+mp->rx_slot); + /* read packets */ + + while(mp->rx_done < left) + { + struct mace_frame *mf=((struct mace_frame *) + mp->rx_ring)+mp->rx_done++; + mace_dma_rx_frame(dev, mf); + } + + if(left == 0) /* Out of DMA room */ + { + psc_load_rxdma_base(mp->rx_slot, + (void *)virt_to_phys(mp->rx_ring)); + mp->rx_slot^=16; + mp->rx_done = 0; + } + else + { + psc_write_word(PSC_ENETRD_CMD+mp->rx_slot, + 0x9800); + } + + } + + /* + * Process the write queue + */ + + psc_status = psc_read_word(PSC_ENETWR_CTL); + if(psc_status&0x2000) { + mace68k_txdma_reset(dev); + } else if(psc_status&0x0100) { + psc_write_word(PSC_ENETWR_CMD+mp->tx_slot, 0x100); + mp->tx_slot^=16; + mp->tx_count++; + dev->tbusy = 0; + mark_bh(NET_BH); + } + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/macsonic.c linux/drivers/net/macsonic.c --- v2.2.17/drivers/net/macsonic.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/macsonic.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,624 @@ +/* + * macsonic.c + * + * (C) 1998 Alan Cox + * + * Debugging Andreas Ehliar, Michael Schmitz + * + * Based on code + * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de) + * + * This driver is based on work from Andreas Busse, but most of + * the code is rewritten. + * + * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de) + * + * A driver for the Mac onboard Sonic ethernet chip. + * + * 98/12/21 MSch: judged from tests on Q800, it's basically working, + * but eating up both receive and transmit resources + * and duplicating packets. Needs more testing. + * + * 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#define SREGS_PAD(n) u16 n; + +#include "sonic.h" + +static int sonic_debug = 0; +static int sonic_version_printed = 0; + +extern int macsonic_probe(struct device* dev); +extern int mac_onboard_sonic_probe(struct device* dev); +extern int mac_nubus_sonic_probe(struct device* dev); + +/* For onboard SONIC */ +#define ONBOARD_SONIC_REGISTERS 0x50F0A000 +#define ONBOARD_SONIC_PROM_BASE 0x50f08000 + +enum macsonic_type { + MACSONIC_DUODOCK, + MACSONIC_APPLE, + MACSONIC_APPLE16, + MACSONIC_DAYNA, + MACSONIC_DAYNALINK +}; + +/* For the built-in SONIC in the Duo Dock */ +#define DUODOCK_SONIC_REGISTERS 0xe10000 +#define DUODOCK_SONIC_PROM_BASE 0xe12000 + +/* For Apple-style NuBus SONIC */ +#define APPLE_SONIC_REGISTERS 0 +#define APPLE_SONIC_PROM_BASE 0x40000 + +/* Daynalink LC SONIC */ +#define DAYNALINK_PROM_BASE 0x400000 + +/* For Dayna-style NuBus SONIC (haven't seen one yet) */ +#define DAYNA_SONIC_REGISTERS 0x180000 +/* This is what OpenBSD says. However, this is definitely in NuBus + ROM space so we should be able to get it by walking the NuBus + resource directories */ +#define DAYNA_SONIC_MAC_ADDR 0xffe004 + +#define SONIC_READ_PROM(addr) readb(prom_addr+addr) + +__initfunc(int macsonic_probe(struct device* dev)) +{ + int rv; + + /* This will catch fatal stuff like -ENOMEM as well as success */ + if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV) + return rv; + return mac_nubus_sonic_probe(dev); +} + +/* + * For reversing the PROM address + */ + +static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, + 1, 9, 5, 13, 3, 11, 7, 15}; + +static inline void bit_reverse_addr(unsigned char addr[6]) +{ + int i; + + for(i = 0; i < 6; i++) + addr[i] = ((nibbletab[addr[i] & 0xf] << 4) | + nibbletab[(addr[i] >> 4) &0xf]); +} + +__initfunc(int macsonic_init(struct device* dev)) +{ + struct sonic_local* lp = (struct sonic_local *)dev->priv; + int i; + + /* Allocate the entire chunk of memory for the descriptors. + Note that this cannot cross a 64K boundary. */ + for (i = 0; i < 20; i++) { + unsigned long desc_base, desc_top; + if ((lp->sonic_desc = + kmalloc(SIZEOF_SONIC_DESC + * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_DMA)) == NULL) { + printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); + } + desc_base = (unsigned long) lp->sonic_desc; + desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode); + if ((desc_top & 0xffff) >= (desc_base & 0xffff)) + break; + /* Hmm. try again (FIXME: does this actually work?) */ + kfree(lp->sonic_desc); + printk(KERN_DEBUG + "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n", + dev->name, desc_base, desc_top); + } + + if (lp->sonic_desc == NULL) { + printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n", + dev->name); + return -ENOMEM; + } + + /* Now set up the pointers to point to the appropriate places */ + lp->cda = lp->sonic_desc; + lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + + /* FIXME, maybe we should use skbs */ + if ((lp->rba = (char *) + kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_DMA)) == NULL) { + printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); + return -ENOMEM; + } + + { + int rs, ds; + + /* almost always 12*4096, but let's not take chances */ + rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096; + /* almost always under a page, but let's not take chances */ + ds = ((SIZEOF_SONIC_DESC + 4095) / 4096) * 4096; + kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER); + kernel_set_cachemode(lp->sonic_desc, ds, IOMAP_NOCACHE_SER); + } + + flush_cache_all(); + + dev->open = sonic_open; + dev->stop = sonic_close; + dev->hard_start_xmit = sonic_send_packet; + dev->get_stats = sonic_get_stats; + dev->set_multicast_list = &sonic_multicast_list; + + /* + * clear tally counter + */ + sonic_write(dev, SONIC_CRCT, 0xffff); + sonic_write(dev, SONIC_FAET, 0xffff); + sonic_write(dev, SONIC_MPT, 0xffff); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; +} + +__initfunc(int mac_onboard_sonic_ethernet_addr(struct device* dev)) +{ + const int prom_addr = ONBOARD_SONIC_PROM_BASE; + int i; + + /* On NuBus boards we can sometimes look in the ROM resources. + No such luck for comm-slot/onboard. */ + for(i = 0; i < 6; i++) + dev->dev_addr[i] = SONIC_READ_PROM(i); + + /* Most of the time, the address is bit-reversed. The NetBSD + source has a rather long and detailed historical account of + why this is so. */ + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + bit_reverse_addr(dev->dev_addr); + else + return 0; + + /* If we still have what seems to be a bogus address, we'll + look in the CAM. The top entry should be ours. */ + /* Danger! This only works if MacOS has already initialized + the card... */ + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + { + unsigned short val; + + printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n"); + + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_CEP, 15); + + val = sonic_read(dev, SONIC_CAP2); + dev->dev_addr[5] = val >> 8; + dev->dev_addr[4] = val & 0xff; + val = sonic_read(dev, SONIC_CAP1); + dev->dev_addr[3] = val >> 8; + dev->dev_addr[2] = val & 0xff; + val = sonic_read(dev, SONIC_CAP0); + dev->dev_addr[1] = val >> 8; + dev->dev_addr[0] = val & 0xff; + + printk(KERN_INFO "HW Address from CAM 15: "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + printk("\n"); + } else return 0; + + if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && + memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x05\x02", 3)) + { + /* + * Still nonsense ... messed up someplace! + */ + printk(KERN_ERR "macsonic: ERROR (INVALID MAC)\n"); + return -EIO; + } else return 0; +} + +__initfunc(int mac_onboard_sonic_probe(struct device* dev)) +{ + /* Bwahahaha */ + static int once_is_more_than_enough = 0; + struct sonic_local* lp; + int i; + + if (once_is_more_than_enough) + return -ENODEV; + once_is_more_than_enough = 1; + + if (!MACH_IS_MAC) + return -ENODEV; + + printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); + + if (macintosh_config->ether_type != MAC_ETHER_SONIC) + { + printk("none.\n"); + return -ENODEV; + } + + /* Bogus probing, on the models which may or may not have + Ethernet (BTW, the Ethernet *is* always at the same + address, and nothing else lives there, at least if Apple's + documentation is to be believed) */ + if (macintosh_config->ident == MAC_MODEL_Q630 || + macintosh_config->ident == MAC_MODEL_P588 || + macintosh_config->ident == MAC_MODEL_C610) { + unsigned long flags; + int card_present; + + save_flags(flags); + cli(); + card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS); + restore_flags(flags); + + if (!card_present) { + printk("none.\n"); + return -ENODEV; + } + } + + printk("yes\n"); + + if (dev) { + dev = init_etherdev(dev, sizeof(struct sonic_local)); + /* methinks this will always be true but better safe than sorry */ + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + } else { + dev = init_etherdev(NULL, sizeof(struct sonic_local)); + } + + if (dev == NULL) + return -ENOMEM; + + lp = (struct sonic_local*) dev->priv; + memset(lp, 0, sizeof(struct sonic_local)); + /* Danger! My arms are flailing wildly! You *must* set this + before using sonic_read() */ + + dev->base_addr = ONBOARD_SONIC_REGISTERS; + if (via_alt_mapping) + dev->irq = IRQ_AUTO_3; + else + dev->irq = IRQ_NUBUS_9; + + if (!sonic_version_printed) { + printk(KERN_INFO "%s", version); + sonic_version_printed = 1; + } + printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", + dev->name, dev->base_addr); + + /* Now do a song and dance routine in an attempt to determine + the bus width */ + + /* The PowerBook's SONIC is 16 bit always. */ + if (macintosh_config->ident == MAC_MODEL_PB520) { + lp->reg_offset = 0; + lp->dma_bitmode = 0; + } else { + /* Some of the comm-slot cards are 16 bit. But some + of them are not. The 32-bit cards use offset 2 and + pad with zeroes or sometimes ones (I think...) + Therefore, if we try offset 0 and get a silicon + revision of 0, we assume 16 bit. */ + int sr; + + /* Technically this is not necessary since we zeroed + it above */ + lp->reg_offset = 0; + lp->dma_bitmode = 0; + sr = sonic_read(dev, SONIC_SR); + if (sr == 0 || sr == 0xffff) { + lp->reg_offset = 2; + /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */ + sr = sonic_read(dev, SONIC_SR); + lp->dma_bitmode = 1; + + } + printk(KERN_INFO + "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + dev->name, sr, lp->dma_bitmode?32:16, lp->reg_offset); + } + + + /* Software reset, then initialize control registers. */ + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS | + SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | + (lp->dma_bitmode ? SONIC_DCR_DW : 0)); + + /* Clear *and* disable interrupts to be on the safe side */ + sonic_write(dev, SONIC_ISR,0x7fff); + sonic_write(dev, SONIC_IMR,0); + + /* Now look for the MAC address. */ + if (mac_onboard_sonic_ethernet_addr(dev) != 0) + return -ENODEV; + + printk(KERN_INFO "MAC "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + + printk(" IRQ %d\n", dev->irq); + + /* Shared init code */ + return macsonic_init(dev); +} + +__initfunc(int mac_nubus_sonic_ethernet_addr(struct device* dev, + unsigned long prom_addr, + int id)) +{ + int i; + for(i = 0; i < 6; i++) + dev->dev_addr[i] = SONIC_READ_PROM(i); + /* For now we are going to assume that they're all bit-reversed */ + bit_reverse_addr(dev->dev_addr); + + return 0; +} + +__initfunc(int macsonic_ident(struct nubus_dev* ndev)) +{ + if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && + ndev->dr_sw == NUBUS_DRSW_SONIC_LC) + return MACSONIC_DAYNALINK; + if (ndev->dr_hw == NUBUS_DRHW_SONIC && + ndev->dr_sw == NUBUS_DRSW_APPLE) { + /* There has to be a better way to do this... */ + if (strstr(ndev->board->name, "DuoDock")) + return MACSONIC_DUODOCK; + else + return MACSONIC_APPLE; + } + if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC && + ndev->dr_sw == 0) { /* huh? */ + return MACSONIC_APPLE16; + } + return -1; +} + +__initfunc(int mac_nubus_sonic_probe(struct device* dev)) +{ + static int slots = 0; + struct nubus_dev* ndev = NULL; + struct sonic_local* lp; + unsigned long base_addr, prom_addr; + u16 sonic_dcr; + int id = -1; + int i; + int reg_offset, dma_bitmode; + + /* Find the first SONIC that hasn't been initialized already */ + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, + NUBUS_TYPE_ETHERNET, ndev)) != NULL) + { + /* Have we seen it already? */ + if (slots & (1<board->slot)) + continue; + slots |= 1<board->slot; + + /* Is it one of ours? */ + if ((id = macsonic_ident(ndev)) != -1) + break; + } + + if (ndev == NULL) + return -ENODEV; + + switch (id) { + case MACSONIC_DUODOCK: + base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 + | SONIC_DCR_TFT0; + reg_offset = 2; + dma_bitmode = 1; + break; + case MACSONIC_APPLE: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; + reg_offset = 0; + dma_bitmode = 1; + break; + case MACSONIC_APPLE16: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; + sonic_dcr = SONIC_DCR_EXBUS + | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 + | SONIC_DCR_PO1 | SONIC_DCR_BMS; + reg_offset = 0; + dma_bitmode = 0; + break; + case MACSONIC_DAYNALINK: + base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; + sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 + | SONIC_DCR_PO1 | SONIC_DCR_BMS; + reg_offset = 0; + dma_bitmode = 0; + break; + case MACSONIC_DAYNA: + base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; + prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; + sonic_dcr = SONIC_DCR_BMS + | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; + reg_offset = 0; + dma_bitmode = 0; + break; + default: + printk(KERN_ERR "macsonic: WTF, id is %d\n", id); + return -ENODEV; + } + + if (dev) { + dev = init_etherdev(dev, sizeof(struct sonic_local)); + /* methinks this will always be true but better safe than sorry */ + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + } else { + dev = init_etherdev(NULL, sizeof(struct sonic_local)); + } + + if (dev == NULL) + return -ENOMEM; + + lp = (struct sonic_local*) dev->priv; + memset(lp, 0, sizeof(struct sonic_local)); + /* Danger! My arms are flailing wildly! You *must* set this + before using sonic_read() */ + lp->reg_offset = reg_offset; + lp->dma_bitmode = dma_bitmode; + dev->base_addr = base_addr; + dev->irq = SLOT2IRQ(ndev->board->slot); + + if (!sonic_version_printed) { + printk(KERN_INFO "%s", version); + sonic_version_printed = 1; + } + printk(KERN_INFO "%s: %s in slot %X\n", + dev->name, ndev->board->name, ndev->board->slot); + printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset); + + /* Software reset, then initialize control registers. */ + sonic_write(dev, SONIC_CMD, SONIC_CR_RST); + sonic_write(dev, SONIC_DCR, sonic_dcr + | (dma_bitmode ? SONIC_DCR_DW : 0)); + /* This *must* be written back to in order to restore the + extended programmable output bits */ + sonic_write(dev, SONIC_DCR2, 0); + + /* Clear *and* disable interrupts to be on the safe side */ + sonic_write(dev, SONIC_ISR,0x7fff); + sonic_write(dev, SONIC_IMR,0); + + /* Now look for the MAC address. */ + if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) + return -ENODEV; + + printk(KERN_INFO "MAC "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + printk(" IRQ %d\n", dev->irq); + + /* Shared init code */ + return macsonic_init(dev); +} + +#ifdef MODULE +static char namespace[16] = ""; +static struct device dev_macsonic = { + NULL, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL }; + +MODULE_PARM(sonic_debug, "i"); + +EXPORT_NO_SYMBOLS; + +int +init_module(void) +{ + dev_macsonic.name = namespace; + dev_macsonic.init = macsonic_probe; + + if (register_netdev(&dev_macsonic) != 0) { + printk(KERN_WARNING "macsonic.c: No card found\n"); + return -ENXIO; + } + return 0; +} + +void +cleanup_module(void) +{ + if (dev_macsonic.priv != NULL) { + unregister_netdev(&dev_macsonic); + kfree(dev_macsonic.priv); + dev_macsonic.priv = NULL; + } +} +#endif /* MODULE */ + + +#define vdma_alloc(foo, bar) ((u32)foo) +#define vdma_free(baz) +#define sonic_chiptomem(bat) (bat) +#define PHYSADDR(quux) (quux) + +#include "sonic.c" + +/* + * Local variables: + * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o macsonic.o macsonic.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/mvme147.c linux/drivers/net/mvme147.c --- v2.2.17/drivers/net/mvme147.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/mvme147.c Sat Oct 14 00:02:32 2000 @@ -0,0 +1,209 @@ +/* mvme147.c : the Linux/mvme147/lance ethernet driver + * + * Copyright (C) 05/1998 Peter Maydell + * Based on the Sun Lance driver and the NetBSD HP Lance driver + * Uses the generic 7990.c LANCE code. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Used for the temporal inet entries and routing */ +#include +#include + +#include + +#include +#include +#include + +#include + +/* We have 16834 bytes of RAM for the init block and buffers. This places + * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx + * buffers and 2 Tx buffers. + */ +#define LANCE_LOG_TX_BUFFERS 1 +#define LANCE_LOG_RX_BUFFERS 3 + +#include "7990.h" /* use generic LANCE code */ + +/* Our private data structure */ +struct m147lance_private { + struct lance_private lance; + void *base; + void *ram; +}; + +/* function prototypes... This is easy because all the grot is in the + * generic LANCE support. All we have to support is probing for boards, + * plus board-specific init, open and close actions. + * Oh, and we need to tell the generic code how to read and write LANCE registers... + */ +int mvme147lance_probe(struct device *dev); +static int m147lance_open(struct device *dev); +static int m147lance_close(struct device *dev); +static void m147lance_writerap(struct m147lance_private *lp, unsigned short value); +static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value); +static unsigned short m147lance_readrdp(struct m147lance_private *lp); + +typedef void (*writerap_t)(void *, unsigned short); +typedef void (*writerdp_t)(void *, unsigned short); +typedef void (*readrdp_t)(void *); + +#ifdef MODULE +static struct m147lance_private *root_m147lance_dev = NULL; +#endif + +/* Initialise the one and only on-board 7990 */ +__initfunc(int mvme147lance_probe(struct device *dev)) +{ + static int called = 0; + static const char name[] = "MVME147 LANCE"; + struct m147lance_private *lp; + u_long *addr; + u_long address; + + if (!MACH_IS_MVME147 || called) + return(ENODEV); + called++; + + dev->priv = kmalloc(sizeof(struct m147lance_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct m147lance_private)); + + /* Fill the dev fields */ + dev->base_addr = (unsigned long)MVME147_LANCE_BASE; + dev->open = &m147lance_open; + dev->stop = &m147lance_close; + dev->hard_start_xmit = &lance_start_xmit; + dev->get_stats = &lance_get_stats; + dev->set_multicast_list = &lance_set_multicast; + dev->dma = 0; + + addr=(u_long *)ETHERNET_ADDRESS; + address = *addr; + dev->dev_addr[0]=0x08; + dev->dev_addr[1]=0x00; + dev->dev_addr[2]=0x3e; + address=address>>8; + dev->dev_addr[5]=address&0xff; + address=address>>8; + dev->dev_addr[4]=address&0xff; + address=address>>8; + dev->dev_addr[3]=address&0xff; + + printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_addr, MVME147_LANCE_IRQ, + dev->dev_addr[0], + dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], + dev->dev_addr[5]); + + lp = (struct m147lance_private *)dev->priv; + lp->ram = (void *)__get_dma_pages(GFP_ATOMIC, 3); /* 16K */ + if (!lp->ram) + { + printk("%s: No memory for LANCE buffers\n", dev->name); + return -ENODEV; + } + + lp->lance.name = (char*)name; /* discards const, shut up gcc */ + lp->lance.ll = (struct lance_regs *)(dev->base_addr); + lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */ + lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram); /* LANCE addr of same RAM */ + lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */ + lp->lance.irq = MVME147_LANCE_IRQ; + lp->lance.writerap = (writerap_t)m147lance_writerap; + lp->lance.writerdp = (writerdp_t)m147lance_writerdp; + lp->lance.readrdp = (readrdp_t)m147lance_readrdp; + lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS; + lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; + lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK; + lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; + ether_setup(dev); + +#ifdef MODULE + dev->ifindex = dev_new_index(); + lp->next_module = root_m147lance_dev; + root_m147lance_dev = lp; +#endif /* MODULE */ + + return 0; +} + +static void m147lance_writerap(struct m147lance_private *lp, unsigned short value) +{ + lp->lance.ll->rap = value; +} + +static void m147lance_writerdp(struct m147lance_private *lp, unsigned short value) +{ + lp->lance.ll->rdp = value; +} + +static unsigned short m147lance_readrdp(struct m147lance_private *lp) +{ + return lp->lance.ll->rdp; +} + +static int m147lance_open(struct device *dev) +{ + int status; + + status = lance_open(dev); /* call generic lance open code */ + if (status) + return status; + /* enable interrupts at board level. */ + m147_pcc->lan_cntrl=0; /* clear the interrupts (if any) */ + m147_pcc->lan_cntrl=0x08 | 0x04; /* Enable irq 4 */ + + MOD_INC_USE_COUNT; + return 0; +} + +static int m147lance_close(struct device *dev) +{ + /* disable interrupts at boardlevel */ + m147_pcc->lan_cntrl=0x0; /* disable interrupts */ + lance_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + root_lance_dev = NULL; + return mvme147lance_probe(NULL); +} + +void cleanup_module(void) +{ + /* Walk the chain of devices, unregistering them */ + struct m147lance_private *lp; + while (root_m147lance_dev) { + lp = root_m147lance_dev->next_module; + unregister_netdev(root_lance_dev->dev); + free_pages(lp->ram, 3); + kfree(root_lance_dev->dev); + root_lance_dev = lp; + } +} + +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ncr885e.h linux/drivers/net/ncr885e.h --- v2.2.17/drivers/net/ncr885e.h Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/ncr885e.h Sat Nov 18 18:01:24 2000 @@ -177,7 +177,7 @@ /* bits for the above three interrupt registers */ #define INTERRUPT_INTE 1<<15 /* interrupt enable */ #define INTERRUPT_WI 1<<9 /* wakeup interrupt */ -#define INTERRUPT_ERI 1<<8 /* early recieve interrupt */ +#define INTERRUPT_ERI 1<<8 /* early receive interrupt */ #define INTERRUPT_PPET 1<<7 /* PCI Tx parity error */ #define INTERRUPT_PBFT 1<<6 /* PCI Tx bus fault */ #define INTERRUPT_IIDT 1<<5 /* illegal instruction Tx */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ne2.c linux/drivers/net/ne2.c --- v2.2.17/drivers/net/ne2.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/ne2.c Mon Sep 11 17:58:02 2000 @@ -110,16 +110,16 @@ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ /* From the .ADF file: */ -static unsigned int addresses[7]= +static unsigned int addresses[7] __initdata = {0x1000, 0x2020, 0x8020, 0xa0a0, 0xb0b0, 0xc0c0, 0xc3d0}; -static int irqs[4] = {3, 4, 5, 9}; +static int irqs[4] __initdata = {3, 4, 5, 9}; struct ne2_adapters_t { unsigned int id; char *name; }; -const struct ne2_adapters_t ne2_adapters[] = { +static struct ne2_adapters_t ne2_adapters[] __initdata = { { 0x6354, "Arco Ethernet Adapter AE/2" }, { 0x70DE, "Compex ENET-16 MC/P" }, { 0x7154, "Novell Ethernet Adapter NE/2" }, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.2.17/drivers/net/ni52.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/ni52.c Sat Sep 30 18:35:22 2000 @@ -160,9 +160,9 @@ /**************************************************************************/ /* different DELAYs */ -#define DELAY(x) __delay((loops_per_sec>>5)*(x)); -#define DELAY_16(); { __delay( (loops_per_sec>>16)+1 ); } -#define DELAY_18(); { __delay( (loops_per_sec>>18)+1 ); } +#define DELAY(x) mdelay(32 * x); +#define DELAY_16(); { udelay(16); } +#define DELAY_18(); { udelay(4); } /* wait for command with timeout: */ #define WAIT_4_SCB_CMD() \ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.2.17/drivers/net/pcnet32.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/pcnet32.c Sat Sep 30 23:21:57 2000 @@ -316,6 +316,12 @@ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, pcnet32_probe1}, + /* Someone apparently got their vendor id wrong .. + reported in an IBM box */ + { "AMD PCnetPCI series (IBM)", + 0x1023, 0x2000, 0, 0, + PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, + pcnet32_probe1}, { "AMD PCnetHome series", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/rcif.h linux/drivers/net/rcif.h --- v2.2.17/drivers/net/rcif.h Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/rcif.h Sat Sep 23 13:59:26 2000 @@ -43,10 +43,10 @@ /* define a single TCB & buffer */ typedef struct /* a single buffer */ { - U32 context; /* context */ - U32 scount; /* segment count */ - U32 size; /* segment size */ - U32 addr; /* segment physical address */ + u32 context; /* context */ + u32 scount; /* segment count */ + u32 size; /* segment size */ + u32 addr; /* segment physical address */ } __attribute__((packed)) singleB, *psingleB ; @@ -65,7 +65,7 @@ ** | | physical address of buffer / ** +-----------------------+ _/ */ - U32 bcount; /* buffer count */ + u32 bcount; /* buffer count */ singleB b; /* buffer */ } @@ -82,7 +82,7 @@ 5) Command identifier entry For Example ("GETSPEED"): - 1) struct RCgetspeed_tag { U32 LinkSpeedCode; } RCgetspeed; + 1) struct RCgetspeed_tag { u32 LinkSpeedCode; } RCgetspeed; 2) struct RCgetspeed_tag *getspeed; 3) #define RCUS_GETSPEED data.RCgetspeed; 4) #define RCUD_GETSPEED _RC_user_data.getspeed @@ -121,66 +121,66 @@ /* GETSPEED structure */ struct RCgetspeed_tag { - U32 LinkSpeedCode; + u32 LinkSpeedCode; } RCgetspeed; /* <---- RCgetspeed */ /* SETSPEED structure */ struct RCsetspeed_tag { - U16 LinkSpeedCode; + u16 LinkSpeedCode; } RCsetspeed; /* <---- RCsetspeed */ /* GETPROM structure */ struct RCgetprom_tag { - U32 PromMode; + u32 PromMode; } RCgetprom; /* <---- RCgetprom */ /* SETPROM structure */ struct RCsetprom_tag { - U16 PromMode; + u16 PromMode; } RCsetprom; /* <---- RCsetprom */ /* GETBROADCAST structure */ struct RCgetbroadcast_tag { - U32 BroadcastMode; + u32 BroadcastMode; } RCgetbroadcast; /* <---- RCgetbroadcast */ /* SETBROADCAST structure */ struct RCsetbroadcast_tag { - U16 BroadcastMode; + u16 BroadcastMode; } RCsetbroadcast; /* <---- RCsetbroadcast */ /* GETFIRMWAREVER structure */ #define FirmStringLen 80 struct RCgetfwver_tag { - U8 FirmString[FirmStringLen]; + u8 FirmString[FirmStringLen]; } RCgetfwver; /* <---- RCgetfwver */ /* GETIPANDMASK structure */ struct RCgetipnmask_tag { - U32 IpAddr; - U32 NetMask; + u32 IpAddr; + u32 NetMask; } RCgetipandmask; /* <---- RCgetipandmask */ /* SETIPANDMASK structure */ struct RCsetipnmask_tag { - U32 IpAddr; - U32 NetMask; + u32 IpAddr; + u32 NetMask; } RCsetipandmask; /* <---- RCsetipandmask */ /* GETMAC structure */ #define MAC_SIZE 10 struct RCgetmac_tag { - U8 mac[MAC_SIZE]; + u8 mac[MAC_SIZE]; } RCgetmac; /* <---- RCgetmac */ /* SETMAC structure */ struct RCsetmac_tag { - U8 mac[MAC_SIZE]; + u8 mac[MAC_SIZE]; } RCsetmac; /* <---- RCsetmac */ /* GETLINKSTATUS structure */ struct RCgetlnkstatus_tag { - U32 ReturnStatus; + u32 ReturnStatus; } RCgetlnkstatus; /* <---- RCgetlnkstatus */ /* GETLINKSTATISTICS structure */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/rclanmtl.c linux/drivers/net/rclanmtl.c --- v2.2.17/drivers/net/rclanmtl.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/rclanmtl.c Fri Sep 29 10:11:45 2000 @@ -231,13 +231,13 @@ /* I2O message header */ typedef struct _I2O_MESSAGE_FRAME { - U8 VersionOffset; - U8 MsgFlags; - U16 MessageSize; + u8 VersionOffset; + u8 MsgFlags; + u16 MessageSize; BF TargetAddress:I2O_TID_SZ; BF InitiatorAddress:I2O_TID_SZ; BF Function:I2O_FUNCTION_SZ; - U32 InitiatorContext; + u32 InitiatorContext; /* SGL[] */ } I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME; @@ -289,15 +289,15 @@ typedef struct { PATU p_atu; /* ptr to ATU register block */ - PU8 pPci45LinBaseAddr; - PU8 pLinOutMsgBlock; - U32 outMsgBlockPhyAddr; + u8 * pPci45LinBaseAddr; + u8 * pLinOutMsgBlock; + u32 outMsgBlockPhyAddr; PFNTXCALLBACK pTransCallbackFunc; PFNRXCALLBACK pRecvCallbackFunc; PFNCALLBACK pRebootCallbackFunc; PFNCALLBACK pCallbackFunc; - U16 IOPState; - U16 InboundMFrameSize; + u16 IOPState; + u16 InboundMFrameSize; } PAB, *PPAB; @@ -357,8 +357,8 @@ /* local function prototypes */ -static void ProcessOutboundI2OMsg(PPAB pPab, U32 phyMsgAddr); -static int FillI2OMsgSGLFromTCB(PU32 pMsg, PRCTCB pXmitCntrlBlock); +static void ProcessOutboundI2OMsg(PPAB pPab, u32 phyMsgAddr); +static int FillI2OMsgSGLFromTCB(u32 * pMsg, PRCTCB pXmitCntrlBlock); static int GetI2OStatus(PPAB pPab); static int SendI2OOutboundQInitMsg(PPAB pPab); static int SendEnableSysMsg(PPAB pPab); @@ -386,8 +386,8 @@ ** ========================================================================= */ RC_RETURN -RCInitI2OMsgLayer(U16 AdapterID, U32 pciBaseAddr, - PU8 p_msgbuf, PU8 p_phymsgbuf, +RCInitI2OMsgLayer(u16 AdapterID, u32 pciBaseAddr, + u8 * p_msgbuf, u8 * p_phymsgbuf, PFNTXCALLBACK TransmitCallbackFunction, PFNRXCALLBACK ReceiveCallbackFunction, PFNCALLBACK RebootCallbackFunction) @@ -406,7 +406,7 @@ if (PCIAdapterBlock[AdapterID] != NULL) { printk("PCIAdapterBlock[%d]!=NULL\n", AdapterID); -// RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL); +// RCResetLANCard(AdapterID, 0, (u32 *)NULL, (PFNCALLBACK)NULL); PCIAdapterBlock[AdapterID] = NULL; } @@ -417,11 +417,11 @@ pPab = (PPAB)p_msgbuf; pPab->p_atu = (PATU)pciBaseAddr; - pPab->pPci45LinBaseAddr = (PU8)pciBaseAddr; + pPab->pPci45LinBaseAddr = (u8 *)pciBaseAddr; /* Set outbound message frame addr - skip over Adapter Block */ - pPab->outMsgBlockPhyAddr = (U32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE); - pPab->pLinOutMsgBlock = (PU8)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE); + pPab->outMsgBlockPhyAddr = (u32)(p_phymsgbuf + ADAPTER_BLOCK_RESERVED_SPACE); + pPab->pLinOutMsgBlock = (u8 *)(p_msgbuf + ADAPTER_BLOCK_RESERVED_SPACE); /* store callback function addresses */ pPab->pTransCallbackFunc = TransmitCallbackFunction; @@ -440,7 +440,7 @@ if (pPab->IOPState == I2O_IOP_STATE_OPERATIONAL) { printk("pPab->IOPState == op: resetting adapter\n"); - RCResetLANCard(AdapterID, 0, (PU32)NULL, (PFNCALLBACK)NULL); + RCResetLANCard(AdapterID, 0, (u32 *)NULL, (PFNCALLBACK)NULL); } result = SendI2OOutboundQInitMsg(pPab); @@ -469,7 +469,7 @@ */ #define i960_OUT_POST_Q_INT_BIT 0x0008 /* bit set masks interrupts */ -RC_RETURN RCDisableI2OInterrupts(U16 AdapterID) +RC_RETURN RCDisableI2OInterrupts(u16 AdapterID) { PPAB pPab; @@ -484,7 +484,7 @@ return RC_RTN_NO_ERROR; } -RC_RETURN RCEnableI2OInterrupts(U16 AdapterID) +RC_RETURN RCEnableI2OInterrupts(u16 AdapterID) { PPAB pPab; @@ -506,10 +506,10 @@ ** ========================================================================= */ RC_RETURN -RCI2OSendPacket(U16 AdapterID, U32 InitiatorContext, PRCTCB pTransCtrlBlock) +RCI2OSendPacket(u16 AdapterID, u32 InitiatorContext, PRCTCB pTransCtrlBlock) { - U32 msgOffset; - PU32 pMsg; + u32 msgOffset; + u32 * pMsg; int size; PPAB pPab; @@ -536,7 +536,7 @@ } /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock); @@ -572,10 +572,10 @@ ** ========================================================================= */ RC_RETURN -RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransCtrlBlock) +RCPostRecvBuffers(u16 AdapterID, PRCTCB pTransCtrlBlock) { - U32 msgOffset; - PU32 pMsg; + u32 msgOffset; + u32 * pMsg; int size; PPAB pPab; @@ -603,7 +603,7 @@ } /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); size = FillI2OMsgSGLFromTCB(pMsg + 4, pTransCtrlBlock); @@ -623,7 +623,7 @@ pMsg[0] = (size + 4) << 16 | LAN_MSG_REQST; /* send over message size and flags */ pMsg[1] = I2O_LAN_RECEIVE_POST << 24 | I2O_HOST_TID << 12 | RC_LAN_TARGET_ID; pMsg[2] = DEFAULT_RECV_INIT_CONTEXT; - pMsg[3] = *(PU32)pTransCtrlBlock; /* number of packet buffers */ + pMsg[3] = *(u32 *)pTransCtrlBlock; /* number of packet buffers */ /* post to Post Q */ pPab->p_atu->InQueue = msgOffset; return RC_RTN_NO_ERROR; @@ -639,12 +639,12 @@ ** ========================================================================= */ void -RCProcI2OMsgQ(U16 AdapterID) +RCProcI2OMsgQ(u16 AdapterID) { - U32 phyAddrMsg; - PU8 p8Msg; - PU32 p32; - U16 count; + u32 phyAddrMsg; + u8 * p8Msg; + u32 * p32; + u16 count; PPAB pPab; unsigned char debug_msg[20]; @@ -658,7 +658,7 @@ while (phyAddrMsg != 0xFFFFFFFF) { p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); - p32 = (PU32)p8Msg; + p32 = (u32 *)p8Msg; //printk(" msg: 0x%x 0x%x \n", p8Msg[7], p32[5]); @@ -667,7 +667,7 @@ */ if (I2O_LAN_PACKET_SEND == p8Msg[7]) /* function code byte */ { - count = *(PU16)(p8Msg+2); + count = *(u16 *)(p8Msg+2); count -= p8Msg[0] >> 4; /* status, count, context[], adapter */ (*pPab->pTransCallbackFunc)(p8Msg[19], count, p32+5, AdapterID); @@ -773,14 +773,14 @@ ** ========================================================================= */ RC_RETURN -RCGetLinkStatistics(U16 AdapterID, +RCGetLinkStatistics(u16 AdapterID, P_RCLINKSTATS StatsReturnAddr, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset; - volatile U32 timeout; - volatile PU32 pMsg; - volatile PU32 p32, pReturnAddr; + u32 msgOffset; + volatile u32 timeout; + volatile u32 * pMsg; + volatile u32 * p32, *pReturnAddr; P_NICSTAT pStats; int i; PPAB pPab; @@ -803,7 +803,7 @@ } /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); /*dprintf("Get82558Stats - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ /*dprintf("Get82558Stats - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ @@ -815,7 +815,7 @@ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_NIC_STATS; pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); - p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); pStats = (P_NICSTAT)p32; pStats->dump_status = 0xFFFFFFFF; @@ -844,7 +844,7 @@ } } - pReturnAddr = (PU32)StatsReturnAddr; + pReturnAddr = (u32 *)StatsReturnAddr; /* copy Nic stats to user's structure */ for (i = 0; i < (int) sizeof(RCLINKSTATS) / 4; i++) @@ -860,12 +860,12 @@ ** ========================================================================= */ RC_RETURN -RCGetLinkStatus(U16 AdapterID, PU32 ReturnAddr, PFNWAITCALLBACK WaitCallback) +RCGetLinkStatus(u16 AdapterID, u32 * ReturnAddr, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset; - volatile U32 timeout; - volatile PU32 pMsg; - volatile PU32 p32; + u32 msgOffset; + volatile u32 timeout; + volatile u32 * pMsg; + volatile u32 * p32; PPAB pPab; /*kprintf("Get82558LinkStatus() ReturnPhysAddr:0x%08.8ulx\n", ReturnAddr);*/ @@ -886,7 +886,7 @@ } /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); /*dprintf("Get82558LinkStatus - pMsg = 0x%08ulx, InQ msgOffset = 0x%08ulx\n", pMsg, msgOffset);*/ /*dprintf("Get82558LinkStatus - pMsg = 0x%08X, InQ msgOffset = 0x%08X\n", pMsg, msgOffset);*/ @@ -897,7 +897,7 @@ pMsg[4] = RC_PCI45_VENDOR_ID << 16 | RC_PRIVATE_GET_LINK_STATUS; pMsg[5] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); - p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); *p32 = 0xFFFFFFFF; /* post to Inbound Post Q */ @@ -906,7 +906,7 @@ timeout = 100000; while (1) { - U32 i; + u32 i; if (WaitCallback) (*WaitCallback)(); @@ -941,12 +941,12 @@ ** ========================================================================= */ RC_RETURN -RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback) +RCGetMAC(u16 AdapterID, u8 * mac, PFNWAITCALLBACK WaitCallback) { unsigned i, timeout; - U32 off; - PU32 p; - U32 temp[2]; + u32 off; + u32 * p; + u32 temp[2]; PPAB pPab; PATU p_atu; @@ -965,7 +965,7 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - p = (PU32)(pPab->pPci45LinBaseAddr + off); + p = (u32 *)(pPab->pPci45LinBaseAddr + off); #ifdef RCDEBUG printk("RCGetMAC: p_atu 0x%08x, off 0x%08x, p 0x%08x\n", @@ -1025,10 +1025,10 @@ ** ========================================================================= */ RC_RETURN -RCSetMAC(U16 AdapterID, PU8 mac) +RCSetMAC(u16 AdapterID, u8 * mac) { - U32 off; - PU32 pMsg; + u32 off; + u32 * pMsg; PPAB pPab; @@ -1042,7 +1042,7 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup private message */ pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1074,10 +1074,10 @@ ** ========================================================================= */ RC_RETURN -RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode) +RCSetLinkSpeed(u16 AdapterID, u16 LinkSpeedCode) { - U32 off; - PU32 pMsg; + u32 off; + u32 * pMsg; PPAB pPab; @@ -1091,7 +1091,7 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup private message */ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1116,10 +1116,10 @@ ** ========================================================================= */ RC_RETURN -RCSetPromiscuousMode(U16 AdapterID, U16 Mode) +RCSetPromiscuousMode(u16 AdapterID, u16 Mode) { - U32 off; - PU32 pMsg; + u32 off; + u32 * pMsg; PPAB pPab; pPab =PCIAdapterBlock[AdapterID]; @@ -1132,7 +1132,7 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup private message */ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1159,11 +1159,11 @@ ** ========================================================================= */ RC_RETURN -RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) +RCGetPromiscuousMode(u16 AdapterID, u32 * pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; + u32 msgOffset, timeout; + u32 * pMsg; + volatile u32 * p32; PPAB pPab; pPab =PCIAdapterBlock[AdapterID]; @@ -1179,10 +1179,10 @@ } /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (volatile u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); p32[0] = 0xff; /* setup private message */ @@ -1222,7 +1222,7 @@ } /* get mode */ - *pMode = (U8)((volatile PU8)p32)[0] & 0x0f; + *pMode = (u8)((volatile u8 *)p32)[0] & 0x0f; return RC_RTN_NO_ERROR; } @@ -1237,10 +1237,10 @@ ** ========================================================================= */ RC_RETURN -RCSetBroadcastMode(U16 AdapterID, U16 Mode) +RCSetBroadcastMode(u16 AdapterID, u16 Mode) { - U32 off; - PU32 pMsg; + u32 off; + u32 * pMsg; PPAB pPab; pPab =PCIAdapterBlock[AdapterID]; @@ -1253,7 +1253,7 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup private message */ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1280,11 +1280,11 @@ ** ========================================================================= */ RC_RETURN -RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) +RCGetBroadcastMode(u16 AdapterID, u32 * pMode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; + u32 msgOffset, timeout; + u32 * pMsg; + volatile u32 * p32; PPAB pPab; pPab =PCIAdapterBlock[AdapterID]; @@ -1300,10 +1300,10 @@ } /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (volatile u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); p32[0] = 0xff; /* setup private message */ @@ -1343,7 +1343,7 @@ } /* get mode */ - *pMode = (U8)((volatile PU8)p32)[0] & 0x0f; + *pMode = (u8)((volatile u8 *)p32)[0] & 0x0f; return RC_RTN_NO_ERROR; } @@ -1363,12 +1363,12 @@ ** ========================================================================= */ RC_RETURN -RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback) +RCGetLinkSpeed(u16 AdapterID, u32 * pLinkSpeedCode, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; - U8 IOPLinkSpeed; + u32 msgOffset, timeout; + u32 * pMsg; + volatile u32 * p32; + u8 IOPLinkSpeed; PPAB pPab; pPab =PCIAdapterBlock[AdapterID]; @@ -1384,10 +1384,10 @@ } /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (volatile u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); p32[0] = 0xff; /* setup private message */ @@ -1427,7 +1427,7 @@ } /* get Link speed */ - IOPLinkSpeed = (U8)((volatile PU8)p32)[0] & 0x0f; + IOPLinkSpeed = (u8)((volatile u8 *)p32)[0] & 0x0f; *pLinkSpeedCode= IOPLinkSpeed; @@ -1436,7 +1436,7 @@ /* ** ========================================================================= -** RCReportDriverCapability(U16 AdapterID, U32 capability) +** RCReportDriverCapability(u16 AdapterID, u32 capability) ** ** Currently defined bits: ** WARM_REBOOT_CAPABLE 0x01 @@ -1444,10 +1444,10 @@ ** ========================================================================= */ RC_RETURN -RCReportDriverCapability(U16 AdapterID, U32 capability) +RCReportDriverCapability(u16 AdapterID, u32 capability) { - U32 off; - PU32 pMsg; + u32 off; + u32 * pMsg; PPAB pPab; pPab =PCIAdapterBlock[AdapterID]; @@ -1460,7 +1460,7 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup private message */ pMsg[0] = SIX_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1484,11 +1484,11 @@ ** ========================================================================= */ RC_RETURN -RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback) +RCGetFirmwareVer(u16 AdapterID, u8 * pFirmString, PFNWAITCALLBACK WaitCallback) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; + u32 msgOffset, timeout; + u32 * pMsg; + volatile u32 * p32; PPAB pPab; pPab =PCIAdapterBlock[AdapterID]; @@ -1503,10 +1503,10 @@ } /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); /* virtual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (volatile u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); p32[0] = 0xff; /* setup private message */ @@ -1547,7 +1547,7 @@ } } - strcpy(pFirmString, (PU8)p32); + strcpy(pFirmString, (u8 *)p32); return RC_RTN_NO_ERROR; } @@ -1565,10 +1565,10 @@ ** ========================================================================= */ RC_RETURN -RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction) +RCResetLANCard(u16 AdapterID, u16 ResourceFlags, u32 * ReturnAddr, PFNCALLBACK CallbackFunction) { unsigned long off; - unsigned long *pMsg; + u32 *pMsg; PPAB pPab; int i; long timeout = 0; @@ -1586,7 +1586,7 @@ pPab->pCallbackFunc = CallbackFunction; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup message */ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1611,8 +1611,8 @@ break; } } - if (ReturnAddr != (PU32)NULL) - *ReturnAddr = (U32)pPab->pCallbackFunc; + if (ReturnAddr != (u32 *)NULL) + *ReturnAddr = (u32)pPab->pCallbackFunc; } return RC_RTN_NO_ERROR ; @@ -1626,12 +1626,12 @@ ** ========================================================================= */ RC_RETURN -RCResetIOP(U16 AdapterID) +RCResetIOP(u16 AdapterID) { - U32 msgOffset, timeout; - PU32 pMsg; + u32 msgOffset, timeout; + u32 *pMsg; PPAB pPab; - volatile PU32 p32; + volatile u32 * p32; pPab = PCIAdapterBlock[AdapterID]; msgOffset = pPab->p_atu->InQueue; @@ -1642,7 +1642,7 @@ } /* calc virtual address of msg - virtual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; pMsg[1] = I2O_EXEC_IOP_RESET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; @@ -1656,7 +1656,7 @@ pMsg[8] = 1; /* return 1 byte */ /* virual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (volatile u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); p32[0] = 0; p32[1] = 0; @@ -1699,10 +1699,10 @@ ** ========================================================================= */ RC_RETURN -RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction) +RCShutdownLANCard(u16 AdapterID, u16 ResourceFlags, u32 * ReturnAddr, PFNCALLBACK CallbackFunction) { - volatile PU32 pMsg; - U32 off; + volatile u32 * pMsg; + u32 off; PPAB pPab; int i; long timeout = 0; @@ -1719,7 +1719,7 @@ pPab->pCallbackFunc = CallbackFunction; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup message */ pMsg[0] = FOUR_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1745,8 +1745,8 @@ break; } } - if (ReturnAddr != (PU32)NULL) - *ReturnAddr = (U32)pPab->pCallbackFunc; + if (ReturnAddr != (u32 *)NULL) + *ReturnAddr = (u32)pPab->pCallbackFunc; } return RC_RTN_NO_ERROR ; } @@ -1765,10 +1765,10 @@ ** ========================================================================= */ RC_RETURN -RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask) +RCSetRavlinIPandMask(u16 AdapterID, u32 ipAddr, u32 netMask) { - volatile PU32 pMsg; - U32 off; + volatile u32 * pMsg; + u32 off; PPAB pPab; pPab = PCIAdapterBlock[AdapterID]; @@ -1781,7 +1781,7 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); /* setup private message */ pMsg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; @@ -1807,12 +1807,12 @@ ** ========================================================================= */ RC_RETURN -RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask, +RCGetRavlinIPandMask(u16 AdapterID, u32 * pIpAddr, u32 * pNetMask, PFNWAITCALLBACK WaitCallback) { unsigned i, timeout; - U32 off; - PU32 pMsg, p32; + u32 off; + u32 * pMsg, *p32; PPAB pPab; PATU p_atu; @@ -1831,10 +1831,10 @@ if (0xFFFFFFFF == off) return RC_RTN_FREE_Q_EMPTY; - p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); *p32 = 0xFFFFFFFF; - pMsg = (PU32)(pPab->pPci45LinBaseAddr + off); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + off); #ifdef DEBUG kprintf("RCGetRavlinIPandMask: p_atu 0x%08.8ulx, off 0x%08.8ulx, p32 0x%08.8ulx\n", p_atu, off, p32); @@ -1907,9 +1907,9 @@ static int SendI2OOutboundQInitMsg(PPAB pPab) { - U32 msgOffset, timeout, phyOutQFrames, i; - volatile PU32 pMsg; - volatile PU32 p32; + u32 msgOffset, timeout, phyOutQFrames, i; + volatile u32 * pMsg; + volatile u32 * p32; @@ -1926,7 +1926,7 @@ /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); #ifdef DEBUG kprintf("SendI2OOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset); @@ -1943,7 +1943,7 @@ pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); /* virual pointer to return buffer - clear first two dwords */ - p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); p32[0] = 0; /* post to Inbound Post Q */ @@ -2009,9 +2009,9 @@ static int GetI2OStatus(PPAB pPab) { - U32 msgOffset, timeout; - PU32 pMsg; - volatile PU32 p32; + u32 msgOffset, timeout; + u32 * pMsg; + volatile u32 * p32; msgOffset = pPab->p_atu->InQueue; @@ -2027,7 +2027,7 @@ } /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); pMsg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_0; pMsg[1] = I2O_EXEC_STATUS_GET << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID; @@ -2041,7 +2041,7 @@ pMsg[8] = 88; /* return 88 bytes */ /* virual pointer to return buffer - clear first two dwords */ - p32 = (volatile PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); + p32 = (volatile u32 *)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB)); p32[0] = 0; p32[1] = 0; @@ -2087,8 +2087,8 @@ kprintf("0x%08.8ulx:0x%08.8ulx:0x%08.8ulx:0x%08.8ulx\n", p32[8], p32[9], p32[10], p32[11]); #endif /* DEBUG */ /* get IOP state */ - pPab->IOPState = ((volatile PU8)p32)[10]; - pPab->InboundMFrameSize = ((volatile PU16)p32)[6]; + pPab->IOPState = ((volatile u8 *)p32)[10]; + pPab->InboundMFrameSize = ((volatile u16 *)p32)[6]; #ifdef DEBUG kprintf("IOP state 0x%02.2x InFrameSize = 0x%04.4x\n", @@ -2108,8 +2108,8 @@ static int SendEnableSysMsg(PPAB pPab) { - U32 msgOffset; // timeout; - volatile PU32 pMsg; + u32 msgOffset; // timeout; + volatile u32 * pMsg; msgOffset = pPab->p_atu->InQueue; @@ -2122,7 +2122,7 @@ } /* calc virual address of msg - virual already mapped to physical */ - pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset); + pMsg = (u32 *)(pPab->pPci45LinBaseAddr + msgOffset); #ifdef DEBUG kprintf("SendEnableSysMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset); @@ -2145,17 +2145,17 @@ ** ========================================================================= ** FillI2OMsgFromTCB() ** -** inputs pMsgU32 - virual pointer (mapped to physical) of message frame +** inputs pMsgu32 - virual pointer (mapped to physical) of message frame ** pXmitCntrlBlock - pointer to caller buffer control block. ** ** fills in LAN SGL after Transaction Control Word or Bucket Count. ** ========================================================================= */ static int -FillI2OMsgSGLFromTCB(PU32 pMsgFrame, PRCTCB pTransCtrlBlock) +FillI2OMsgSGLFromTCB(u32 * pMsgFrame, PRCTCB pTransCtrlBlock) { unsigned int nmbrBuffers, nmbrSeg, nmbrDwords, context, flags; - PU32 pTCB, pMsg; + u32 * pTCB, *pMsg; /* SGL element flags */ #define EOB 0x40000000 @@ -2163,7 +2163,7 @@ #define SIMPLE_SGL 0x10000000 #define BC_PRESENT 0x01000000 - pTCB = (PU32)pTransCtrlBlock; + pTCB = (u32 *)pTransCtrlBlock; pMsg = pMsgFrame; nmbrDwords = 0; @@ -2248,15 +2248,15 @@ ** ========================================================================= */ static void -ProcessOutboundI2OMsg(PPAB pPab, U32 phyAddrMsg) +ProcessOutboundI2OMsg(PPAB pPab, u32 phyAddrMsg) { - PU8 p8Msg; - PU32 p32; - // U16 count; + u8 * p8Msg; + u32 * p32; + // u16 count; p8Msg = pPab->pLinOutMsgBlock + (phyAddrMsg - pPab->outMsgBlockPhyAddr); - p32 = (PU32)p8Msg; + p32 = (u32 *)p8Msg; #ifdef DEBUG kprintf("VXD: ProcessOutboundI2OMsg - pPab 0x%08.8ulx, phyAdr 0x%08.8ulx, linAdr 0x%08.8ulx\n", pPab, phyAddrMsg, p8Msg); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/rclanmtl.h linux/drivers/net/rclanmtl.h --- v2.2.17/drivers/net/rclanmtl.h Fri Apr 21 23:18:12 2000 +++ linux/drivers/net/rclanmtl.h Sat Nov 18 18:01:24 2000 @@ -39,11 +39,7 @@ /* Linux specific includes */ #define kprintf printk -#ifdef RC_LINUX_MODULE /* linux modules need non-library version of string functions */ #include -#else -#include -#endif /* PCI/45 Configuration space values */ #define RC_PCI45_VENDOR_ID 0x4916 @@ -68,12 +64,6 @@ #define WARM_REBOOT_CAPABLE 0x01 /* scalar data types */ -typedef unsigned char U8; -typedef unsigned char* PU8; -typedef unsigned short U16; -typedef unsigned short* PU16; -typedef unsigned long U32; -typedef unsigned long* PU32; typedef unsigned long BF; typedef int RC_RETURN; @@ -97,10 +87,10 @@ ** The User's TransmitCallbackFunction should recover (put back in free queue) ** the packet buffers associated with the buffer context values. */ -typedef void (*PFNTXCALLBACK)(U32 Status, - U16 PcktCount, - PU32 BufferContext, - U16 AdaterID); +typedef void (*PFNTXCALLBACK)(u32 Status, + u16 PcktCount, + u32 * BufferContext, + u16 AdaterID); /* ** type PFNRXCALLBACK @@ -111,11 +101,11 @@ ** The received callback function should process the Packet Descriptor Block ** pointed to by PacketDescBlock. See Packet Decription Block below. */ -typedef void (*PFNRXCALLBACK)(U32 Status, - U8 PktCount, - U32 BucketsRemain, - PU32 PacketDescBlock, - U16 AdapterID); +typedef void (*PFNRXCALLBACK)(u32 Status, + u8 PktCount, + u32 BucketsRemain, + u32 * PacketDescBlock, + u16 AdapterID); /* ** type PFNCALLBACK @@ -125,10 +115,10 @@ ** the reset or shutdown is complete. ** Param1 and Param2 are invalid for LANReset and LANShutdown. */ -typedef void (*PFNCALLBACK)(U32 Status, - U32 Param1, - U32 Param2, - U16 AdapterID); +typedef void (*PFNCALLBACK)(u32 Status, + u32 Param1, + u32 Param2, + u16 AdapterID); /* ** Status - Transmit and Receive callback status word @@ -275,12 +265,12 @@ /* Buffer Segment Descriptor */ typedef struct { - U32 size; - U32 phyAddress; + u32 size; + u32 phyAddress; } BSD, *PBSD; -typedef PU32 PRCTCB; +typedef u32 * PRCTCB; /* ** ------------------------------------------------------------------------- ** Exported functions comprising the API to the LAN I2O message transport layer @@ -310,8 +300,8 @@ ** ReceiveCallbackFunction - address of user's RX callback function ** */ -RC_RETURN RCInitI2OMsgLayer(U16 AdapterID, U32 pciBaseAddr, - PU8 p_msgbuf, PU8 p_phymsgbuf, +RC_RETURN RCInitI2OMsgLayer(u16 AdapterID, u32 pciBaseAddr, + u8 * p_msgbuf, u8 * p_phymsgbuf, PFNTXCALLBACK TransmitCallbackFunction, PFNRXCALLBACK ReceiveCallbackFunction, PFNCALLBACK RebootCallbackFunction); @@ -326,7 +316,7 @@ ** 0x04030201 and 0x00FFFFFF on a little endian machine. ** */ -RC_RETURN RCSetRavlinIPandMask(U16 AdapterID, U32 ipAddr, U32 netMask); +RC_RETURN RCSetRavlinIPandMask(u16 AdapterID, u32 ipAddr, u32 netMask); /* @@ -338,7 +328,7 @@ ** ========================================================================= */ RC_RETURN -RCGetRavlinIPandMask(U16 AdapterID, PU32 pIpAddr, PU32 pNetMask, +RCGetRavlinIPandMask(u16 AdapterID, u32 * pIpAddr, u32 * pNetMask, PFNWAITCALLBACK WaitCallback); /* @@ -350,19 +340,19 @@ ** callback functions, TransmitCallbackFunction or ReceiveCallbackFunction, ** if a TX or RX transaction has completed. */ -void RCProcI2OMsgQ(U16 AdapterID); +void RCProcI2OMsgQ(u16 AdapterID); /* ** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time ** but can be disabled and re-enabled through these two function calls. - ** Packets will still be put into any posted recieved buffers and packets will + ** Packets will still be put into any posted received buffers and packets will ** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts ** will prevent hardware interrupt to host even though the outbound I2O msg ** queue is not emtpy. */ -RC_RETURN RCEnableI2OInterrupts(U16 adapterID); -RC_RETURN RCDisableI2OInterrupts(U16 AdapterID); +RC_RETURN RCEnableI2OInterrupts(u16 adapterID); +RC_RETURN RCDisableI2OInterrupts(u16 AdapterID); /* @@ -377,7 +367,7 @@ ** to the RedCreek adapter are considered owned by the adapter until the ** context is return to user through the ReceiveCallbackFunction. */ -RC_RETURN RCPostRecvBuffers(U16 AdapterID, PRCTCB pTransactionCtrlBlock); +RC_RETURN RCPostRecvBuffers(u16 AdapterID, PRCTCB pTransactionCtrlBlock); #define MAX_NMBR_POST_BUFFERS_PER_MSG 32 /* @@ -390,30 +380,30 @@ ** Transmit buffer are considered owned by the adapter until context's ** returned to user through the TransmitCallbackFunction. */ -RC_RETURN RCI2OSendPacket(U16 AdapterID, - U32 context, +RC_RETURN RCI2OSendPacket(u16 AdapterID, + u32 context, PRCTCB pTransactionCtrlBlock); /* Ethernet Link Statistics structure */ typedef struct tag_RC_link_stats { - U32 TX_good; /* good transmit frames */ - U32 TX_maxcol; /* frames not TX due to MAX collisions */ - U32 TX_latecol; /* frames not TX due to late collisions */ - U32 TX_urun; /* frames not TX due to DMA underrun */ - U32 TX_crs; /* frames TX with lost carrier sense */ - U32 TX_def; /* frames deferred due to activity on link */ - U32 TX_singlecol; /* frames TX with one and only on collision */ - U32 TX_multcol; /* frames TX with more than one collision */ - U32 TX_totcol; /* total collisions detected during TX */ - U32 Rcv_good; /* good frames received */ - U32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */ - U32 Rcv_alignerr; /* frames RX with alignment and CRC errors */ - U32 Rcv_reserr; /* good frames discarded due to no RX buffer */ - U32 Rcv_orun; /* RX frames lost due to FIFO overrun */ - U32 Rcv_cdt; /* RX frames with collision during RX */ - U32 Rcv_runt; /* RX frames shorter than 64 bytes */ + u32 TX_good; /* good transmit frames */ + u32 TX_maxcol; /* frames not TX due to MAX collisions */ + u32 TX_latecol; /* frames not TX due to late collisions */ + u32 TX_urun; /* frames not TX due to DMA underrun */ + u32 TX_crs; /* frames TX with lost carrier sense */ + u32 TX_def; /* frames deferred due to activity on link */ + u32 TX_singlecol; /* frames TX with one and only on collision */ + u32 TX_multcol; /* frames TX with more than one collision */ + u32 TX_totcol; /* total collisions detected during TX */ + u32 Rcv_good; /* good frames received */ + u32 Rcv_CRCerr; /* frames RX and discarded with CRC errors */ + u32 Rcv_alignerr; /* frames RX with alignment and CRC errors */ + u32 Rcv_reserr; /* good frames discarded due to no RX buffer */ + u32 Rcv_orun; /* RX frames lost due to FIFO overrun */ + u32 Rcv_cdt; /* RX frames with collision during RX */ + u32 Rcv_runt; /* RX frames shorter than 64 bytes */ } RCLINKSTATS, *P_RCLINKSTATS; @@ -424,7 +414,7 @@ ** If given, not NULL, the function WaitCallback is called during the wait ** loop while waiting for the adapter to respond. */ -RC_RETURN RCGetLinkStatistics(U16 AdapterID, +RC_RETURN RCGetLinkStatistics(u16 AdapterID, P_RCLINKSTATS StatsReturnAddr, PFNWAITCALLBACK WaitCallback); @@ -435,8 +425,8 @@ ** If given, not NULL, the function WaitCallback is called during the wait ** loop while waiting for the adapter to respond. */ -RC_RETURN RCGetLinkStatus(U16 AdapterID, - PU32 pReturnStatus, +RC_RETURN RCGetLinkStatus(u16 AdapterID, + u32 * pReturnStatus, PFNWAITCALLBACK WaitCallback); /* Link Status defines - value returned in pReturnStatus */ @@ -452,7 +442,7 @@ ** adapter runs in promiscous mode because of the dual address requirement. ** The MAC address is returned to the unsigned char array pointer to by mac. */ -RC_RETURN RCGetMAC(U16 AdapterID, PU8 mac, PFNWAITCALLBACK WaitCallback); +RC_RETURN RCGetMAC(u16 AdapterID, u8 * mac, PFNWAITCALLBACK WaitCallback); /* ** RCSetMAC() @@ -460,14 +450,14 @@ ** Set a new user port MAC address. This address will be returned on ** subsequent RCGetMAC() calls. */ -RC_RETURN RCSetMAC(U16 AdapterID, PU8 mac); +RC_RETURN RCSetMAC(u16 AdapterID, u8 * mac); /* ** RCSetLinkSpeed() ** ** set adapter's link speed based on given input code. */ -RC_RETURN RCSetLinkSpeed(U16 AdapterID, U16 LinkSpeedCode); +RC_RETURN RCSetLinkSpeed(u16 AdapterID, u16 LinkSpeedCode); /* Set link speed codes */ #define LNK_SPD_AUTO_NEG_NWAY 0 #define LNK_SPD_100MB_FULL 1 @@ -491,10 +481,10 @@ #define LNK_SPD_10MB_HALF 4 RC_RETURN -RCGetLinkSpeed(U16 AdapterID, PU32 pLinkSpeedCode, PFNWAITCALLBACK WaitCallback); +RCGetLinkSpeed(u16 AdapterID, u32 * pLinkSpeedCode, PFNWAITCALLBACK WaitCallback); /* ** ========================================================================= -** RCSetPromiscuousMode(U16 AdapterID, U16 Mode) +** RCSetPromiscuousMode(u16 AdapterID, u16 Mode) ** ** Defined values for Mode: ** 0 - turn off promiscuous mode @@ -505,10 +495,10 @@ #define PROMISCUOUS_MODE_OFF 0 #define PROMISCUOUS_MODE_ON 1 RC_RETURN -RCSetPromiscuousMode(U16 AdapterID, U16 Mode); +RCSetPromiscuousMode(u16 AdapterID, u16 Mode); /* ** ========================================================================= -** RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) +** RCGetPromiscuousMode(u16 AdapterID, u32 * pMode, PFNWAITCALLBACK WaitCallback) ** ** get promiscuous mode setting ** @@ -519,11 +509,11 @@ ** ========================================================================= */ RC_RETURN -RCGetPromiscuousMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback); +RCGetPromiscuousMode(u16 AdapterID, u32 * pMode, PFNWAITCALLBACK WaitCallback); /* ** ========================================================================= -** RCSetBroadcastMode(U16 AdapterID, U16 Mode) +** RCSetBroadcastMode(u16 AdapterID, u16 Mode) ** ** Defined values for Mode: ** 0 - turn off promiscuous mode @@ -534,10 +524,10 @@ #define BROADCAST_MODE_OFF 0 #define BROADCAST_MODE_ON 1 RC_RETURN -RCSetBroadcastMode(U16 AdapterID, U16 Mode); +RCSetBroadcastMode(u16 AdapterID, u16 Mode); /* ** ========================================================================= -** RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback) +** RCGetBroadcastMode(u16 AdapterID, u32 * pMode, PFNWAITCALLBACK WaitCallback) ** ** get broadcast mode setting ** @@ -548,10 +538,10 @@ ** ========================================================================= */ RC_RETURN -RCGetBroadcastMode(U16 AdapterID, PU32 pMode, PFNWAITCALLBACK WaitCallback); +RCGetBroadcastMode(u16 AdapterID, u32 * pMode, PFNWAITCALLBACK WaitCallback); /* ** ========================================================================= -** RCReportDriverCapability(U16 AdapterID, U32 capability) +** RCReportDriverCapability(u16 AdapterID, u32 capability) ** ** Currently defined bits: ** WARM_REBOOT_CAPABLE 0x01 @@ -559,7 +549,7 @@ ** ========================================================================= */ RC_RETURN -RCReportDriverCapability(U16 AdapterID, U32 capability); +RCReportDriverCapability(u16 AdapterID, u32 capability); /* ** RCGetFirmwareVer() @@ -569,7 +559,7 @@ ** WARNING: user's space pointed to by pFirmString should be at least 60 bytes. */ RC_RETURN -RCGetFirmwareVer(U16 AdapterID, PU8 pFirmString, PFNWAITCALLBACK WaitCallback); +RCGetFirmwareVer(u16 AdapterID, u8 * pFirmString, PFNWAITCALLBACK WaitCallback); /* ** ---------------------------------------------- @@ -600,7 +590,7 @@ ** operation if the receive buffers were returned during LANReset. ** Note: The IOP status is not affected by a LAN reset. */ -RC_RETURN RCResetLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction); +RC_RETURN RCResetLANCard(u16 AdapterID, u16 ResourceFlags, u32 * ReturnAddr, PFNCALLBACK CallbackFunction); /* @@ -622,7 +612,7 @@ ** Note: The IOP status is not affected by a LAN shutdown. */ RC_RETURN -RCShutdownLANCard(U16 AdapterID, U16 ResourceFlags, PU32 ReturnAddr, PFNCALLBACK CallbackFunction); +RCShutdownLANCard(u16 AdapterID, u16 ResourceFlags, u32 * ReturnAddr, PFNCALLBACK CallbackFunction); /* ** RCResetIOP(); @@ -632,6 +622,6 @@ ** Clears outbound message Q. */ RC_RETURN -RCResetIOP(U16 AdapterID); +RCResetIOP(u16 AdapterID); #endif /* RCLANMTL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c --- v2.2.17/drivers/net/rcpci45.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/rcpci45.c Fri Sep 29 10:11:45 2000 @@ -114,7 +114,7 @@ #define DEFAULT_RECV_INIT_CONTEXT 0xA17 -static U32 DriverControlWord = 0; +static u32 DriverControlWord = 0; static void rc_timer(unsigned long); @@ -131,10 +131,10 @@ struct device *dev; char devname[8]; /* "ethN" string */ - U8 id; /* the AdapterID */ - U32 pci_addr; /* the pci address of the adapter */ - U32 bus; - U32 function; + u8 id; /* the AdapterID */ + u32 pci_addr; /* the pci address of the adapter */ + u32 bus; + u32 function; struct timer_list timer; /* timer */ struct enet_statistics stats; /* the statistics structure */ struct device *next; /* points to the next RC adapter */ @@ -142,7 +142,7 @@ unsigned char shutdown; unsigned char reboot; unsigned char nexus; - PU8 PLanApiPA; /* Pointer to Lan Api Private Area */ + u8 * PLanApiPA; /* Pointer to Lan Api Private Area */ } DPA, *PDPA; @@ -169,10 +169,10 @@ static struct enet_statistics *RCget_stats(struct device *); static int RCioctl(struct device *, struct ifreq *, int); static int RCconfig(struct device *, struct ifmap *); -static void RCxmit_callback(U32, U16, PU32, U16); -static void RCrecv_callback(U32, U8, U32, PU32, U16); -static void RCreset_callback(U32, U32, U32, U16); -static void RCreboot_callback(U32, U32, U32, U16); +static void RCxmit_callback(u32, u16, u32 *, u16); +static void RCrecv_callback(u32, u8, u32, u32 *, u16); +static void RCreset_callback(u32, u32, u32, u16); +static void RCreboot_callback(u32, u32, u32, u16); static int RC_allocate_and_post_buffers(struct device *, int); @@ -405,14 +405,14 @@ if ( request_irq(dev->irq, (void *)RCinterrupt, SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev) ) { - printk( "RC PCI 45: %s: unable to get IRQ %d\n", (PU8)dev->name, (uint)dev->irq ); + printk( "RC PCI 45: %s: unable to get IRQ %d\n", (u8 *)dev->name, (uint)dev->irq ); iounmap(vaddr); kfree(dev); return 1; } init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr, - pDpa->PLanApiPA, (PU8)virt_to_bus((void *)pDpa->PLanApiPA), + pDpa->PLanApiPA, (u8 *)virt_to_bus((void *)pDpa->PLanApiPA), (PFNTXCALLBACK)RCxmit_callback, (PFNRXCALLBACK)RCrecv_callback, (PFNCALLBACK)RCreboot_callback); @@ -560,7 +560,7 @@ * we'll get the context when the adapter interrupts us to tell us that * the transmision is done. At that time, we can free skb. */ - ptcb->b.context = (U32)skb; + ptcb->b.context = (u32)skb; ptcb->b.scount = 1; ptcb->b.size = skb->len; ptcb->b.addr = virt_to_bus((void *)skb->data); @@ -569,7 +569,7 @@ printk("rc: RC xmit: skb = 0x%x, pDpa = 0x%x, id = %d, ptcb = 0x%x\n", (uint)skb, (uint)pDpa, (uint)pDpa->id, (uint)ptcb); #endif - if ( (status = RCI2OSendPacket(pDpa->id, (U32)NULL, (PRCTCB)ptcb)) + if ( (status = RCI2OSendPacket(pDpa->id, (u32)NULL, (PRCTCB)ptcb)) != RC_RTN_NO_ERROR) { #ifdef RCDEBUG @@ -600,10 +600,10 @@ * All we need to do is free the buffers. */ static void -RCxmit_callback(U32 Status, - U16 PcktCount, - PU32 BufferContext, - U16 AdapterID) +RCxmit_callback(u32 Status, + u16 PcktCount, + u32 * BufferContext, + u16 AdapterID) { struct sk_buff *skb; PDPA pDpa; @@ -649,7 +649,7 @@ } static void -RCreset_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID) +RCreset_callback(u32 Status, u32 p1, u32 p2, u16 AdapterID) { PDPA pDpa; struct device *dev; @@ -693,7 +693,7 @@ } static void -RCreboot_callback(U32 Status, U32 p1, U32 p2, U16 AdapterID) +RCreboot_callback(u32 Status, u32 p1, u32 p2, u16 AdapterID) { PDPA pDpa; @@ -742,14 +742,14 @@ * filled (one ethernet packet per buffer). */ static void -RCrecv_callback(U32 Status, - U8 PktCount, - U32 BucketsRemain, - PU32 PacketDescBlock, - U16 AdapterID) +RCrecv_callback(u32 Status, + u8 PktCount, + u32 BucketsRemain, + u32 * PacketDescBlock, + u16 AdapterID) { - U32 len, count; + u32 len, count; PDPA pDpa; struct sk_buff *skb; struct device *dev; @@ -845,7 +845,7 @@ * post one buffer at a time but ... may be that should be * optimized at some point. */ - ptcb->b.context = (U32)skb; + ptcb->b.context = (u32)skb; ptcb->b.scount = 1; ptcb->b.size = MAX_ETHER_SIZE; ptcb->b.addr = virt_to_bus((void *)skb->data); @@ -946,7 +946,7 @@ { init_status = RCInitI2OMsgLayer(pDpa->id, dev->base_addr, pDpa->PLanApiPA, - (PU8)virt_to_bus((void *)pDpa->PLanApiPA), + (u8 *)virt_to_bus((void *)pDpa->PLanApiPA), (PFNTXCALLBACK)RCxmit_callback, (PFNRXCALLBACK)RCrecv_callback, (PFNCALLBACK)RCreboot_callback); @@ -1180,7 +1180,7 @@ case RCUC_GETFWVER: printk("RC GETFWVER\n"); RCUD_GETFWVER = &RCuser.RCUS_GETFWVER; - RCGetFirmwareVer(pDpa->id, (PU8) &RCUD_GETFWVER->FirmString, NULL); + RCGetFirmwareVer(pDpa->id, (u8 *) &RCUD_GETFWVER->FirmString, NULL); break; case RCUC_GETINFO: printk("RC GETINFO\n"); @@ -1193,8 +1193,8 @@ case RCUC_GETIPANDMASK: printk("RC GETIPANDMASK\n"); RCUD_GETIPANDMASK = &RCuser.RCUS_GETIPANDMASK; - RCGetRavlinIPandMask(pDpa->id, (PU32) &RCUD_GETIPANDMASK->IpAddr, - (PU32) &RCUD_GETIPANDMASK->NetMask, NULL); + RCGetRavlinIPandMask(pDpa->id, (u32 *) &RCUD_GETIPANDMASK->IpAddr, + (u32 *) &RCUD_GETIPANDMASK->NetMask, NULL); break; case RCUC_GETLINKSTATISTICS: printk("RC GETLINKSTATISTICS\n"); @@ -1204,22 +1204,22 @@ case RCUC_GETLINKSTATUS: printk("RC GETLINKSTATUS\n"); RCUD_GETLINKSTATUS = &RCuser.RCUS_GETLINKSTATUS; - RCGetLinkStatus(pDpa->id, (PU32) &RCUD_GETLINKSTATUS->ReturnStatus, NULL); + RCGetLinkStatus(pDpa->id, (u32 *) &RCUD_GETLINKSTATUS->ReturnStatus, NULL); break; case RCUC_GETMAC: printk("RC GETMAC\n"); RCUD_GETMAC = &RCuser.RCUS_GETMAC; - RCGetMAC(pDpa->id, (PU8) &RCUD_GETMAC->mac, NULL); + RCGetMAC(pDpa->id, (u8 *) &RCUD_GETMAC->mac, NULL); break; case RCUC_GETPROM: printk("RC GETPROM\n"); RCUD_GETPROM = &RCuser.RCUS_GETPROM; - RCGetPromiscuousMode(pDpa->id, (PU32) &RCUD_GETPROM->PromMode, NULL); + RCGetPromiscuousMode(pDpa->id, (u32 *) &RCUD_GETPROM->PromMode, NULL); break; case RCUC_GETBROADCAST: printk("RC GETBROADCAST\n"); RCUD_GETBROADCAST = &RCuser.RCUS_GETBROADCAST; - RCGetBroadcastMode(pDpa->id, (PU32) &RCUD_GETBROADCAST->BroadcastMode, NULL); + RCGetBroadcastMode(pDpa->id, (u32 *) &RCUD_GETBROADCAST->BroadcastMode, NULL); break; case RCUC_GETSPEED: printk("RC GETSPEED\n"); @@ -1229,47 +1229,47 @@ return -ENODATA; } RCUD_GETSPEED = &RCuser.RCUS_GETSPEED; - RCGetLinkSpeed(pDpa->id, (PU32) &RCUD_GETSPEED->LinkSpeedCode, NULL); - printk("RC speed = 0x%ld\n", RCUD_GETSPEED->LinkSpeedCode); + RCGetLinkSpeed(pDpa->id, (u32 *) &RCUD_GETSPEED->LinkSpeedCode, NULL); + printk("RC speed = 0x%d\n", RCUD_GETSPEED->LinkSpeedCode); break; case RCUC_SETIPANDMASK: printk("RC SETIPANDMASK\n"); RCUD_SETIPANDMASK = &RCuser.RCUS_SETIPANDMASK; - printk ("RC New IP Addr = %d.%d.%d.%d, ", (U8) ((RCUD_SETIPANDMASK->IpAddr) & 0xff), - (U8) ((RCUD_SETIPANDMASK->IpAddr >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK->IpAddr >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK->IpAddr >> 24) & 0xff)); - printk ("RC New Mask = %d.%d.%d.%d\n", (U8) ((RCUD_SETIPANDMASK->NetMask) & 0xff), - (U8) ((RCUD_SETIPANDMASK->NetMask >> 8) & 0xff), - (U8) ((RCUD_SETIPANDMASK->NetMask >> 16) & 0xff), - (U8) ((RCUD_SETIPANDMASK->NetMask >> 24) & 0xff)); - RCSetRavlinIPandMask(pDpa->id, (U32) RCUD_SETIPANDMASK->IpAddr, - (U32) RCUD_SETIPANDMASK->NetMask); + printk ("RC New IP Addr = %d.%d.%d.%d, ", (u8) ((RCUD_SETIPANDMASK->IpAddr) & 0xff), + (u8) ((RCUD_SETIPANDMASK->IpAddr >> 8) & 0xff), + (u8) ((RCUD_SETIPANDMASK->IpAddr >> 16) & 0xff), + (u8) ((RCUD_SETIPANDMASK->IpAddr >> 24) & 0xff)); + printk ("RC New Mask = %d.%d.%d.%d\n", (u8) ((RCUD_SETIPANDMASK->NetMask) & 0xff), + (u8) ((RCUD_SETIPANDMASK->NetMask >> 8) & 0xff), + (u8) ((RCUD_SETIPANDMASK->NetMask >> 16) & 0xff), + (u8) ((RCUD_SETIPANDMASK->NetMask >> 24) & 0xff)); + RCSetRavlinIPandMask(pDpa->id, (u32) RCUD_SETIPANDMASK->IpAddr, + (u32) RCUD_SETIPANDMASK->NetMask); break; case RCUC_SETMAC: printk("RC SETMAC\n"); RCUD_SETMAC = &RCuser.RCUS_SETMAC; printk ("RC New MAC addr = %02X:%02X:%02X:%02X:%02X:%02X\n", - (U8) (RCUD_SETMAC->mac[0]), (U8) (RCUD_SETMAC->mac[1]), (U8) (RCUD_SETMAC->mac[2]), - (U8) (RCUD_SETMAC->mac[3]), (U8) (RCUD_SETMAC->mac[4]), (U8) (RCUD_SETMAC->mac[5])); - RCSetMAC(pDpa->id, (PU8) &RCUD_SETMAC->mac); + (u8) (RCUD_SETMAC->mac[0]), (u8) (RCUD_SETMAC->mac[1]), (u8) (RCUD_SETMAC->mac[2]), + (u8) (RCUD_SETMAC->mac[3]), (u8) (RCUD_SETMAC->mac[4]), (u8) (RCUD_SETMAC->mac[5])); + RCSetMAC(pDpa->id, (u8 *) &RCUD_SETMAC->mac); break; case RCUC_SETSPEED: printk("RC SETSPEED\n"); RCUD_SETSPEED = &RCuser.RCUS_SETSPEED; - RCSetLinkSpeed(pDpa->id, (U16) RCUD_SETSPEED->LinkSpeedCode); + RCSetLinkSpeed(pDpa->id, (u16) RCUD_SETSPEED->LinkSpeedCode); printk("RC New speed = 0x%d\n", RCUD_SETSPEED->LinkSpeedCode); break; case RCUC_SETPROM: printk("RC SETPROM\n"); RCUD_SETPROM = &RCuser.RCUS_SETPROM; - RCSetPromiscuousMode(pDpa->id,(U16)RCUD_SETPROM->PromMode); + RCSetPromiscuousMode(pDpa->id,(u16)RCUD_SETPROM->PromMode); printk("RC New prom mode = 0x%d\n", RCUD_SETPROM->PromMode); break; case RCUC_SETBROADCAST: printk("RC SETBROADCAST\n"); RCUD_SETBROADCAST = &RCuser.RCUS_SETBROADCAST; - RCSetBroadcastMode(pDpa->id,(U16)RCUD_SETBROADCAST->BroadcastMode); + RCSetBroadcastMode(pDpa->id,(u16)RCUD_SETBROADCAST->BroadcastMode); printk("RC New broadcast mode = 0x%d\n", RCUD_SETBROADCAST->BroadcastMode); break; default: @@ -1349,7 +1349,7 @@ int i; PDPA pDpa = (PDPA)dev->priv; - PU32 p; + u32 * p; psingleB pB; struct sk_buff *skb; RC_RETURN status; @@ -1365,7 +1365,7 @@ numBuffers = 32; } - p = (PU32) kmalloc(sizeof(U32) + numBuffers*sizeof(singleB), GFP_ATOMIC); + p = (u32 *) kmalloc(sizeof(u32) + numBuffers*sizeof(singleB), GFP_ATOMIC); #ifdef RCDEBUG printk("rc: TCB = 0x%x\n", (uint)p); @@ -1378,7 +1378,7 @@ } p[0] = 0; /* Buffer Count */ - pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */ + pB = (psingleB)((u32)p + sizeof(u32)); /* point to the first buffer */ #ifdef RCDEBUG printk("rc: p[0] = 0x%x, p = 0x%x, pB = 0x%x\n", (uint)p[0], (uint)p, (uint)pB); @@ -1408,7 +1408,7 @@ printk("post 0x%x\n", (uint)skb); #endif skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - pB->context = (U32)skb; + pB->context = (u32)skb; pB->scount = 1; /* segment count */ pB->size = MAX_ETHER_SIZE; pB->addr = virt_to_bus((void *)skb->data); @@ -1419,7 +1419,7 @@ if ( (status = RCPostRecvBuffers(pDpa->id, (PRCTCB)p )) != RC_RTN_NO_ERROR) { printk("rc: Post buffer failed with error code 0x%x!\n", status); - pB = (psingleB)((U32)p + sizeof(U32)); /* point to the first buffer */ + pB = (psingleB)((u32)p + sizeof(u32)); /* point to the first buffer */ while(p[0]) { skb = (struct sk_buff *)pB->context; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c --- v2.2.17/drivers/net/rtl8139.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/net/rtl8139.c Tue Sep 12 12:49:40 2000 @@ -1235,8 +1235,9 @@ /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ struct sk_buff *skb; + int pkt_size = rx_size - 4; - skb = dev_alloc_skb(rx_size + 2); + skb = dev_alloc_skb(pkt_size + 2); if (skb == NULL) { printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", dev->name); @@ -1247,12 +1248,12 @@ } skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset+rx_size+4 > RX_BUF_LEN) { + if (ring_offset+rx_size > RX_BUF_LEN) { int semi_count = RX_BUF_LEN - ring_offset - 4; memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], semi_count); - memcpy(skb_put(skb, rx_size-semi_count), rx_ring, - rx_size-semi_count); + memcpy(skb_put(skb, pkt_size-semi_count), rx_ring, + pkt_size-semi_count); if (rtl8129_debug > 4) { int i; printk(KERN_DEBUG"%s: Frame wrap @%d", @@ -1265,17 +1266,17 @@ } else { #if 1 /* USE_IP_COPYSUM */ eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], - rx_size - 4, 0); - skb_put(skb, rx_size - 4); + pkt_size, 0); + skb_put(skb, pkt_size); #else - memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4], - rx_size); + memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4], + pkt_size); #endif } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); #if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += rx_size; + tp->stats.rx_bytes += pkt_size; #endif tp->stats.rx_packets++; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/sbni.c linux/drivers/net/sbni.c --- v2.2.17/drivers/net/sbni.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/sbni.c Sat Dec 9 20:57:13 2000 @@ -342,7 +342,7 @@ if(base_addr > 0x1ff) /* Check a single specified location. */ return sbni_probe1(dev, base_addr); else if(base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for(i = 0; (base_addr = netcard_portlist[i]); i++) { if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1) @@ -353,7 +353,7 @@ return 0; } } - return ENODEV; + return -ENODEV; } #endif /* have devlist*/ @@ -416,7 +416,7 @@ } if(bad_card) - return ENODEV; + return -ENODEV; else outb(0, ioaddr + CSR0); if(dev->irq < 2) @@ -429,8 +429,8 @@ if(autoirq == 0) { - printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr); - return EAGAIN; + printk(KERN_ERR "sbni probe at %#x failed to detect IRQ line\n", ioaddr); + return -EAGAIN; } } /* clear FIFO buffer */ @@ -444,7 +444,7 @@ if (irqval) { printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); - return EAGAIN; + return -EAGAIN; } } @@ -456,6 +456,7 @@ if(dev->priv == NULL) { DP( printk("%s: cannot allocate memory\n", dev->name); ) + free_irq(dev->irq, dev); return -ENOMEM; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.2.17/drivers/net/sdla.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/sdla.c Thu Aug 31 15:20:28 2000 @@ -1218,7 +1218,10 @@ return(-ENOMEM); sdla_read(dev, mem.addr, temp, mem.len); if(copy_to_user(mem.data, temp, mem.len)) + { + kfree(temp); return -EFAULT; + } kfree(temp); } else @@ -1227,7 +1230,10 @@ if (!temp) return(-ENOMEM); if(copy_from_user(temp, mem.data, mem.len)) + { + kfree(temp); return -EFAULT; + } sdla_write(dev, mem.addr, temp, mem.len); kfree(temp); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.2.17/drivers/net/sis900.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/sis900.c Wed Nov 1 17:32:31 2000 @@ -1,8 +1,8 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.05 Aug 7 1999 - - Modified from the driver which is originally written by Donald Becker. + Revision: 1.06.05 Aug 24 2000 + + Modified from the driver which is originally written by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License (GPL), incorporated herein by reference. @@ -17,11 +17,13 @@ SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution, preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm - - Rev 1.06.02 Nov. 23 1999 Ollie Lho + + Rev 1.06.05 Aug. 22 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E equalier workaroung rule + 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 + 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 Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release */ @@ -41,7 +43,7 @@ #include #include -#include /* Processor type for cache alignment. */ +#include /* Processor type for cache alignment. */ #include #include #include @@ -49,22 +51,22 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.06.03 12/23/99\n"; +"sis900.c: v1.06.05 08/24/00\n"; static int max_interrupt_work = 20; +static int multicast_filter_limit = 128; + #define sis900_debug debug static int sis900_debug = 0; -static int multicast_filter_limit = 128; - /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (4*HZ) struct mac_chip_info { - const char *name; - u16 vendor_id, device_id, flags; - int io_size; - struct device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev, + const char *name; + u16 vendor_id, device_id, flags; + int io_size; + struct device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev, struct device * net_dev); }; static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, @@ -75,7 +77,7 @@ PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe}, { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016, PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe}, - {0,}, /* 0 terminated list. */ + {0,}, /* 0 terminated list. */ }; static void sis900_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex); @@ -102,37 +104,38 @@ }; typedef struct _BufferDesc { - u32 link; - u32 cmdsts; - u32 bufptr; + u32 link; + u32 cmdsts; + u32 bufptr; } BufferDesc; struct sis900_private { - struct device *next_module; - struct net_device_stats stats; + struct device *next_module; + struct net_device_stats stats; struct pci_dev * pci_dev; struct mac_chip_info * mac; struct mii_phy * mii; unsigned int cur_phy; - struct timer_list timer; /* Link status detection timer. */ - unsigned int cur_rx, dirty_rx; - unsigned int cur_tx, dirty_tx; + struct timer_list timer; /* Link status detection timer. */ + + unsigned int cur_rx, dirty_rx; /* producer/comsumer pointers for Tx/Rx ring */ + unsigned int cur_tx, dirty_tx; - /* The saved address of a sent/receive-in-place packet buffer */ - struct sk_buff *tx_skbuff[NUM_TX_DESC]; + /* The saved address of a sent/receive-in-place packet buffer */ + struct sk_buff *tx_skbuff[NUM_TX_DESC]; struct sk_buff *rx_skbuff[NUM_RX_DESC]; - BufferDesc tx_ring[NUM_TX_DESC]; - BufferDesc rx_ring[NUM_RX_DESC]; - unsigned int tx_full; /* The Tx queue is full. */ + BufferDesc tx_ring[NUM_TX_DESC]; + BufferDesc rx_ring[NUM_RX_DESC]; - int LinkOn; + unsigned int tx_full; /* The Tx queue is full. */ + int LinkOn; }; #ifdef MODULE #if LINUX_VERSION_CODE > 0x20115 -MODULE_AUTHOR("Jim Huang "); +MODULE_AUTHOR("Jim Huang , Ollie Lho "); MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver"); MODULE_PARM(multicast_filter_limit, "i"); MODULE_PARM(max_interrupt_work, "i"); @@ -161,6 +164,7 @@ static u16 sis900_compute_hashtable_index(u8 *addr); static void set_rx_mode(struct device *net_dev); static void sis900_reset(struct device *net_dev); +static void sis630e_set_eq(struct device *net_dev); /* A list of all installed SiS900 devices, for removing the driver module. */ static struct device *root_sis900_dev = NULL; @@ -170,10 +174,10 @@ { int found = 0; struct pci_dev * pci_dev = NULL; - + if (!pci_present()) return -ENODEV; - + while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) { /* pci_dev contains all ethernet devices */ u32 pci_io_base; @@ -185,23 +189,23 @@ pci_dev->device == mac->device_id) break; } - + if (mac->vendor_id == 0) /* pci_dev does not match any of our cards */ continue; - + /* now, pci_dev should be either 900 or 7016 */ pci_io_base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; - if ((mac->flags & PCI_COMMAND_IO ) && + if ((mac->flags & PCI_COMMAND_IO ) && check_region(pci_io_base, mac->io_size)) continue; - + /* setup various bits in PCI command register */ pci_set_master(pci_dev); /* do the real low level jobs */ net_dev = mac->probe(mac, pci_dev, net_dev); - + if (net_dev != NULL) { found++; } @@ -210,15 +214,83 @@ return found ? 0 : -ENODEV; } -static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, +/* older SiS900 and friends, use EEPROM to store MAC address */ +static int sis900_get_mac_addr(struct pci_dev * pci_dev, struct device *net_dev) +{ + long ioaddr = pci_dev->base_address[0] & ~3; + u16 signature; + int i; + + /* check to see if we have sane EEPROM */ + signature = (u16) read_eeprom(ioaddr, EEPROMSignature); + if (signature == 0xffff || signature == 0x0000) { + printk (KERN_INFO "%s: Error EERPOM read %x\n", + net_dev->name, signature); + return 0; + } + + /* get MAC address from EEPROM */ + for (i = 0; i < 3; i++) + ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + + return 1; +} + +/* SiS630E model, use APC CMOS RAM to store MAC address */ +static int sis630e_get_mac_addr(struct pci_dev * pci_dev, struct device *net_dev) +{ + struct pci_dev *isa_bridge = NULL; + u8 reg; + int i; + + if ((isa_bridge = pci_find_device(0x1039, 0x0008, isa_bridge)) == NULL) { + printk("%s: Can not find ISA bridge\n", net_dev->name); + return 0; + } + pci_read_config_byte(isa_bridge, 0x48, ®); + pci_write_config_byte(isa_bridge, 0x48, reg | 0x40); + + for (i = 0; i < 6; i++) { + outb(0x09 + i, 0x70); + ((u8 *)(net_dev->dev_addr))[i] = inb(0x71); + } + pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40); + + return 1; +} + +/* SiS630E A1, The Mac address is hardcoded in the RFCR register so it is actually not necessary to + probe the MAC address */ +static int sis630ea1_get_mac_addr(struct pci_dev * pci_dev, struct device *net_dev) +{ + long ioaddr = pci_dev->base_address[0] & ~3; + u32 reg; + int i; + + /* reload MAC address */ + reg = inl(ioaddr + cr); + outl(reg | RELOAD, ioaddr + cr); + + reg = inl(ioaddr + cr); + outl(reg & ~RELOAD, ioaddr + cr); + + for (i = 0; i < 3; i++) { + outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); + ((u16 *)(net_dev->dev_addr))[i] = inl(ioaddr + rfdr); + } + + return 1; +} + +static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, struct device * net_dev) { struct sis900_private *sis_priv; long ioaddr = pci_dev->base_address[0] & ~3; int irq = pci_dev->irq; static int did_version = 0; - u16 signature; - int i; + u8 revision; + int i, ret = 0; if (did_version++ == 0) printk(KERN_INFO "%s", version); @@ -226,21 +298,24 @@ 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) { - printk (KERN_INFO "%s: Error EEPROM read: %x\n", - net_dev->name, signature); + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV) + ret = sis630e_get_mac_addr(pci_dev, net_dev); + else if (revision == SIS630EA1_REV) { + ret = sis630e_get_mac_addr(pci_dev, net_dev); + printk(KERN_INFO "using 630ea1\n"); + } + else + ret = sis900_get_mac_addr(pci_dev, net_dev); + + if (ret == 0) { unregister_netdevice(net_dev); return NULL; } + /* print some information about our NIC */ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name, ioaddr, irq); - - /* get MAC address from EEPROM */ - for (i = 0; i < 3; i++) - ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); for (i = 0; i < 5; i++) printk("%2.2x:", (u8)net_dev->dev_addr[i]); printk("%2.2x.\n", net_dev->dev_addr[i]); @@ -286,247 +361,268 @@ { struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv; int phy_addr; - + u8 revision; + sis_priv->mii = NULL; - + /* search for total of 32 possible mii phy addresses */ for (phy_addr = 0; phy_addr < 32; phy_addr++) { u16 mii_status; u16 phy_id0, phy_id1; int i; - + mii_status = mdio_read(net_dev, phy_addr, MII_STATUS); if (mii_status == 0xffff || mii_status == 0x0000) /* the mii is not accessable, try next one */ continue; - + phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0); phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1); - + /* search our mii table for the current mii */ for (i = 0; mii_chip_table[i].phy_id1; i++) if (phy_id0 == mii_chip_table[i].phy_id0) { struct mii_phy * mii_phy; - - printk(KERN_INFO + + printk(KERN_INFO "%s: %s transceiver found at address %d.\n", - net_dev->name, mii_chip_table[i].name, + net_dev->name, mii_chip_table[i].name, phy_addr);; if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { mii_phy->chip_info = mii_chip_table+i; mii_phy->phy_addr = phy_addr; - mii_phy->status = mdio_read(net_dev, phy_addr, + mii_phy->status = mdio_read(net_dev, phy_addr, MII_STATUS); mii_phy->next = sis_priv->mii; sis_priv->mii = mii_phy; } - /* the current mii is on our mii_info_table, + /* the current mii is on our mii_info_table, try next address */ break; } } - + if (sis_priv->mii == NULL) { - printk(KERN_INFO "%s: No MII transceivers found!\n", + printk(KERN_INFO "%s: No MII transceivers found!\n", net_dev->name); return 0; } - /* arbitrary choose that last PHY and current PHY */ + /* arbitrary choose that last PHY as current PHY */ sis_priv->cur_phy = sis_priv->mii->phy_addr; printk(KERN_INFO "%s: Using %s as default\n", net_dev->name, sis_priv->mii->chip_info->name); - if (sis_priv->mii->status & MII_STAT_LINK) + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV) { + /* SiS 630E has some bugs on default value of PHY registers */ + mdio_write(net_dev, sis_priv->cur_phy, MII_ANADV, 0x05e1); + mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22); + mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00); + mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0); + mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000); + } + + if (sis_priv->mii->status & MII_STAT_LINK) sis_priv->LinkOn = TRUE; else sis_priv->LinkOn = FALSE; - + return 1; } /* Delay between EEPROM clock transitions. */ -#define eeprom_delay() inl(ee_addr) +#define eeprom_delay() inl(ee_addr) -/* Read Serial EEPROM through EEPROM Access Register, Note that location is +/* Read Serial EEPROM through EEPROM Access Register, Note that location is in word (16 bits) unit */ static u16 read_eeprom(long ioaddr, int location) { int i; - u16 retval = 0; - long ee_addr = ioaddr + mear; - u32 read_cmd = location | EEread; - - outl(0, ee_addr); - eeprom_delay(); - outl(EECLK, ee_addr); - eeprom_delay(); - - /* Shift the read command (9) bits out. */ - for (i = 8; i >= 0; i--) { - u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; - outl(dataval, ee_addr); - eeprom_delay(); - outl(dataval | EECLK, ee_addr); - eeprom_delay(); - } - outb(EECS, ee_addr); - eeprom_delay(); + u16 retval = 0; + long ee_addr = ioaddr + mear; + u32 read_cmd = location | EEread; + + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); + eeprom_delay(); + + /* Shift the read command (9) bits out. */ + for (i = 8; i >= 0; i--) { + u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS; + outl(dataval, ee_addr); + eeprom_delay(); + outl(dataval | EECLK, ee_addr); + eeprom_delay(); + } + outb(EECS, ee_addr); + eeprom_delay(); /* read the 16-bits data in */ - for (i = 16; i > 0; i--) { - outl(EECS, ee_addr); - eeprom_delay(); - outl(EECS | EECLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outl(0, ee_addr); - eeprom_delay(); - outl(EECLK, ee_addr); + for (i = 16; i > 0; i--) { + outl(EECS, ee_addr); + eeprom_delay(); + outl(EECS | EECLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(0, ee_addr); + eeprom_delay(); + outl(EECLK, ee_addr); - return (retval); + return (retval); } /* Read and write the MII management registers using software-generated serial MDIO protocol. Note that the command bits and data bits are send out seperately */ -#define mdio_delay() inl(mdio_addr) +#define mdio_delay() inl(mdio_addr) static void mdio_idle(long mdio_addr) { - outl(MDIO | MDDIR, mdio_addr); - mdio_delay(); - outl(MDIO | MDDIR | MDC, mdio_addr); + outl(MDIO | MDDIR, mdio_addr); + mdio_delay(); + outl(MDIO | MDDIR | MDC, mdio_addr); } /* Syncronize the MII management interface by shifting 32 one bits out. */ static void mdio_reset(long mdio_addr) { - int i; + int i; - for (i = 31; i >= 0; i--) { - outl(MDDIR | MDIO, mdio_addr); - mdio_delay(); - outl(MDDIR | MDIO | MDC, mdio_addr); - mdio_delay(); - } - return; + for (i = 31; i >= 0; i--) { + outl(MDDIR | MDIO, mdio_addr); + mdio_delay(); + outl(MDDIR | MDIO | MDC, mdio_addr); + mdio_delay(); + } + return; } static u16 mdio_read(struct device *net_dev, int phy_id, int location) { - long mdio_addr = net_dev->base_addr + mear; - int mii_cmd = MIIread|(phy_id<= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; - outl(dataval, mdio_addr); + long mdio_addr = net_dev->base_addr + mear; + int mii_cmd = MIIread|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outl(dataval, mdio_addr); mdio_delay(); - outl(dataval | MDC, mdio_addr); + outl(dataval | MDC, mdio_addr); mdio_delay(); - } + } - /* Read the 16 data bits. */ - for (i = 16; i > 0; i--) { - outl(0, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); - outl(MDC, mdio_addr); - mdio_delay(); - } - return retval; + /* Read the 16 data bits. */ + for (i = 16; i > 0; i--) { + outl(0, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0); + outl(MDC, mdio_addr); + mdio_delay(); + } + outl(0x00, mdio_addr); + + return retval; } static void mdio_write(struct device *net_dev, int phy_id, int location, int value) { - long mdio_addr = net_dev->base_addr + mear; - int mii_cmd = MIIwrite|(phy_id<= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; - outb(dataval, mdio_addr); - mdio_delay(); - outb(dataval | MDC, mdio_addr); - mdio_delay(); - } - mdio_delay(); + long mdio_addr = net_dev->base_addr + mear; + int mii_cmd = MIIwrite|(phy_id<= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR; + outb(dataval, mdio_addr); + mdio_delay(); + outb(dataval | MDC, mdio_addr); + mdio_delay(); + } + mdio_delay(); /* Shift the value bits out. */ for (i = 15; i >= 0; i--) { int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR; - outl(dataval, mdio_addr); - mdio_delay(); - outl(dataval | MDC, mdio_addr); - mdio_delay(); + outl(dataval, mdio_addr); + mdio_delay(); + outl(dataval | MDC, mdio_addr); + mdio_delay(); } mdio_delay(); - - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - outb(MDC, mdio_addr); - mdio_delay(); - } - return; + + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outb(0, mdio_addr); + mdio_delay(); + outb(MDC, mdio_addr); + mdio_delay(); + } + outl(0x00, mdio_addr); + + return; } static int sis900_open(struct device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + u8 revision; - /* Soft reset the chip. */ + /* Soft reset the chip. */ sis900_reset(net_dev); + + /* Equalizer workaroung Rule */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV || revision == SIS630EA1_REV) + sis630e_set_eq(net_dev); + + if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) { + return -EAGAIN; + } - if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) { - return -EAGAIN; - } - - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; sis900_init_rxfilter(net_dev); sis900_init_tx_ring(net_dev); sis900_init_rx_ring(net_dev); - set_rx_mode(net_dev); + set_rx_mode(net_dev); - net_dev->tbusy = 0; - net_dev->interrupt = 0; - net_dev->start = 1; + net_dev->tbusy = 0; + net_dev->interrupt = 0; + net_dev->start = 1; - /* Enable all known interrupts by setting the interrupt mask. */ + /* Enable all known interrupts by setting the interrupt mask. */ outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); - outl(RxENA, ioaddr + cr); - outl(IE, ioaddr + ier); + outl(RxENA, ioaddr + cr); + outl(IE, ioaddr + ier); sis900_check_mode(net_dev, sis_priv->mii); - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&sis_priv->timer); - sis_priv->timer.expires = jiffies + HZ; - sis_priv->timer.data = (unsigned long)net_dev; - sis_priv->timer.function = &sis900_timer; - add_timer(&sis_priv->timer); + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&sis_priv->timer); + sis_priv->timer.expires = jiffies + HZ; + sis_priv->timer.data = (unsigned long)net_dev; + sis_priv->timer.function = &sis900_timer; + add_timer(&sis_priv->timer); - return 0; + return 0; } /* set receive filter address to our MAC address */ @@ -536,7 +632,7 @@ long ioaddr = net_dev->base_addr; u32 rfcrSave; u32 i; - + rfcrSave = inl(rfcr + ioaddr); /* disable packet filtering before setting filter */ @@ -564,38 +660,38 @@ static void sis900_init_tx_ring(struct device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; - int i; - - sis_priv->tx_full = 0; - sis_priv->dirty_tx = sis_priv->cur_tx = 0; - - for (i = 0; i < NUM_TX_DESC; i++) { + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + int i; + + sis_priv->tx_full = 0; + sis_priv->dirty_tx = sis_priv->cur_tx = 0; + + for (i = 0; i < NUM_TX_DESC; i++) { sis_priv->tx_skbuff[i] = NULL; sis_priv->tx_ring[i].link = (u32) virt_to_bus(&sis_priv->tx_ring[i+1]); - sis_priv->tx_ring[i].cmdsts = 0; + sis_priv->tx_ring[i].cmdsts = 0; sis_priv->tx_ring[i].bufptr = 0; - } + } sis_priv->tx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->tx_ring[0]); /* load Transmit Descriptor Register */ - outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); + outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); if (sis900_debug > 2) - printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", + printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + txdp)); } -/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */ +/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */ static void -sis900_init_rx_ring(struct device *net_dev) -{ - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; - int i; - - sis_priv->cur_rx = 0; +sis900_init_rx_ring(struct device *net_dev) +{ + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + int i; + + sis_priv->cur_rx = 0; sis_priv->dirty_rx = 0; /* init RX descriptor */ @@ -608,14 +704,14 @@ } sis_priv->rx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->rx_ring[0]); - /* allocate sock buffers */ + /* allocate sock buffers */ for (i = 0; i < NUM_RX_DESC; i++) { struct sk_buff *skb; if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { /* not enough memory for skbuff, this makes a "hole" - on the buffer ring, it is not clear how the - hardware will react to this kind of degenerated + on the buffer ring, it is not clear how the + hardware will react to this kind of degenerated buffer */ break; } @@ -627,31 +723,97 @@ sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC); /* load Receive Descriptor Register */ - outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp); + outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp); if (sis900_debug > 2) - printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", + printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + rxdp)); } + +/* 630E equalizer workaroung rule(Cyrus Huang 08/15) + PHY register 14h(Test) + Bit 14: 0 -- Automatically dectect (default) + 1 -- Manually set Equalizer filter + Bit 13: 0 -- (Default) + 1 -- Speed up convergence of equalizer setting + Bit 9 : 0 -- (Default) + 1 -- Disable Baseline Wander + Bit 3~7 -- Equalizer filter setting + + Link ON: Set Bit 9, 13 to 1, Bit 14 to 0 + Then calculate equalizer value + Then set equalizer value, and set Bit 14 to 1, Bit 9 to 0 + Link Off:Set Bit 13 to 1, Bit 14 to 0 + + Calculate Equalizer value: + When Link is ON and Bit 14 is 0, SIS900PHY will auto-dectect proper equalizer value. + When the equalizer is stable, this value is not a fixed value. It will be within + a small range(eg. 7~9). Then we get a minimum and a maximum value(eg. min=7, max=9) + 0 <= max <= 4 --> set equalizer to max + 5 <= max <= 14 --> set equalizer to max+1 or + set equalizer to max+2 if max == min + max >= 15 --> set equalizer to max+5 or + set equalizer to max+6 if max == min +*/ +static void sis630e_set_eq(struct device *net_dev) +{ + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + u16 reg14h, eq_value, max_value=0, min_value=0; + int i, maxcount=10; + + if (sis_priv->LinkOn == TRUE) { + reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF); + for (i=0; i < maxcount; i++) { + eq_value=(0x00F8 & mdio_read(net_dev, sis_priv->cur_phy, MII_RESV)) >> 3; + max_value=(eq_value > max_value) ? eq_value : max_value; + min_value=(eq_value < min_value) ? eq_value : min_value; + } + if (max_value < 5) + eq_value=max_value; + else if (max_value >= 5 && max_value < 15) + eq_value=(max_value == min_value) ? max_value+2 : max_value+1; + else if (max_value >= 15) + eq_value=(max_value == min_value) ? max_value+6 : max_value+5; + reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + reg14h=(reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8); + reg14h=(reg14h | 0x6000) & 0xFDFF; + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h); + } + else { + reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF); + } + return; +} + /* on each timer ticks we check two things, Link Status (ON/OFF) and Link Mode (10/100/Full/Half) */ static void sis900_timer(unsigned long data) { - struct device *net_dev = (struct device *)data; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct device *net_dev = (struct device *)data; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; struct mii_phy *mii_phy = sis_priv->mii; - static int next_tick = 5*HZ; - u16 status; + static int next_tick = 5*HZ; + u16 status; + u8 revision; status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); + status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); /* current mii phy is failed to link, try another one */ - while (!(status & MII_STAT_LINK)) { - if (mii_phy->next == NULL) { + while (!(status & MII_STAT_LINK)) { + if (mii_phy->next == NULL) { if (sis_priv->LinkOn) { /* link stat change from ON to OFF */ next_tick = HZ; sis_priv->LinkOn = FALSE; + + /* Equalizer workaroung Rule */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV || revision == SIS630EA1_REV) + sis630e_set_eq(net_dev); + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); } @@ -667,19 +829,28 @@ /* link stat change forn OFF to ON, read and report link mode */ sis_priv->LinkOn = TRUE; next_tick = 5*HZ; + + /* Equalizer workaroung Rule */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV || revision == SIS630EA1_REV) + sis630e_set_eq(net_dev); + /* change what cur_phy means */ if (mii_phy->phy_addr != sis_priv->cur_phy) { - printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name, - mii_phy->chip_info->name); + printk(KERN_INFO "%s: Changing transceiver to %s\n", + net_dev->name, mii_phy->chip_info->name); + /* disable previous PHY */ status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); - mdio_write(net_dev, sis_priv->cur_phy, + mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status | MII_CNTL_ISOLATE); + /* enable next PHY */ status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL); - mdio_write(net_dev, mii_phy->phy_addr, + mdio_write(net_dev, mii_phy->phy_addr, MII_CONTROL, status & ~MII_CNTL_ISOLATE); sis_priv->cur_phy = mii_phy->phy_addr; } sis900_check_mode(net_dev, mii_phy); + } sis_priv->timer.expires = jiffies + next_tick; @@ -688,7 +859,7 @@ static void sis900_check_mode (struct device *net_dev, struct mii_phy *mii_phy) { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; + long ioaddr = net_dev->base_addr; int speed, duplex; u32 tx_flags = 0, rx_flags = 0; @@ -718,7 +889,7 @@ { int i = 0; u32 status; - + /* STSOUT register is Latched on Transition, read operation updates it */ while (i++ < 2) status = mdio_read(net_dev, phy_addr, MII_STSOUT); @@ -736,9 +907,9 @@ if (status & MII_STSOUT_LINK_FAIL) printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); else - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", net_dev->name, - *speed == HW_SPEED_100_MBPS ? + *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half"); @@ -747,7 +918,7 @@ { int i; u16 status; - + for (i = 0; i < 2; i++) status = mdio_read(net_dev, phy_addr, MII_STATUS); @@ -765,9 +936,9 @@ *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STSSUM_LINK) - printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", net_dev->name, - *speed == HW_SPEED_100_MBPS ? + *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half"); @@ -779,7 +950,7 @@ *speed = HW_SPEED_HOME; *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STAT_LINK) - printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", + printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", net_dev->name); else printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); @@ -787,188 +958,189 @@ } static void sis900_tx_timeout(struct device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; + 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)); - - /* Disable interrupts by clearing the interrupt mask. */ - outl(0x0000, ioaddr + imr); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); /* 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; + 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; + net_dev->trans_start = jiffies; net_dev->tbusy = sis_priv->tx_full = 0; /* FIXME: Should we restart the transmission thread here ?? */ + outl(TxENA, ioaddr + cr); - /* Enable all known interrupts by setting the interrupt mask. */ + /* Enable all known interrupts by setting the interrupt mask. */ outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); - return; + return; } static int sis900_start_xmit(struct sk_buff *skb, struct device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; - unsigned int entry; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; + unsigned int entry; /* test tbusy to see if we have timeout situation then set it */ - if (test_and_set_bit(0, (void*)&net_dev->tbusy) != 0) { - if (jiffies - net_dev->trans_start > TX_TIMEOUT) + if (test_and_set_bit(0, (void*)&net_dev->tbusy) != 0) { + if (jiffies - net_dev->trans_start > TX_TIMEOUT) sis900_tx_timeout(net_dev); - return 1; - } + return 1; + } - /* Calculate the next Tx descriptor entry. */ - entry = sis_priv->cur_tx % NUM_TX_DESC; - sis_priv->tx_skbuff[entry] = skb; + /* Calculate the next Tx descriptor entry. */ + entry = sis_priv->cur_tx % NUM_TX_DESC; + sis_priv->tx_skbuff[entry] = skb; /* set the transmit buffer descriptor and enable Transmit State Machine */ sis_priv->tx_ring[entry].bufptr = virt_to_bus(skb->data); - sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len); - outl(TxENA, ioaddr + cr); + sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len); + outl(TxENA, ioaddr + cr); - if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) { + if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) { /* Typical path, clear tbusy to indicate more transmission is possible */ - clear_bit(0, (void*)&net_dev->tbusy); - } else { + clear_bit(0, (void*)&net_dev->tbusy); + } else { /* no more transmit descriptor avaiable, tbusy remain set */ - sis_priv->tx_full = 1; - } + sis_priv->tx_full = 1; + } - net_dev->trans_start = jiffies; + net_dev->trans_start = jiffies; - if (sis900_debug > 3) - printk(KERN_INFO "%s: Queued Tx packet at %p size %d " + if (sis900_debug > 3) + printk(KERN_INFO "%s: Queued Tx packet at %p size %d " "to slot %d.\n", net_dev->name, skb->data, (int)skb->len, entry); - return 0; + return 0; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct device *net_dev = (struct device *)dev_instance; - int boguscnt = max_interrupt_work; + struct device *net_dev = (struct device *)dev_instance; + int boguscnt = max_interrupt_work; long ioaddr = net_dev->base_addr; u32 status; #if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&net_dev->interrupt)) { - printk(KERN_INFO "%s: SMP simultaneous entry of " + /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ + if (test_and_set_bit(0, (void*)&net_dev->interrupt)) { + printk(KERN_INFO "%s: SMP simultaneous entry of " "an interrupt handler.\n", net_dev->name); - net_dev->interrupt = 0; /* Avoid halting machine. */ - return; - } + net_dev->interrupt = 0; /* Avoid halting machine. */ + return; + } #else - if (net_dev->interrupt) { - printk(KERN_INFO "%s: Re-entering the interrupt handler.\n", + if (net_dev->interrupt) { + printk(KERN_INFO "%s: Re-entering the interrupt handler.\n", net_dev->name); - return; - } - net_dev->interrupt = 1; + return; + } + net_dev->interrupt = 1; #endif - do { - status = inl(ioaddr + isr); - + do { + status = inl(ioaddr + isr); + if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0) /* nothing intresting happened */ - break; + break; /* why dow't we break after Tx/Rx case ?? keyword: full-duplex */ - if (status & (RxORN | RxERR | RxOK)) + if (status & (RxORN | RxERR | RxOK)) /* Rx interrupt */ - sis900_rx(net_dev); + sis900_rx(net_dev); if (status & (TxURN | TxERR | TxIDLE)) /* Tx interrupt */ sis900_finish_xmit(net_dev); - /* something strange happened !!! */ - if (status & HIBERR) { + /* something strange happened !!! */ + if (status & HIBERR) { printk(KERN_INFO "%s: Abnormal interrupt," "status %#8.8x.\n", net_dev->name, status); break; } - if (--boguscnt < 0) { - printk(KERN_INFO "%s: Too much work at interrupt, " + if (--boguscnt < 0) { + printk(KERN_INFO "%s: Too much work at interrupt, " "interrupt status = %#8.8x.\n", net_dev->name, status); - break; - } - } while (1); - - if (sis900_debug > 3) - printk(KERN_INFO "%s: exiting interrupt, " + break; + } + } while (1); + + if (sis900_debug > 3) + printk(KERN_INFO "%s: exiting interrupt, " "interrupt status = 0x%#8.8x.\n", net_dev->name, inl(ioaddr + isr)); #if defined(__i386__) - clear_bit(0, (void*)&net_dev->interrupt); + clear_bit(0, (void*)&net_dev->interrupt); #else - net_dev->interrupt = 0; + net_dev->interrupt = 0; #endif - return; + return; } /* Process receive interrupt events, put buffer to higher layer and refill buffer pool Note: This fucntion is called by interrupt handler, don't do "too much" work here */ static int sis900_rx(struct device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - long ioaddr = net_dev->base_addr; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; - u32 rx_status = sis_priv->rx_ring[entry].cmdsts; - - if (sis900_debug > 3) - printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " + u32 rx_status = sis_priv->rx_ring[entry].cmdsts; + + if (sis900_debug > 3) + printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", - sis_priv->cur_rx, sis_priv->dirty_rx,rx_status); - - while (rx_status & OWN) { - unsigned int rx_size; - + sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); + + while (rx_status & OWN) { + unsigned int rx_size; + rx_size = (rx_status & DSIZE) - CRC_SIZE; - + if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { /* corrupted packet received */ - if (sis900_debug > 3) - printk(KERN_INFO "%s: Corrupted packet " + if (sis900_debug > 3) + printk(KERN_INFO "%s: Corrupted packet " "received, buffer status = 0x%8.8x.\n", net_dev->name, rx_status); - sis_priv->stats.rx_errors++; + sis_priv->stats.rx_errors++; if (rx_status & OVERRUN) sis_priv->stats.rx_over_errors++; if (rx_status & (TOOLONG|RUNT)) - sis_priv->stats.rx_length_errors++; - if (rx_status & (RXISERR | FAERR)) - sis_priv->stats.rx_frame_errors++; + sis_priv->stats.rx_length_errors++; + if (rx_status & (RXISERR | FAERR)) + sis_priv->stats.rx_frame_errors++; if (rx_status & CRCERR) sis_priv->stats.rx_crc_errors++; /* reset buffer descriptor state */ sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; - } else { + } 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 :-( */ @@ -976,41 +1148,62 @@ printk(KERN_INFO "%s: NULL pointer " "encountered in Rx ring, skipping\n", net_dev->name); - break; + break; } + + /* gvie the socket buffer to upper layers */ skb = sis_priv->rx_skbuff[entry]; - sis_priv->rx_skbuff[entry] = NULL; - /* reset buffer descriptor state */ - sis_priv->rx_ring[entry].cmdsts = 0; - sis_priv->rx_ring[entry].bufptr = 0; - skb_put(skb, rx_size); - skb->protocol = eth_type_trans(skb, net_dev); - netif_rx(skb); - + skb->protocol = eth_type_trans(skb, net_dev); + netif_rx(skb); + + /* some network statistics */ if ((rx_status & BCAST) == MCAST) sis_priv->stats.multicast++; net_dev->last_rx = jiffies; - sis_priv->stats.rx_bytes += rx_size; - sis_priv->stats.rx_packets++; - } - sis_priv->cur_rx++; + sis_priv->stats.rx_bytes += rx_size; + sis_priv->stats.rx_packets++; + + /* refill the Rx buffer, what if there is not enought memory for + new socket buffer ?? */ + if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { + /* not enough memory for skbuff, this makes a "hole" + on the buffer ring, it is not clear how the + hardware will react to this kind of degenerated + buffer */ + printk(KERN_INFO "%s: Memory squeeze," + "deferring packet.\n", + net_dev->name); + sis_priv->rx_skbuff[entry] = NULL; + /* reset buffer descriptor state */ + sis_priv->rx_ring[entry].cmdsts = 0; + sis_priv->rx_ring[entry].bufptr = 0; + sis_priv->stats.rx_dropped++; + break; + } + skb->dev = net_dev; + sis_priv->rx_skbuff[entry] = skb; + sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; + sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail); + sis_priv->dirty_rx++; + } + sis_priv->cur_rx++; entry = sis_priv->cur_rx % NUM_RX_DESC; - rx_status = sis_priv->rx_ring[entry].cmdsts; - } // while - + rx_status = sis_priv->rx_ring[entry].cmdsts; + } // while + /* refill the Rx buffer, what if the rate of refilling is slower than consuming ?? */ for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { struct sk_buff *skb; - + entry = sis_priv->dirty_rx % NUM_RX_DESC; - + if (sis_priv->rx_skbuff[entry] == NULL) { if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) { /* not enough memory for skbuff, this makes a "hole" - on the buffer ring, it is not clear how the - hardware will react to this kind of degenerated + on the buffer ring, it is not clear how the + hardware will react to this kind of degenerated buffer */ printk(KERN_INFO "%s: Memory squeeze," "deferring packet.\n", @@ -1024,10 +1217,11 @@ sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail); } } + /* re-enable the potentially idle receive state matchine */ outl(RxENA , ioaddr + cr ); - - return 0; + + return 0; } /* finish up transmission of packets, check for error condition and free skbuff etc. @@ -1035,21 +1229,21 @@ static void sis900_finish_xmit (struct device *net_dev) { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - + for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) { unsigned int entry; u32 tx_status; - + entry = sis_priv->dirty_tx % NUM_TX_DESC; - tx_status = sis_priv->tx_ring[entry].cmdsts; - + tx_status = sis_priv->tx_ring[entry].cmdsts; + if (tx_status & OWN) { /* 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; } - + if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { /* packet unsuccessfully transmited */ if (sis900_debug > 3) @@ -1077,7 +1271,7 @@ sis_priv->tx_ring[entry].bufptr = 0; sis_priv->tx_ring[entry].cmdsts = 0; } - + 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 @@ -1091,23 +1285,23 @@ static int sis900_close(struct device *net_dev) { - long ioaddr = net_dev->base_addr; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - int i; - - net_dev->start = 0; - net_dev->tbusy = 1; + long ioaddr = net_dev->base_addr; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + int i; + + net_dev->start = 0; + net_dev->tbusy = 1; - /* Disable interrupts by clearing the interrupt mask. */ - outl(0x0000, ioaddr + imr); + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x0000, ioaddr + imr); outl(0x0000, ioaddr + ier); - /* Stop the chip's Tx and Rx Status Machine */ - outl(RxDIS | TxDIS, ioaddr + cr); + /* Stop the chip's Tx and Rx Status Machine */ + outl(RxDIS | TxDIS, ioaddr + cr); - del_timer(&sis_priv->timer); + del_timer(&sis_priv->timer); - free_irq(net_dev->irq, net_dev); + free_irq(net_dev->irq, net_dev); /* Free Tx and RX skbuff */ for (i = 0; i < NUM_RX_DESC; i++) { @@ -1115,47 +1309,47 @@ dev_kfree_skb(sis_priv->rx_skbuff[i]); sis_priv->rx_skbuff[i] = 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; - } + 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; + } - /* Green! Put the chip in low-power mode. */ + /* Green! Put the chip in low-power mode. */ - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; - return 0; + return 0; } static int mii_ioctl(struct device *net_dev, struct ifreq *rq, int cmd) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + u16 *data = (u16 *)&rq->ifr_data; - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = sis_priv->mii->phy_addr; - /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(net_dev, data[0] & 0x1f, data[1] & 0x1f); - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) - return -EPERM; - mdio_write(net_dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); - return 0; - default: - return -EOPNOTSUPP; - } + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = sis_priv->mii->phy_addr; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(net_dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!suser()) + return -EPERM; + mdio_write(net_dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } } static struct enet_statistics * sis900_get_stats(struct device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; - return &sis_priv->stats; + return &sis_priv->stats; } /* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast hash table, which makes @@ -1183,49 +1377,49 @@ byte >>= 1; } } - /* leave 7 most siginifant bits */ + /* leave 7 most siginifant bits */ return ((int)(crc >> 25)); } static void set_rx_mode(struct device *net_dev) { - long ioaddr = net_dev->base_addr; - u16 mc_filter[8]; /* 128 bits multicast hash table */ - int i; - u32 rx_mode; + long ioaddr = net_dev->base_addr; + u16 mc_filter[8]; /* 128 bits multicast hash table */ + int i; + u32 rx_mode; - if (net_dev->flags & IFF_PROMISC) { + if (net_dev->flags & IFF_PROMISC) { /* Accept any kinds of packets */ rx_mode = RFPromiscuous; - for (i = 0; i < 8; i++) - mc_filter[i] = 0xffff; - } else if ((net_dev->mc_count > multicast_filter_limit) || + for (i = 0; i < 8; i++) + mc_filter[i] = 0xffff; + } else if ((net_dev->mc_count > multicast_filter_limit) || (net_dev->flags & IFF_ALLMULTI)) { /* too many multicast addresses or accept all multicast packets */ - rx_mode = RFAAB | RFAAM; - for (i = 0; i < 8; i++) - mc_filter[i] = 0xffff; - } else { + rx_mode = RFAAB | RFAAM; + for (i = 0; i < 8; i++) + mc_filter[i] = 0xffff; + } else { /* Accept Broadcast packets, destination addresses match our MAC address, use Receive Filter to reject unwanted MCAST packets */ - struct dev_mc_list *mclist; - rx_mode = RFAAB; - for (i = 0; i < 8; i++) - mc_filter[i]=0; - for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count; + struct dev_mc_list *mclist; + rx_mode = RFAAB; + for (i = 0; i < 8; i++) + mc_filter[i]=0; + for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count; i++, mclist = mclist->next) - set_bit(sis900_compute_hashtable_index(mclist->dmi_addr), + set_bit(sis900_compute_hashtable_index(mclist->dmi_addr), mc_filter); - } + } /* update Multicast Hash Table in Receive Filter */ - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { /* 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); - } + outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); + outl(mc_filter[i], ioaddr + rfdr); + } - outl(RFEN | rx_mode, ioaddr + rfcr); + outl(RFEN | rx_mode, ioaddr + rfcr); /* sis900 is capatable of looping back packet at MAC level for debugging purpose */ if (net_dev->flags & IFF_LOOPBACK) { @@ -1240,33 +1434,33 @@ outl(cr_saved, ioaddr + cr); } - return; + return; } static void sis900_reset(struct device *net_dev) { - long ioaddr = net_dev->base_addr; + long ioaddr = net_dev->base_addr; int i = 0; u32 status = TxRCMP | RxRCMP; - outl(0, ioaddr + ier); - outl(0, ioaddr + imr); - outl(0, ioaddr + rfcr); + outl(0, ioaddr + ier); + outl(0, ioaddr + imr); + outl(0, ioaddr + rfcr); - outl(RxRESET | TxRESET | RESET, ioaddr + cr); + outl(RxRESET | TxRESET | RESET, ioaddr + cr); /* Check that the chip has finished the reset. */ while (status && (i++ < 1000)) { status ^= (inl(isr + ioaddr) & status); - } + } - outl(PESEL, ioaddr + cfg); + outl(PESEL, ioaddr + cfg); } #ifdef MODULE int init_module(void) { - return sis900_probe(NULL); + return sis900_probe(NULL); } void @@ -1277,7 +1471,7 @@ struct sis900_private *sis_priv = (struct sis900_private *)root_sis900_dev->priv; struct device *next_dev = sis_priv->next_module; - + unregister_netdev(root_sis900_dev); release_region(root_sis900_dev->base_addr, sis_priv->mac->io_size); @@ -1285,7 +1479,7 @@ kfree(root_sis900_dev); root_sis900_dev = next_dev; - } + } } -#endif /* MODULE */ +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/sis900.h linux/drivers/net/sis900.h --- v2.2.17/drivers/net/sis900.h Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/sis900.h Thu Aug 31 14:30:01 2000 @@ -38,6 +38,7 @@ /* Symbolic names for bits in various registers */ enum sis900_command_register_bits { + RELOAD = 0x00000400, RESET = 0x00000100, SWI = 0x00000080, RxRESET = 0x00000020, TxRESET = 0x00000010, RxDIS = 0x00000008, RxENA = 0x00000004, TxDIS = 0x00000002, TxENA = 0x00000001 @@ -164,7 +165,7 @@ /* mii registers specific to SiS 900 */ enum sis_mii_registers { MII_CONFIG1 = 0x0010, MII_CONFIG2 = 0x0011, MII_STSOUT = 0x0012, - MII_MASK = 0x0013 + MII_MASK = 0x0013, MII_RESV = 0x0014 }; /* mii registers specific to AMD 79C901 */ @@ -214,6 +215,10 @@ enum mii_stssum_register_bits { MII_STSSUM_LINK = 0x0008, MII_STSSUM_DPLX = 0x0004, MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD = 0x0001 +}; + +enum sis630_revision_id { + SIS630E_REV = 0x81, SIS630EA1_REV = 0x83 }; #define FDX_CAPABLE_DUPLEX_UNKNOWN 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- v2.2.17/drivers/net/sk98lin/skge.c Fri Apr 21 12:46:19 2000 +++ linux/drivers/net/sk98lin/skge.c Fri Sep 1 13:48:23 2000 @@ -431,6 +431,7 @@ pci_set_master(pdev); base_address = pdev->base_address[0]; + base_address &= PCI_BASE_ADDRESS_MEM_MASK; #ifdef __sparc_v9__ /* SPARC machines do not initialize the chache line size */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/Makefile linux/drivers/net/skfp/Makefile --- v2.2.17/drivers/net/skfp/Makefile Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/Makefile Fri Sep 1 13:48:23 2000 @@ -0,0 +1,39 @@ +# +# Makefile for the SysKonnect FDDI PCI adapter driver +# + +ifeq ($(CONFIG_SKFP),y) + O_TARGET := skfp.o + O_OBJS = skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ + ecm.o pcmplc.o pmf.o queue.o rmt.o \ + smtdef.o smtinit.o smttimer.o srf.o lnkstat.o \ + smtparse.o hwt.o drvfbi.o ess.o +else + ifeq ($(CONFIG_SKFP),m) + MOD_LIST_NAME := SKFP_MODULES + M_OBJS := skfp.o + O_TARGET := skfp.o + O_OBJS = skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ + ecm.o pcmplc.o pmf.o queue.o rmt.o \ + smtdef.o smtinit.o smttimer.o srf.o lnkstat.o \ + smtparse.o hwt.o drvfbi.o ess.o + endif +endif + +# NOTE: +# Compiling this driver produces some warnings (and some more are +# switched off below), but I did not fix this, because the Hardware +# Module source (see skfddi.c for details) is used for different +# drivers, and fixing it for Linux might bring problems on other +# projects. To keep the source common for all those drivers (and +# thus simplify fixes to it), please do not clean it up! + +EXTRA_CFLAGS += -I. -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/can.c linux/drivers/net/skfp/can.c --- v2.2.17/drivers/net/skfp/can.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/can.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,83 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +#ifndef lint +static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ; +#endif + +/* + * canonical bit order + */ +const u_char canonical[256] = { + 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, + 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, + 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, + 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, + 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, + 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, + 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, + 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, + 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, + 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, + 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, + 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, + 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, + 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, + 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, + 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, + 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, + 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, + 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, + 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, + 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, + 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, + 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, + 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, + 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, + 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, + 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, + 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, + 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, + 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, + 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, + 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +} ; + +#ifdef MAKE_TABLE +int byte_reverse(x) +int x ; +{ + int y = 0 ; + + if (x & 0x01) + y |= 0x80 ; + if (x & 0x02) + y |= 0x40 ; + if (x & 0x04) + y |= 0x20 ; + if (x & 0x08) + y |= 0x10 ; + if (x & 0x10) + y |= 0x08 ; + if (x & 0x20) + y |= 0x04 ; + if (x & 0x40) + y |= 0x02 ; + if (x & 0x80) + y |= 0x01 ; + return(y) ; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/cfm.c linux/drivers/net/skfp/cfm.c --- v2.2.17/drivers/net/skfp/cfm.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/cfm.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,642 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + SMT CFM + Configuration Management + DAS with single MAC +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * + * The following external HW dependant functions are referenced : + * config_mux() + * + * The following HW dependant events are required : + * NONE + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)cfm.c 2.18 98/10/06 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.fddiSMTCF_State = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.fddiSMTCF_State &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const cfm_states[] = { + "SC0_ISOLATED","CF1","CF2","CF3","CF4", + "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S", + "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A" +} ; + +/* + * symbolic event names + */ +static const char * const cfm_events[] = { + "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B" +} ; +#endif + +/* + * map from state to downstream port type + */ +static const u_char cf_to_ptype[] = { + TNONE,TNONE,TNONE,TNONE,TNONE, + TNONE,TB,TB,TS, + TA,TB,TS,TB +} ; + +/* + * CEM port states + */ +#define CEM_PST_DOWN 0 +#define CEM_PST_UP 1 +#define CEM_PST_HOLD 2 +/* define portstate array only for A and B port */ +/* Do this within the smc structure (use in multiple cards) */ + +/* + * all Globals are defined in smc.h + * struct s_cfm + */ + +/* + * function declarations + */ +static void cfm_fsm() ; + +/* + init CFM state machine + clear all CFM vars and flags +*/ +void cfm_init(smc) +struct s_smc *smc ; +{ + smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ; + smc->r.rm_join = 0 ; + smc->r.rm_loop = 0 ; + smc->y[PA].scrub = 0 ; + smc->y[PB].scrub = 0 ; + smc->y[PA].cem_pst = CEM_PST_DOWN ; + smc->y[PB].cem_pst = CEM_PST_DOWN ; +} + +/* Some terms conditions used by the selection criteria */ +#define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \ + smc->y[PB].pc_mode != PM_TREE) +/* Selection criteria for the ports */ +static void selection_criteria (smc,phy) +struct s_smc *smc ; +struct s_phy *phy ; +{ + + switch (phy->mib->fddiPORTMy_Type) { + case TA: + if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) { + phy->wc_flag = TRUE ; + } else { + phy->wc_flag = FALSE ; + } + + break; + case TB: + /* take precedence over PA */ + phy->wc_flag = FALSE ; + break; + case TS: + phy->wc_flag = FALSE ; + break; + case TM: + phy->wc_flag = FALSE ; + break; + } + +} + +void all_selection_criteria (smc) +struct s_smc *smc ; +{ + struct s_phy *phy ; + int p ; + + for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) { + /* Do the selection criteria */ + selection_criteria (smc,phy); + } +} + +static void cem_priv_state (smc, event) +struct s_smc *smc ; +int event ; +/* State machine for private PORT states: used to optimize dual homing */ +{ + int np; /* Number of the port */ + int i; + + /* Do this only in a DAS */ + if (smc->s.sas != SMT_DAS ) + return ; + + np = event - CF_JOIN; + + if (np != PA && np != PB) { + return ; + } + /* Change the port state according to the event (portnumber) */ + if (smc->y[np].cf_join) { + smc->y[np].cem_pst = CEM_PST_UP ; + } else if (!smc->y[np].wc_flag) { + /* set the port to done only if it is not withheld */ + smc->y[np].cem_pst = CEM_PST_DOWN ; + } + + /* Don't set an hold port to down */ + + /* Check all ports of restart conditions */ + for (i = 0 ; i < 2 ; i ++ ) { + /* Check all port for PORT is on hold and no withhold is done */ + if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) { + smc->y[i].cem_pst = CEM_PST_DOWN; + queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; + } + if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) { + smc->y[i].cem_pst = CEM_PST_HOLD; + queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; + } + if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) { + /* + * The port must be restarted when the wc_flag + * will be reset. So set the port on hold. + */ + smc->y[i].cem_pst = CEM_PST_HOLD; + } + } + return ; +} + +/* + CFM state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void cfm(smc,event) +struct s_smc *smc ; +int event ; +{ + int state ; /* remember last state */ + int cond ; + int oldstate ; + + /* We will do the following: */ + /* - compute the variable WC_Flag for every port (This is where */ + /* we can extend the requested path checking !!) */ + /* - do the old (SMT 6.2 like) state machine */ + /* - do the resulting station states */ + + all_selection_criteria (smc); + + /* We will check now whether a state transition is allowed or not */ + /* - change the portstates */ + cem_priv_state (smc, event); + + oldstate = smc->mib.fddiSMTCF_State ; + do { + DB_CFM("CFM : state %s%s", + (smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "", + cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ; + DB_CFM(" event %s\n",cfm_events[event],0) ; + state = smc->mib.fddiSMTCF_State ; + cfm_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.fddiSMTCF_State) ; + +#ifndef SLIM_SMT + /* + * check peer wrap condition + */ + cond = FALSE ; + if ( (smc->mib.fddiSMTCF_State == SC9_C_WRAP_A && + smc->y[PA].pc_mode == PM_PEER) || + (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B && + smc->y[PB].pc_mode == PM_PEER) || + (smc->mib.fddiSMTCF_State == SC11_C_WRAP_S && + smc->y[PS].pc_mode == PM_PEER && + smc->y[PS].mib->fddiPORTNeighborType != TS ) ) { + cond = TRUE ; + } + if (cond != smc->mib.fddiSMTPeerWrapFlag) + smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ; + +#if 0 + /* + * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired + * to the primary path. + */ + /* + * path change + */ + if (smc->mib.fddiSMTCF_State != oldstate) { + smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ; + } +#endif +#endif /* no SLIM_SMT */ + + /* + * set MAC port type + */ + smc->mib.m[MAC0].fddiMACDownstreamPORTType = + cf_to_ptype[smc->mib.fddiSMTCF_State] ; + cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ; +} + +/* + process CFM event +*/ +/*ARGSUSED1*/ +static void cfm_fsm(smc,cmd) +struct s_smc *smc ; +int cmd ; +{ + switch(smc->mib.fddiSMTCF_State) { + case ACTIONS(SC0_ISOLATED) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; + config_mux(smc,MUX_ISOLATE) ; /* configure PHY Mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = FALSE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + /* Don't do the WC-Flag changing here */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break; + case SC0_ISOLATED : + /*SC07*/ + /*SAS port can be PA or PB ! */ + if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop || + smc->y[PB].cf_join || smc->y[PB].cf_loop)) { + GO_STATE(SC11_C_WRAP_S) ; + break ; + } + /*SC01*/ + if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join && + !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) { + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC02*/ + if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join && + !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) { + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + break ; + case ACTIONS(SC9_C_WRAP_A) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPA) ; /* configure PHY mux */ + if (smc->y[PA].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PA].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC9_C_WRAP_A : + /*SC10*/ + if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) && + !smc->y[PA].cf_loop ) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + /*SC12*/ + else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP) || + ((smc->y[PB].cf_loop || + (smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP)) && + (smc->y[PA].pc_mode == PM_TREE || + smc->y[PB].pc_mode == PM_TREE))) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC14*/ + else if (!smc->s.attach_s && + smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP && + smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP && + smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + /*SC15*/ + else if ( smc->s.attach_s && + smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP && + smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP && + smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC10_C_WRAP_B) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPB) ; /* configure PHY mux */ + if (smc->y[PB].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PB].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC10_C_WRAP_B : + /*SC20*/ + if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + /*SC21*/ + else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC24*/ + else if (!smc->s.attach_s && + smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + /*SC25*/ + else if ( smc->s.attach_s && + smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC4_THRU_A) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; + config_mux(smc,MUX_THRUA) ; /* configure PHY mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC4_THRU_A : + /*SC41*/ + if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC42*/ + else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC45*/ + else if (smc->s.attach_s) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC5_THRU_B) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; + config_mux(smc,MUX_THRUB) ; /* configure PHY mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC5_THRU_B : + /*SC51*/ + if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC52*/ + else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC54*/ + else if (!smc->s.attach_s) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + break ; + case ACTIONS(SC11_C_WRAP_S) : + smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPS) ; /* configure PHY mux */ + if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PA].cf_join || smc->y[PB].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC11_C_WRAP_S : + /*SC70*/ + if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop && + !smc->y[PB].cf_join && !smc->y[PB].cf_loop) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + break ; + default: + SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ; + break; + } +} + +/* + * get MAC's input Port + * return : + * PA or PB + */ +int cfm_get_mac_input(smc) +struct s_smc *smc ; +{ + return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || + smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA) ; +} + +/* + * get MAC's output Port + * return : + * PA or PB + */ +int cfm_get_mac_output(smc) +struct s_smc *smc ; +{ + return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || + smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA) ; +} + +static char path_iso[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_wrap_a[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_wrap_b[] = { + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_thru[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM +} ; + +static char path_wrap_s[] = { + 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, +} ; + +static char path_iso_s[] = { + 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_ISO, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, +} ; + +int cem_build_path(smc,to,path_index) +struct s_smc *smc ; +char *to ; +int path_index ; +{ + char *path ; + int len ; + + switch (smc->mib.fddiSMTCF_State) { + default : + case SC0_ISOLATED : + path = smc->s.sas ? path_iso_s : path_iso ; + len = smc->s.sas ? sizeof(path_iso_s) : sizeof(path_iso) ; + break ; + case SC9_C_WRAP_A : + path = path_wrap_a ; + len = sizeof(path_wrap_a) ; + break ; + case SC10_C_WRAP_B : + path = path_wrap_b ; + len = sizeof(path_wrap_b) ; + break ; + case SC4_THRU_A : + path = path_thru ; + len = sizeof(path_thru) ; + break ; + case SC11_C_WRAP_S : + path = path_wrap_s ; + len = sizeof(path_wrap_s) ; + break ; + } + memcpy(to,path,len) ; + + LINT_USE(path_index); + + return(len) ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/drvfbi.c linux/drivers/net/skfp/drvfbi.c --- v2.2.17/drivers/net/skfp/drvfbi.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/drvfbi.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,1612 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + * FBI board dependent Driver for SMT and LLC + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "h/skfbiinc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; +#endif + +/* + * PCM active state + */ +#define PC8_ACTIVE 8 + +#define LED_Y_ON 0x11 /* Used for ring up/down indication */ +#define LED_Y_OFF 0x10 + + +#define MS2BCLK(x) ((x)*12500L) + +/* + * valid configuration values are: + */ +#ifdef ISA +const int opt_ints[] = {8, 3, 4, 5, 9, 10, 11, 12, 15} ; +const int opt_iops[] = {8, + 0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340}; +const int opt_dmas[] = {4, 3, 5, 6, 7} ; +const int opt_eproms[] = {15, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; +#endif +#ifdef EISA +const int opt_ints[] = {5, 9, 10, 11} ; +const int opt_dmas[] = {0, 5, 6, 7} ; +const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; +#endif + +#ifdef MCA +int opt_ints[] = {3, 11, 10, 9} ; /* FM1 */ +int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ; +#endif /* MCA */ + +/* + * xPOS_ID:xxxx + * | \ / + * | \/ + * | --------------------- the patched POS_ID of the Adapter + * | xxxx = (Vendor ID low byte, + * | Vendor ID high byte, + * | Device ID low byte, + * | Device ID high byte) + * +------------------------------ the patched oem_id must be + * 'S' for SK or 'I' for IBM + * this is a short id for the driver. + */ +#ifndef MULT_OEM +#ifndef OEM_CONCEPT +#ifndef MCA +const u_char oem_id[] = "xPOS_ID:xxxx" ; +#else +const u_char oem_id[] = "xPOSID1:xxxx" ; /* FM1 card id. */ +#endif +#else /* OEM_CONCEPT */ +#ifndef MCA +const u_char oem_id[] = OEM_ID ; +#else +const u_char oem_id[] = OEM_ID1 ; /* FM1 card id. */ +#endif /* MCA */ +#endif /* OEM_CONCEPT */ +#define ID_BYTE0 8 +#define OEMID(smc,i) oem_id[ID_BYTE0 + i] +#else /* MULT_OEM */ +const struct s_oem_ids oem_ids[] = { +#include "oemids.h" +{0} +}; +#define OEMID(smc,i) smc->hw.oem_id->oi_id[i] +#endif /* MULT_OEM */ + +/* Prototypes of external functions */ +extern void hwt_restart() ; +#ifdef AIX +extern int AIX_vpdReadByte() ; +#endif + + +/* Prototypes of local functions. */ +void smt_stop_watchdog() ; + +#ifdef MCA +static int read_card_id() ; +static void DisableSlotAccess() ; +static void EnableSlotAccess() ; +#ifdef AIX +extern int attach_POS_addr() ; +extern int detach_POS_addr() ; +extern u_char read_POS() ; +extern void write_POS() ; +extern int AIX_vpdReadByte() ; +#else +#define read_POS(smc,a1,a2) ((u_char) inp(a1)) +#define write_POS(smc,a1,a2,a3) outp((a1),(a3)) +#endif +#endif /* MCA */ + + +/* + * FDDI card reset + */ +static void card_start(smc) +struct s_smc *smc ; +{ + int i ; +#ifdef PCI + u_char rev_id ; + u_short word; +#endif + + smt_stop_watchdog(smc) ; + +#ifdef ISA + outpw(CSR_A,0) ; /* reset for all chips */ + for (i = 10 ; i ; i--) /* delay for PLC's */ + (void)inpw(ISR_A) ; + OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ; + /* counter 2, mode 2 */ + OUT_82c54_TIMER(2,97) ; /* LSB */ + OUT_82c54_TIMER(2,0) ; /* MSB ( 15.6 us ) */ + outpw(CSR_A,CS_CRESET) ; +#endif +#ifdef EISA + outpw(CSR_A,0) ; /* reset for all chips */ + for (i = 10 ; i ; i--) /* delay for PLC's */ + (void)inpw(ISR_A) ; + outpw(CSR_A,CS_CRESET) ; + smc->hw.led = (2<<6) ; + outpw(CSR_A,CS_CRESET | smc->hw.led) ; +#endif +#ifdef MCA + outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ + for (i = 10 ; i ; i--) /* delay for PLC's */ + (void)inpw(ISR_A) ; + outp(ADDR(CARD_EN),0) ; + /* first I/O after reset must not be a access to FORMAC or PLC */ + + /* + * bus timeout (MCA) + */ + OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ; + /* counter 2, mode 3 */ + OUT_82c54_TIMER(2,(2*24)) ; /* 3.9 us * 2 square wave */ + OUT_82c54_TIMER(2,0) ; /* MSB */ + + /* POS 102 indicated an activ Check Line or Buss Error monitoring */ + if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) { + outp(ADDR(IRQ_CHCK_EN),0) ; + } + + if (!((i = inpw(CSR_A)) & CS_SAS)) { + if (!(i & CS_BYSTAT)) { + outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ + } + } + outpw(LEDR_A,LED_1) ; /* yellow */ +#endif /* MCA */ +#ifdef PCI + /* + * make sure no transfer activity is pending + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; + /* + * now reset everything + */ + outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ + i = (int) inp(ADDR(B0_CTRL)) ; /* do dummy read */ + SK_UNUSED(i) ; /* Make LINT happy. */ + outp(ADDR(B0_CTRL), CTRL_RST_CLR) ; + + /* + * Reset all bits in the PCI STATUS register + */ + outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ; /* enable for writes */ + word = inpw(PCI_C(PCI_STATUS)) ; + outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ; + outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ; /* disable writes */ + + /* + * Release the reset of all the State machines + * Release Master_Reset + * Release HPI_SM_Reset + */ + outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ; + + /* + * determine the adapter type + * Note: Do it here, because some drivers may call card_start() once + * at very first before any other initialization functions is + * executed. + */ + rev_id = inp(PCI_C(PCI_REV_ID)) ; + if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) { + smc->hw.hw_is_64bit = TRUE ; + } else { + smc->hw.hw_is_64bit = FALSE ; + } + + /* + * Watermark initialization + */ + if (!smc->hw.hw_is_64bit) { + outpd(ADDR(B4_R1_F), RX_WATERMARK) ; + outpd(ADDR(B5_XA_F), TX_WATERMARK) ; + outpd(ADDR(B5_XS_F), TX_WATERMARK) ; + } + + outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* clear the reset chips */ + outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */ + + /* init the timer value for the watch dog 2,5 minutes */ + outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ; + + /* initialize the ISR mask */ + smc->hw.is_imask = ISR_MASK ; + smc->hw.hw_state = STOPPED ; +#endif + GET_PAGE(0) ; /* necessary for BOOT */ +} + +void card_stop(smc) +struct s_smc *smc ; +{ + smt_stop_watchdog(smc) ; + smc->hw.mac_ring_is_up = 0 ; /* ring down */ +#ifdef ISA + outpw(CSR_A,0) ; /* reset for all chips */ +#endif +#ifdef EISA + outpw(CSR_A,0) ; /* reset for all chips */ +#endif +#ifdef MCA + outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ +#endif +#ifdef PCI + /* + * make sure no transfer activity is pending + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; + /* + * now reset everything + */ + outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ + outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* reset for all chips */ + outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */ + smc->hw.hw_state = STOPPED ; +#endif +} +/*--------------------------- ISR handling ----------------------------------*/ + +#ifndef PCI +void mac1_irq(smc,stu, stl) +struct s_smc *smc ; +u_short stu; +u_short stl; +{ + int restart_tx = 0 ; +again: +#ifndef ISA +/* + * FORMAC+ bug modified the queue pointer if many read/write accesses happens!? + */ + if (stl & (FM_SPCEPDS | /* parit/coding err. syn.q.*/ + FM_SPCEPDA0 | /* parit/coding err. a.q.0 */ + FM_SPCEPDA1 | /* parit/coding err. a.q.1 */ + FM_SPCEPDA2)) { /* parit/coding err. a.q.2 */ + SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ; + } + if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ + FM_STBURA0 | /* tx buffer underrun a.q.0 */ + FM_STBURA1 | /* tx buffer underrun a.q.1 */ + FM_STBURA2)) { /* tx buffer underrun a.q.2 */ + SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; + } +#endif + if ( (stu & (FM_SXMTABT | /* transmit abort */ +#ifdef SYNC + FM_STXABRS | /* syn. tx abort */ +#endif /* SYNC */ + FM_STXABRA0)) || /* asyn. tx abort */ + (stl & (FM_SQLCKS | /* lock for syn. q. */ + FM_SQLCKA0)) ) { /* lock for asyn. q. */ + formac_tx_restart(smc) ; /* init tx */ + restart_tx = 1 ; + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; + if (stu || stl) + goto again ; + } + +#ifndef SYNC + if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */ + FM_STEFRMA0)) { /* end of frame asyn tx */ + /* free tx_queue */ + smc->hw.n_a_send = 0 ; + if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) { + start_next_send(smc); + } + restart_tx = 1 ; + } +#else /* SYNC */ + if (stu & (FM_STEFRMA0 | /* end of asyn tx */ + FM_STEFRMS)) { /* end of sync tx */ + restart_tx = 1 ; + } +#endif /* SYNC */ + if (restart_tx) + llc_restart_tx(smc) ; +} +#else /* PCI */ + +void mac1_irq(smc,stu, stl) +struct s_smc *smc ; +u_short stu; +u_short stl; +{ + int restart_tx = 0 ; +again: + + /* + * parity error: note encoding error is not possible in tag mode + */ + if (stl & (FM_SPCEPDS | /* parity err. syn.q.*/ + FM_SPCEPDA0 | /* parity err. a.q.0 */ + FM_SPCEPDA1)) { /* parity err. a.q.1 */ + SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ; + } + /* + * buffer underrun: can only occur if a tx threshold is specified + */ + if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ + FM_STBURA0 | /* tx buffer underrun a.q.0 */ + FM_STBURA1)) { /* tx buffer underrun a.q.2 */ + SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; + } + + if ( (stu & (FM_SXMTABT | /* transmit abort */ + FM_STXABRS | /* syn. tx abort */ + FM_STXABRA0)) || /* asyn. tx abort */ + (stl & (FM_SQLCKS | /* lock for syn. q. */ + FM_SQLCKA0)) ) { /* lock for asyn. q. */ + formac_tx_restart(smc) ; /* init tx */ + restart_tx = 1 ; + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; + if (stu || stl) + goto again ; + } + + if (stu & (FM_STEFRMA0 | /* end of asyn tx */ + FM_STEFRMS)) { /* end of sync tx */ + restart_tx = 1 ; + } + + if (restart_tx) + llc_restart_tx(smc) ; +} +#endif /* PCI */ +/* + * interrupt source= plc1 + * this function is called in nwfbisr.asm + */ +void plc1_irq(smc) +struct s_smc *smc ; +{ + u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ; + +#if (defined(ISA) || defined(EISA)) + /* reset PLC Int. bits */ + outpw(PLC1_I,inpw(PLC1_I)) ; +#endif + plc_irq(smc,PB,st) ; +} + +/* + * interrupt source= plc2 + * this function is called in nwfbisr.asm + */ +void plc2_irq(smc) +struct s_smc *smc ; +{ + u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ; + +#if (defined(ISA) || defined(EISA)) + /* reset PLC Int. bits */ + outpw(PLC2_I,inpw(PLC2_I)) ; +#endif + plc_irq(smc,PA,st) ; +} + + +/* + * interrupt source= timer + */ +void timer_irq(smc) +struct s_smc *smc ; +{ + hwt_restart(smc); + smc->hw.t_stop = smc->hw.t_start; + smt_timer_done(smc) ; +} + +/* + * return S-port (PA or PB) + */ +int pcm_get_s_port(smc) +struct s_smc *smc ; +{ + SK_UNUSED(smc) ; + return(PS) ; +} + +/* + * Station Label = "FDDI-XYZ" where + * + * X = connector type + * Y = PMD type + * Z = port type + */ +#define STATION_LABEL_CONNECTOR_OFFSET 5 +#define STATION_LABEL_PMD_OFFSET 6 +#define STATION_LABEL_PORT_OFFSET 7 + +void read_address(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; +{ + char ConnectorType ; + char PmdType ; + int i ; + + extern const u_char canonical[256] ; + +#if (defined(ISA) || defined(MCA)) + for (i = 0; i < 4 ;i++) { /* read mac address from board */ + smc->hw.fddi_phys_addr.a[i] = + canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ; + } + for (i = 4; i < 6; i++) { + smc->hw.fddi_phys_addr.a[i] = + canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ; + } +#endif +#ifdef EISA + /* + * Note: We get trouble on an Alpha machine if we make a inpw() + * instead of inp() + */ + for (i = 0; i < 4 ;i++) { /* read mac address from board */ + smc->hw.fddi_phys_addr.a[i] = + canonical[inp(PR_A(i+SA_MAC))] ; + } + for (i = 4; i < 6; i++) { + smc->hw.fddi_phys_addr.a[i] = + canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ; + } +#endif +#ifdef PCI + for (i = 0; i < 6; i++) { /* read mac address from board */ + smc->hw.fddi_phys_addr.a[i] = + canonical[inp(ADDR(B2_MAC_0+i))] ; + } +#endif +#ifndef PCI + ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ; + PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ; +#else + ConnectorType = inp(ADDR(B2_CONN_TYP)) ; + PmdType = inp(ADDR(B2_PMD_TYP)) ; +#endif + + smc->y[PA].pmd_type[PMD_SK_CONN] = + smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ; + smc->y[PA].pmd_type[PMD_SK_PMD ] = + smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ; + + if (mac_addr) { + for (i = 0; i < 6 ;i++) { + smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ; + smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ; + } + return ; + } + smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ; + + for (i = 0; i < 6 ;i++) { + smc->hw.fddi_canon_addr.a[i] = + canonical[smc->hw.fddi_phys_addr.a[i]] ; + } +} + +/* + * FDDI card soft reset + */ +void init_board(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; +{ + card_start(smc) ; + read_address(smc,mac_addr) ; + +#ifndef PCI + if (inpw(CSR_A) & CS_SAS) +#else + if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL)) +#endif + smc->s.sas = SMT_SAS ; /* Single att. station */ + else + smc->s.sas = SMT_DAS ; /* Dual att. station */ + +#ifndef PCI + if (inpw(CSR_A) & CS_BYSTAT) +#else + if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST)) +#endif + smc->mib.fddiSMTBypassPresent = 0 ; + /* without opt. bypass */ + else + smc->mib.fddiSMTBypassPresent = 1 ; + /* with opt. bypass */ +} + +/* + * insert or deinsert optical bypass (called by ECM) + */ +void sm_pm_bypass_req(smc,mode) +struct s_smc *smc ; +int mode; +{ +#if (defined(ISA) || defined(EISA)) + int csra_v ; +#endif + + DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ? + "BP_INSERT" : "BP_DEINSERT",0) ; + + if (smc->s.sas != SMT_DAS) + return ; + +#if (defined(ISA) || defined(EISA)) + + csra_v = inpw(CSR_A) & ~CS_BYPASS ; +#ifdef EISA + csra_v |= smc->hw.led ; +#endif + + switch(mode) { + case BP_INSERT : + outpw(CSR_A,csra_v | CS_BYPASS) ; + break ; + case BP_DEINSERT : + outpw(CSR_A,csra_v) ; + break ; + } +#endif /* ISA / EISA */ +#ifdef MCA + switch(mode) { + case BP_INSERT : + outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ + break ; + case BP_DEINSERT : + outp(ADDR(BYPASS(STAT_BYP)),0) ; /* bypass station */ + break ; + } +#endif +#ifdef PCI + switch(mode) { + case BP_INSERT : + outp(ADDR(B0_DAS),DAS_BYP_INS) ; /* insert station */ + break ; + case BP_DEINSERT : + outp(ADDR(B0_DAS),DAS_BYP_RMV) ; /* bypass station */ + break ; + } +#endif +} + +/* + * check if bypass connected + */ +int sm_pm_bypass_present(smc) +struct s_smc *smc ; +{ +#ifndef PCI + return( (inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ; +#else + return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ; +#endif +} + +void plc_clear_irq(smc,p) +struct s_smc *smc ; +int p ; +{ + SK_UNUSED(p) ; + +#if (defined(ISA) || defined(EISA)) + switch (p) { + case PA : + /* reset PLC Int. bits */ + outpw(PLC2_I,inpw(PLC2_I)) ; + break ; + case PB : + /* reset PLC Int. bits */ + outpw(PLC1_I,inpw(PLC1_I)) ; + break ; + } +#else + SK_UNUSED(smc) ; +#endif +} + + +/* + * led_indication called by rmt_indication() and + * pcm_state_change() + * + * Input: + * smc: SMT context + * led_event: + * 0 Only switch green LEDs according to their respective PCM state + * LED_Y_OFF just switch yellow LED off + * LED_Y_ON just switch yello LED on + */ +void led_indication(smc,led_event) +struct s_smc *smc ; +int led_event; +{ + /* use smc->hw.mac_ring_is_up == TRUE + * as indication for Ring Operational + */ + u_short led_state ; + struct s_phy *phy ; + struct fddi_mib_p *mib_a ; + struct fddi_mib_p *mib_b ; + + phy = &smc->y[PA] ; + mib_a = phy->mib ; + phy = &smc->y[PB] ; + mib_b = phy->mib ; + +#ifdef EISA + /* Ring up = yellow led OFF*/ + if (led_event == LED_Y_ON) { + smc->hw.led |= CS_LED_1 ; + } + else if (led_event == LED_Y_OFF) { + smc->hw.led &= ~CS_LED_1 ; + } + else { + /* Link at Port A or B = green led ON */ + if (mib_a->fddiPORTPCMState == PC8_ACTIVE || + mib_b->fddiPORTPCMState == PC8_ACTIVE) { + smc->hw.led |= CS_LED_0 ; + } + else { + smc->hw.led &= ~CS_LED_0 ; + } + } +#endif +#ifdef MCA + led_state = inpw(LEDR_A) ; + + /* Ring up = yellow led OFF*/ + if (led_event == LED_Y_ON) { + led_state |= LED_1 ; + } + else if (led_event == LED_Y_OFF) { + led_state &= ~LED_1 ; + } + else { + led_state &= ~(LED_2|LED_0) ; + + /* Link at Port A = green led A ON */ + if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_2 ; + } + + /* Link at Port B/S = green led B ON */ + if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_0 ; + } + } + + outpw(LEDR_A, led_state) ; +#endif /* MCA */ +#ifdef PCI + led_state = 0 ; + + /* Ring up = yellow led OFF*/ + if (led_event == LED_Y_ON) { + led_state |= LED_MY_ON ; + } + else if (led_event == LED_Y_OFF) { + led_state |= LED_MY_OFF ; + } + else { /* PCM state changed */ + /* Link at Port A/S = green led A ON */ + if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_GA_ON ; + } + else { + led_state |= LED_GA_OFF ; + } + + /* Link at Port B = green led B ON */ + if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_GB_ON ; + } + else { + led_state |= LED_GB_OFF ; + } + } + + outp(ADDR(B0_LED), led_state) ; +#endif /* PCI */ + +} + + +void pcm_state_change(smc,plc,p_state) +struct s_smc *smc; +int plc; +int p_state; +{ + /* + * the current implementation of pcm_state_change() in the driver + * parts must be renamed to drv_pcm_state_change() which will be called + * now after led_indication. + */ + DRV_PCM_STATE_CHANGE(smc,plc,p_state) ; + + led_indication(smc,0) ; +} + + +void rmt_indication(smc,i) +struct s_smc *smc ; +int i; +{ + /* Call a driver special function if defined */ + DRV_RMT_INDICATION(smc,i) ; + + led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ; +} + + +/* + * llc_recover_tx called by init_tx (fplus.c) + */ +void llc_recover_tx(smc) +struct s_smc *smc ; +{ +#ifdef LOAD_GEN + extern int load_gen_flag ; + + load_gen_flag = 0 ; +#endif +#ifndef SYNC + smc->hw.n_a_send= 0 ; +#else + SK_UNUSED(smc) ; +#endif +} + +/*--------------------------- DMA init ----------------------------*/ +#ifdef ISA + +/* + * init DMA + */ +void init_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + + /* + * set cascade mode, + * clear mask bit (enable DMA cannal) + */ + if (dma > 3) { + outp(0xd6,(dma & 0x03) | 0xc0) ; + outp(0xd4, dma & 0x03) ; + } + else { + outp(0x0b,(dma & 0x03) | 0xc0) ; + outp(0x0a,dma & 0x03) ; + } +} + +/* + * disable DMA + */ +void dis_dma(smc,dma) +struct s_smc *smc ; +int dma; +{ + SK_UNUSED(smc) ; + + /* + * set mask bit (disable DMA cannal) + */ + if (dma > 3) { + outp(0xd4,(dma & 0x03) | 0x04) ; + } + else { + outp(0x0a,(dma & 0x03) | 0x04) ; + } +} + +#endif /* ISA */ + +#ifdef EISA + +/*arrays with io adresses of dma controller length and adress registers*/ +static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ; +static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ; +static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ; + +void init_dma(smc,dma) +struct s_smc *smc ; +int dma; +{ + /* + * extended mode register + * 32 bit IO + * type c + * TC output + * disable stop + */ + + /* mode read (write) demand */ + smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ; + smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ; + + /* 32 bit IO's, burst DMA mode (type "C") */ + smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ; + + outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ; + + /* disable chaining */ + outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ; + + /*load dma controller addresses for fast access during set dma*/ + smc->hw.dma_base_word_count = cntr[smc->hw.dma]; + smc->hw.dma_base_address = base[smc->hw.dma]; + smc->hw.dma_base_address_page = page[smc->hw.dma]; + +} + +void dis_dma(smc,dma) +struct s_smc *smc ; +int dma; +{ + SK_UNUSED(smc) ; + + outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */ +} +#endif /* EISA */ + +#ifdef MCA +void init_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +void dis_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +#endif + +#ifdef PCI +void init_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +void dis_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +#endif + +#ifdef MULT_OEM +static int is_equal_num(comp1,comp2,num) +char comp1[] ; +char comp2[] ; +int num ; +{ + int i ; + + for (i = 0 ; i < num ; i++) { + if (comp1[i] != comp2[i]) + return (0) ; + } + return (1) ; +} /* is_equal_num */ + + +/* + * set the OEM ID defaults, and test the contents of the OEM data base + * The default OEM is the first ACTIVE entry in the OEM data base + * + * returns: 0 success + * 1 error in data base + * 2 data base empty + * 3 no active entry + */ +int set_oi_id_def(smc) +struct s_smc *smc ; +{ + int sel_id ; + int i ; + int act_entries ; + + i = 0 ; + sel_id = -1 ; + act_entries = FALSE ; + smc->hw.oem_id = 0 ; + smc->hw.oem_min_status = OI_STAT_ACTIVE ; + + /* check OEM data base */ + while (oem_ids[i].oi_status) { + switch (oem_ids[i].oi_status) { + case OI_STAT_ACTIVE: + act_entries = TRUE ; /* we have active IDs */ + if (sel_id == -1) + sel_id = i ; /* save the first active ID */ + case OI_STAT_VALID: + case OI_STAT_PRESENT: + i++ ; + break ; /* entry ok */ + default: + return (1) ; /* invalid oi_status */ + } + } + + if (i == 0) + return (2) ; + if (!act_entries) + return (3) ; + + /* ok, we have a valid OEM data base with an active entry */ + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[sel_id] ; + return (0) ; +} +#endif /* MULT_OEM */ + + +#ifdef MCA +/************************ + * + * BEGIN_MANUAL_ENTRY() + * + * exist_board + * + * Check if an MCA board is present in the specified slot. + * + * int exist_board( + * struct s_smc *smc, + * int slot) ; + * In + * smc - A pointer to the SMT Context struct. + * + * slot - The number of the slot to inspect. + * Out + * 0 = No adapter present. + * 1 = Found FM1 adapter. + * + * Pseudo + * Read MCA ID + * for all valid OEM_IDs + * compare with ID read + * if equal, return 1 + * return(0 + * + * Note + * The smc pointer must be valid now. + * + * END_MANUAL_ENTRY() + * + ************************/ +#define LONG_CARD_ID(lo, hi) ((((hi) & 0xff) << 8) | ((lo) & 0xff)) +int exist_board(smc,slot) +struct s_smc *smc ; +int slot ; +{ +#ifdef MULT_OEM + SK_LOC_DECL(u_char,id[2]) ; + int idi ; +#endif /* MULT_OEM */ + + /* No longer valid. */ + if (smc == NULL) + return(0) ; + +#ifndef MULT_OEM + if (read_card_id(smc, slot) + == LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1))) + return (1) ; /* Found FM adapter. */ + +#else /* MULT_OEM */ + idi = read_card_id(smc, slot) ; + id[0] = idi & 0xff ; + id[1] = idi >> 8 ; + + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; + for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { + if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) + continue ; + + if (is_equal_num(&id[0],&OEMID(smc,0),2)) + return (1) ; + } +#endif /* MULT_OEM */ + return (0) ; /* No adapter found. */ +} + +/************************ + * + * read_card_id + * + * Read the MCA card id from the specified slot. + * In + * smc - A pointer to the SMT Context struct. + * CAVEAT: This pointer may be NULL and *must not* be used within this + * function. It's only purpose is for drivers that need some information + * for the inp() and outp() macros. + * + * slot - The number of the slot for which the card id is returned. + * Out + * Returns the card id read from the specified slot. If an illegal slot + * number is specified, the function returns zero. + * + ************************/ +static int read_card_id(smc,slot) +struct s_smc *smc ; /* Do not use. */ +int slot ; +{ + int card_id ; + + SK_UNUSED(smc) ; /* Make LINT happy. */ + if ((slot < 1) || (slot > 15)) /* max 16 slots, 0 = motherboard */ + return (0) ; /* Illegal slot number specified. */ + + EnableSlotAccess(smc, slot) ; + + card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) | + (read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ; + + DisableSlotAccess(smc) ; + + return (card_id) ; +} + +/************************ + * + * BEGIN_MANUAL_ENTRY() + * + * get_board_para + * + * Get adapter configuration information. Fill all board specific + * parameters within the 'smc' structure. + * + * int get_board_para( + * struct s_smc *smc, + * int slot) ; + * In + * smc - A pointer to the SMT Context struct, to which this function will + * write some adapter configuration data. + * + * slot - The number of the slot, in which the adapter is installed. + * Out + * 0 = No adapter present. + * 1 = Ok. + * 2 = Adapter present, but card enable bit not set. + * + * END_MANUAL_ENTRY() + * + ************************/ +int get_board_para(smc,slot) +struct s_smc *smc ; +int slot ; +{ + int val ; + int i ; + + /* Check if adapter present & get type of adapter. */ + switch (exist_board(smc, slot)) { + case 0: /* Adapter not present. */ + return (0) ; + case 1: /* FM Rev. 1 */ + smc->hw.rev = FM1_REV ; + smc->hw.VFullRead = 0x0a ; + smc->hw.VFullWrite = 0x05 ; + smc->hw.DmaWriteExtraBytes = 8 ; /* 2 extra words. */ + break ; + } + smc->hw.slot = slot ; + + EnableSlotAccess(smc, slot) ; + + if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) { + DisableSlotAccess(smc) ; + return (2) ; /* Card enable bit not set. */ + } + + val = read_POS(smc,POS_104, slot - 1) ; /* I/O, IRQ */ + +#ifndef MEM_MAPPED_IO /* is defined by the operating system */ + i = val & POS_IOSEL ; /* I/O base addr. (0x0200 .. 0xfe00) */ + smc->hw.iop = (i + 1) * 0x0400 - 0x200 ; +#endif + i = ((val & POS_IRQSEL) >> 6) & 0x03 ; /* IRQ <0, 1> */ + smc->hw.irq = opt_ints[i] ; + + /* FPROM base addr. */ + i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ; + smc->hw.eprom = opt_eproms[i] ; + + DisableSlotAccess(smc) ; + + /* before this, the smc->hw.iop must be set !!! */ + smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ; + + return (1) ; +} + +/* Enable access to specified MCA slot. */ +static void EnableSlotAccess(smc,slot) +struct s_smc *smc ; +int slot ; +{ + SK_UNUSED(slot) ; + +#ifndef AIX + SK_UNUSED(smc) ; + + /* System mode. */ + outp(POS_SYS_SETUP, POS_SYSTEM) ; + + /* Select slot. */ + outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ; +#else + attach_POS_addr (smc) ; +#endif +} + +/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */ +static void DisableSlotAccess(smc) +struct s_smc *smc ; +{ +#ifndef AIX + SK_UNUSED(smc) ; + + outp(POS_CHANNEL_POS, 0) ; +#else + detach_POS_addr (smc) ; +#endif +} +#endif /* MCA */ + +#ifdef EISA +#ifndef MEM_MAPPED_IO +#define SADDR(slot) (((slot)<<12)&0xf000) +#else /* MEM_MAPPED_IO */ +#define SADDR(slot) (smc->hw.iop) +#endif /* MEM_MAPPED_IO */ + +/************************ + * + * BEGIN_MANUAL_ENTRY() + * + * exist_board + * + * Check if an EISA board is present in the specified slot. + * + * int exist_board( + * struct s_smc *smc, + * int slot) ; + * In + * smc - A pointer to the SMT Context struct. + * + * slot - The number of the slot to inspect. + * Out + * 0 = No adapter present. + * 1 = Found adapter. + * + * Pseudo + * Read EISA ID + * for all valid OEM_IDs + * compare with ID read + * if equal, return 1 + * return(0 + * + * Note + * The smc pointer must be valid now. + * + ************************/ +int exist_board(smc,slot) +struct s_smc *smc ; +int slot ; +{ + int i ; +#ifdef MULT_OEM + SK_LOC_DECL(u_char,id[4]) ; +#endif /* MULT_OEM */ + + /* No longer valid. */ + if (smc == NULL) + return(0); + + SK_UNUSED(slot) ; + +#ifndef MULT_OEM + for (i = 0 ; i < 4 ; i++) { + if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i)) + return(0) ; + } + return(1) ; +#else /* MULT_OEM */ + for (i = 0 ; i < 4 ; i++) + id[i] = inp(SADDR(slot)+PRA(i)) ; + + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; + + for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { + if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) + continue ; + + if (is_equal_num(&id[0],&OEMID(smc,0),4)) + return (1) ; + } + return (0) ; /* No adapter found. */ +#endif /* MULT_OEM */ +} + + +int get_board_para(smc,slot) +struct s_smc *smc ; +int slot ; +{ + int i ; + + if (!exist_board(smc,slot)) + return(0) ; + + smc->hw.slot = slot ; +#ifndef MEM_MAPPED_IO /* if defined by the operating system */ + smc->hw.iop = SADDR(slot) ; +#endif + + if (!(inp(C0_A(0))&CFG_CARD_EN)) { + return(2) ; /* CFG_CARD_EN bit not set! */ + } + + smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ; + smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ; + + if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f) + smc->hw.eprom = opt_eproms[i] ; + else + smc->hw.eprom = 0 ; + + smc->hw.DmaWriteExtraBytes = 8 ; + + return(1) ; +} +#endif /* EISA */ + +#ifdef ISA +#ifndef MULT_OEM +const u_char sklogo[6] = SKLOGO_STR ; +#define SIZE_SKLOGO(smc) sizeof(sklogo) +#define SKLOGO(smc,i) sklogo[i] +#else /* MULT_OEM */ +#define SIZE_SKLOGO(smc) smc->hw.oem_id->oi_logo_len +#define SKLOGO(smc,i) smc->hw.oem_id->oi_logo[i] +#endif /* MULT_OEM */ + + +int exist_board(smc,port) +struct s_smc *smc ; +HW_PTR port ; +{ + int i ; +#ifdef MULT_OEM + int bytes_read ; + u_char board_logo[15] ; + SK_LOC_DECL(u_char,id[4]) ; +#endif /* MULT_OEM */ + + /* No longer valid. */ + if (smc == NULL) + return(0); + + SK_UNUSED(smc) ; +#ifndef MULT_OEM + for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) { + if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) { + return(0) ; + } + } + + /* check MAC address (S&K or other) */ + for (i = 0 ; i < 3 ; i++) { + if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i)) + return(0) ; + } + return(1) ; +#else /* MULT_OEM */ + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; + board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ; + bytes_read = 1 ; + + for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { + if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) + continue ; + + /* Test all read bytes with current OEM_entry */ + /* for (i=0; (ihw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; + for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { + if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) + continue ; +#endif + ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ; + dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ; + for (i = 0; i < slot; i++) { + if (pci_find_device(i,&smc->hw.pci_handle, + dev_id,ven_id) != 0) { + + found = FALSE ; + } else { + found = TRUE ; + } + } + if (found) { + return(1) ; /* adapter was found */ + } +#ifdef MULT_OEM + } +#endif + return(0) ; /* adapter was not found */ +} +#endif /* PCI */ +#endif /* USE_BIOS_FUNC */ + +void driver_get_bia(smc, bia_addr) +struct s_smc *smc ; +struct fddi_addr *bia_addr ; +{ + int i ; + + extern const u_char canonical[256] ; + + for (i = 0 ; i < 6 ; i++) { + bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ; + } +} + +void smt_start_watchdog(smc) +struct s_smc *smc ; +{ + SK_UNUSED(smc) ; /* Make LINT happy. */ + +#ifndef DEBUG + +#ifdef PCI + if (smc->hw.wdog_used) { + outpw(ADDR(B2_WDOG_CRTL),TIM_START) ; /* Start timer. */ + } +#endif + +#endif /* DEBUG */ +} + +void smt_stop_watchdog(smc) +struct s_smc *smc ; +{ + SK_UNUSED(smc) ; /* Make LINT happy. */ +#ifndef DEBUG + +#ifdef PCI + if (smc->hw.wdog_used) { + outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ; /* Stop timer. */ + } +#endif + +#endif /* DEBUG */ +} + +#ifdef PCI +static char get_rom_byte(smc,addr) +struct s_smc *smc ; +u_short addr ; +{ + GET_PAGE(addr) ; + return (READ_PROM(ADDR(B2_FDP))) ; +} + +/* + * ROM image defines + */ +#define ROM_SIG_1 0 +#define ROM_SIG_2 1 +#define PCI_DATA_1 0x18 +#define PCI_DATA_2 0x19 + +/* + * PCI data structure defines + */ +#define VPD_DATA_1 0x08 +#define VPD_DATA_2 0x09 +#define IMAGE_LEN_1 0x10 +#define IMAGE_LEN_2 0x11 +#define CODE_TYPE 0x14 +#define INDICATOR 0x15 + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_vpd_read) + * mac_drv_vpd_read(smc,buf,size,image) + * + * function DOWNCALL (FDDIWARE) + * reads the VPD data of the FPROM and writes it into the + * buffer + * + * para buf points to the buffer for the VPD data + * size size of the VPD data buffer + * image boot image; code type of the boot image + * image = 0 Intel x86, PC-AT compatible + * 1 OPENBOOT standard for PCI + * 2-FF reserved + * + * returns len number of VPD data bytes read form the FPROM + * <0 number of read bytes + * >0 error: data invalid + * + * END_MANUAL_ENTRY + */ +int mac_drv_vpd_read(smc,buf,size,image) +struct s_smc *smc ; +char *buf ; +int size ; +char image ; +{ + u_short ibase ; + u_short pci_base ; + u_short vpd ; + int len ; + + len = 0 ; + ibase = 0 ; + /* + * as long images defined + */ + while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 && + (u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) { + /* + * get the pointer to the PCI data structure + */ + pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) + + (get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ; + + if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) { + /* + * we have the right image, read the VPD data + */ + vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) + + (get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ; + if (vpd == ibase) { + break ; /* no VPD data */ + } + for (len = 0; len < size; len++,buf++,vpd++) { + *buf = get_rom_byte(smc,vpd) ; + } + break ; + } + else { + /* + * try the next image + */ + if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) { + break ; /* this was the last image */ + } + ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) + + (get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ; + } + } + + return(len) ; +} + +void mac_drv_pci_fix(smc,fix_value) +struct s_smc *smc ; +u_long fix_value ; +{ + smc->hw.pci_fix_value = fix_value ; +} + +void mac_do_pci_fix(smc) +struct s_smc *smc ; +{ + SK_UNUSED(smc) ; +} +#endif /* PCI */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/ecm.c linux/drivers/net/skfp/ecm.c --- v2.2.17/drivers/net/skfp/ecm.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/ecm.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,547 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + SMT ECM + Entity Coordination Management + Hardware independant state machine +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependant functions are referenced : + * sm_pm_bypass_req() + * sm_pm_ls_latch() + * sm_pm_get_ls() + * + * The following HW dependant events are required : + * NONE + * + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)ecm.c 2.7 99/08/05 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.fddiSMTECMState = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.fddiSMTECMState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#define EC0_OUT 0 /* not inserted */ +#define EC1_IN 1 /* inserted */ +#define EC2_TRACE 2 /* tracing */ +#define EC3_LEAVE 3 /* leaving the ring */ +#define EC4_PATH_TEST 4 /* performing path test */ +#define EC5_INSERT 5 /* bypass being turned on */ +#define EC6_CHECK 6 /* checking bypass */ +#define EC7_DEINSERT 7 /* bypass being turnde off */ + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const ecm_states[] = { + "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST", + "EC5_INSERT","EC6_CHECK","EC7_DEINSERT" +} ; + +/* + * symbolic event names + */ +static const char * const ecm_events[] = { + "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST", + "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX", + "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE" +} ; +#endif + +/* + * all Globals are defined in smc.h + * struct s_ecm + */ + +/* + * function declarations + */ + +static void ecm_fsm() ; +static void start_ecm_timer() ; +static void stop_ecm_timer() ; +static void prop_actions() ; + +/* + init ECM state machine + clear all ECM vars and flags +*/ +void ecm_init(smc) +struct s_smc *smc ; +{ + smc->e.path_test = PT_PASSED ; + smc->e.trace_prop = 0 ; + smc->e.sb_flag = 0 ; + smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ; + smc->e.ecm_line_state = FALSE ; +} + +/* + ECM state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void ecm(smc,event) +struct s_smc *smc ; +int event ; +{ + int state ; + + do { + DB_ECM("ECM : state %s%s", + (smc->mib.fddiSMTECMState & AFLAG) ? "ACTIONS " : "", + ecm_states[smc->mib.fddiSMTECMState & ~AFLAG]) ; + DB_ECM(" event %s\n",ecm_events[event],0) ; + state = smc->mib.fddiSMTECMState ; + ecm_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.fddiSMTECMState) ; + ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ; +} + +/* + process ECM event +*/ +static void ecm_fsm(smc,cmd) +struct s_smc *smc ; +int cmd ; +{ + int ls_a ; /* current line state PHY A */ + int ls_b ; /* current line state PHY B */ + int p ; /* ports */ + + + smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ; + if (cmd == EC_CONNECT) + smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; + + /* For AIX event notification: */ + /* Is a disconnect command remotely issued ? */ + if (cmd == EC_DISCONNECT && + smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) + AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long) + FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc), + smt_get_error_word(smc) ); + + /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/ + if (cmd == EC_CONNECT) { + smc->e.DisconnectFlag = FALSE ; + } + else if (cmd == EC_DISCONNECT) { + smc->e.DisconnectFlag = TRUE ; + } + + switch(smc->mib.fddiSMTECMState) { + case ACTIONS(EC0_OUT) : + /* + * We do not perform a path test + */ + smc->e.path_test = PT_PASSED ; + smc->e.ecm_line_state = FALSE ; + stop_ecm_timer(smc) ; + ACTIONS_DONE() ; + break ; + case EC0_OUT: + /*EC01*/ + if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent + && smc->e.path_test==PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC05*/ + else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) && + smc->mib.fddiSMTBypassPresent && + (smc->s.sas == SMT_DAS)) { + GO_STATE(EC5_INSERT) ; + break ; + } + break; + case ACTIONS(EC1_IN) : + stop_ecm_timer(smc) ; + smc->e.trace_prop = 0 ; + sm_ma_control(smc,MA_TREQ) ; + for (p = 0 ; p < NUMPHYS ; p++) + if (smc->mib.p[p].fddiPORTHardwarePresent) + queue_event(smc,EVENT_PCMA+p,PC_START) ; + ACTIONS_DONE() ; + break ; + case EC1_IN: + /*EC12*/ + if (cmd == EC_TRACE_PROP) { + prop_actions(smc) ; + GO_STATE(EC2_TRACE) ; + break ; + } + /*EC13*/ + else if (cmd == EC_DISCONNECT) { + GO_STATE(EC3_LEAVE) ; + break ; + } + break; + case ACTIONS(EC2_TRACE) : + start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration), + EC_TIMEOUT_TMAX) ; + ACTIONS_DONE() ; + break ; + case EC2_TRACE : + /*EC22*/ + if (cmd == EC_TRACE_PROP) { + prop_actions(smc) ; + GO_STATE(EC2_TRACE) ; + break ; + } + /*EC23a*/ + else if (cmd == EC_DISCONNECT) { + smc->e.path_test = PT_EXITING ; + GO_STATE(EC3_LEAVE) ; + break ; + } + /*EC23b*/ + else if (smc->e.path_test == PT_PENDING) { + GO_STATE(EC3_LEAVE) ; + break ; + } + /*EC23c*/ + else if (cmd == EC_TIMEOUT_TMAX) { + /* Trace_Max is expired */ + /* -> send AIX_EVENT */ + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, + (u_long) FDDI_SMT_ERROR, (u_long) + FDDI_TRACE_MAX, smt_get_error_word(smc)); + smc->e.path_test = PT_PENDING ; + GO_STATE(EC3_LEAVE) ; + break ; + } + break ; + case ACTIONS(EC3_LEAVE) : + start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ; + for (p = 0 ; p < NUMPHYS ; p++) + queue_event(smc,EVENT_PCMA+p,PC_STOP) ; + ACTIONS_DONE() ; + break ; + case EC3_LEAVE: + /*EC30*/ + if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent && + (smc->e.path_test != PT_PENDING)) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC34*/ + else if (cmd == EC_TIMEOUT_TD && + (smc->e.path_test == PT_PENDING)) { + GO_STATE(EC4_PATH_TEST) ; + break ; + } + /*EC31*/ + else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC33*/ + else if (cmd == EC_DISCONNECT && + smc->e.path_test == PT_PENDING) { + smc->e.path_test = PT_EXITING ; + /* + * stay in state - state will be left via timeout + */ + } + /*EC37*/ + else if (cmd == EC_TIMEOUT_TD && + smc->mib.fddiSMTBypassPresent && + smc->e.path_test != PT_PENDING) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC4_PATH_TEST) : + stop_ecm_timer(smc) ; + smc->e.path_test = PT_TESTING ; + start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ; + /* now perform path test ... just a simulation */ + ACTIONS_DONE() ; + break ; + case EC4_PATH_TEST : + /* path test done delay */ + if (cmd == EC_TEST_DONE) + smc->e.path_test = PT_PASSED ; + + if (smc->e.path_test == PT_FAILED) + RS_SET(smc,RS_PATHTEST) ; + + /*EC40a*/ + if (smc->e.path_test == PT_FAILED && + !smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC40b*/ + else if (cmd == EC_DISCONNECT && + !smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC41*/ + else if (smc->e.path_test == PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC47a*/ + else if (smc->e.path_test == PT_FAILED && + smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + /*EC47b*/ + else if (cmd == EC_DISCONNECT && + smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC5_INSERT) : + sm_pm_bypass_req(smc,BP_INSERT); + start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ; + ACTIONS_DONE() ; + break ; + case EC5_INSERT : + /*EC56*/ + if (cmd == EC_TIMEOUT_INMAX) { + GO_STATE(EC6_CHECK) ; + break ; + } + /*EC57*/ + else if (cmd == EC_DISCONNECT) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC6_CHECK) : + /* + * in EC6_CHECK, we *POLL* the line state ! + * check whether both bypass switches have switched. + */ + start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; + smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */ + (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */ + (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */ + ACTIONS_DONE() ; + break ; + case EC6_CHECK : + ls_a = sm_pm_get_ls(smc,PA) ; + ls_b = sm_pm_get_ls(smc,PB) ; + + /*EC61*/ + if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) && + ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) { + smc->e.sb_flag = FALSE ; + smc->e.ecm_line_state = FALSE ; + GO_STATE(EC1_IN) ; + break ; + } + /*EC66*/ + else if (!smc->e.sb_flag && + (((ls_a == PC_ILS) && (ls_b == PC_QLS)) || + ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){ + smc->e.sb_flag = TRUE ; + DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK, + smt_get_error_word(smc)); + } + /*EC67*/ + else if (cmd == EC_DISCONNECT) { + smc->e.ecm_line_state = FALSE ; + GO_STATE(EC7_DEINSERT) ; + break ; + } + else { + /* + * restart poll + */ + start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; + } + break ; + case ACTIONS(EC7_DEINSERT) : + sm_pm_bypass_req(smc,BP_DEINSERT); + start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ; + ACTIONS_DONE() ; + break ; + case EC7_DEINSERT: + /*EC70*/ + if (cmd == EC_TIMEOUT_IMAX) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC75*/ + else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { + GO_STATE(EC5_INSERT) ; + break ; + } + break; + default: + SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ; + break; + } +} + +#ifndef CONCENTRATOR +/* + * trace propagation actions for SAS & DAS + */ +static void prop_actions(smc) +struct s_smc *smc ; +{ + int port_in = 0 ; + int port_out = 0 ; + + RS_SET(smc,RS_EVENT) ; + switch (smc->s.sas) { + case SMT_SAS : + port_in = port_out = pcm_get_s_port(smc) ; + break ; + case SMT_DAS : + port_in = cfm_get_mac_input(smc) ; /* PA or PB */ + port_out = cfm_get_mac_output(smc) ; /* PA or PB */ + break ; + case SMT_NAC : + SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ; + return ; + } + + DB_ECM("ECM : prop_actions - trace_prop %d\n", smc->e.trace_prop,0) ; + DB_ECM("ECM : prop_actions - in %d out %d\n", port_in,port_out) ; + + if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { + /* trace initiatior */ + DB_ECM("ECM : initiate TRACE on PHY %c\n",'A'+port_in-PA,0) ; + queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ; + } + else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) && + port_out != PA) { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY B\n",0,0) ; + queue_event(smc,EVENT_PCMB,PC_TRACE) ; + } + else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) && + port_out != PB) { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY A\n",0,0) ; + queue_event(smc,EVENT_PCMA,PC_TRACE) ; + } + else { + /* signal trace termination */ + DB_ECM("ECM : TRACE terminated\n",0,0) ; + smc->e.path_test = PT_PENDING ; + } + smc->e.trace_prop = 0 ; +} +#else +/* + * trace propagation actions for Concentrator + */ +static void prop_actions(smc) +struct s_smc *smc ; +{ + int initiator ; + int upstream ; + int p ; + + RS_SET(smc,RS_EVENT) ; + while (smc->e.trace_prop) { + DB_ECM("ECM : prop_actions - trace_prop %d\n", + smc->e.trace_prop,0) ; + + if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { + initiator = ENTITY_MAC ; + smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ; + DB_ECM("ECM: MAC initiates trace\n",0,0) ; + } + else { + for (p = NUMPHYS-1 ; p >= 0 ; p--) { + if (smc->e.trace_prop & + ENTITY_BIT(ENTITY_PHY(p))) + break ; + } + initiator = ENTITY_PHY(p) ; + smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ; + } + upstream = cem_get_upstream(smc,initiator) ; + + if (upstream == ENTITY_MAC) { + /* signal trace termination */ + DB_ECM("ECM : TRACE terminated\n",0,0) ; + smc->e.path_test = PT_PENDING ; + } + else { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY %d\n",upstream,0) ; + queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ; + } + } +} +#endif + + +/* + * SMT timer interface + * start ECM timer + */ +static void start_ecm_timer(smc,value,event) +struct s_smc *smc ; +u_long value; +int event ; +{ + smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event)); +} + +/* + * SMT timer interface + * stop ECM timer + */ +static void stop_ecm_timer(smc) +struct s_smc *smc ; +{ + if (smc->e.ecm_timer.tm_active) + smt_timer_stop(smc,&smc->e.ecm_timer) ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/ess.c linux/drivers/net/skfp/ess.c --- v2.2.17/drivers/net/skfp/ess.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/ess.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,732 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + * ******************************************************************* + * This SBA code implements the Synchronous Bandwidth Allocation + * functions described in the "FDDI Synchronous Forum Implementer's + * Agreement" dated December 1th, 1993. + * ******************************************************************* + * + * PURPOSE: The purpose of this function is to control + * synchronous allocations on a single FDDI segment. + * Allocations are limited to the primary FDDI ring. + * The SBM provides recovery mechanisms to recover + * unused bandwidth also resolves T_Neg and + * reconfiguration changes. Many of the SBM state + * machine inputs are sourced by the underlying + * FDDI sub-system supporting the SBA application. + * + * ******************************************************************* + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + + +#ifndef SLIM_SMT + +#ifdef ESS + +#ifndef lint +static const char ID_sccs[] = "@(#)ess.c 1.10 96/02/23 (C) SK" ; +#define LINT_USE(x) +#else +#define LINT_USE(x) (x)=(x) +#endif +#define MS2BCLK(x) ((x)*12500L) + +/* + ------------------------------------------------------------- + LOCAL VARIABLES: + ------------------------------------------------------------- +*/ + +static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F, + SMT_P3210, SMT_P0019, SMT_P001A, + SMT_P001D, 0 } ; + +static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210, + SMT_P001A, 0 } ; + +static const struct fddi_addr smt_sba_da = {{0x80,0x01,0x43,0x00,0x80,0x0C}} ; +static const struct fddi_addr null_addr = {{0,0,0,0,0,0}} ; + +/* + ------------------------------------------------------------- + GLOBAL VARIABLES: + ------------------------------------------------------------- +*/ + + +/* + ------------------------------------------------------------- + LOCAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +static void ess_send_response(), ess_config_fifo(), + ess_send_alc_req(), ess_send_frame() ; + +/* + ------------------------------------------------------------- + EXTERNAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +extern void *sm_to_para() ; + +extern void smt_send_frame(), smt_free_mbuf(), + set_formac_tsync(), formac_reinit_tx() ; + +extern int smt_check_para() ; + +extern SMbuf *smt_get_mbuf(), *smt_build_frame() ; + +extern u_long smt_get_tid() ; + +/* + ------------------------------------------------------------- + PUBLIC FUNCTIONS: + ------------------------------------------------------------- +*/ + + void ess_timer_poll(), ess_para_change() ; + + int ess_raf_received_pack(), process_bw_alloc() ; + + +/* + * -------------------------------------------------------------------------- + * End Station Support (ESS) + * -------------------------------------------------------------------------- + */ + +/* + * evaluate the RAF frame + */ +int ess_raf_received_pack(smc,mb,sm,fs) +struct s_smc *smc ; +SMbuf *mb ; +struct smt_header *sm ; +int fs ; +{ + void *p ; /* universal pointer */ + struct smt_p_0016 *cmd ; /* para: command for the ESS */ + SMbuf *db ; + u_long msg_res_type ; /* recource type */ + u_long payload, overhead ; + int local ; + int i ; + + /* + * Message Processing Code + */ + local = ((fs & L_INDICATOR) != 0) ; + + /* + * get the resource type + */ + if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) { + DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ; + return(fs) ; + } + msg_res_type = ((struct smt_p_0015 *)p)->res_type ; + + /* + * get the pointer to the ESS command + */ + if (!(cmd = (struct smt_p_0016 *) sm_to_para(smc,sm,SMT_P0016))) { + /* + * error in frame: para ESS command was not found + */ + DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0); + return(fs) ; + } + + DB_ESSN(2,"fc %x ft %x\n",sm->smt_class,sm->smt_type) ; + DB_ESSN(2,"ver %x tran %lx\n",sm->smt_version,sm->smt_tid) ; + DB_ESSN(2,"stn_id %s\n",addr_to_string(&sm->smt_source),0) ; + + DB_ESSN(2,"infolen %x res %x\n",sm->smt_len, msg_res_type) ; + DB_ESSN(2,"sbacmd %x\n",cmd->sba_cmd,0) ; + + /* + * evaluate the ESS command + */ + switch (cmd->sba_cmd) { + + /* + * Process an ESS Allocation Request + */ + case REQUEST_ALLOCATION : + /* + * check for an RAF Request (Allocation Request) + */ + if (sm->smt_type == SMT_REQUEST) { + /* + * process the Allocation request only if the frame is + * local and no static allocation is used + */ + if (!local || smc->mib.fddiESSPayload) + return(fs) ; + + p = (void *) sm_to_para(smc,sm,SMT_P0019) ; + for (i = 0; i < 5; i++) { + if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) { + return(fs) ; + } + } + + /* + * Note: The Application should send a LAN_LOC_FRAME. + * The ESS do not send the Frame to the network! + */ + smc->ess.alloc_trans_id = sm->smt_tid ; + DB_ESS("ESS: save Alloc Req Trans ID %lx\n",sm->smt_tid,0); + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + ((struct smt_p_320f *)p)->mib_payload = + smc->mib.a[PATH0].fddiPATHSbaPayload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + ((struct smt_p_3210 *)p)->mib_overhead = + smc->mib.a[PATH0].fddiPATHSbaOverhead ; + sm->smt_dest = smt_sba_da ; + + if (smc->ess.local_sba_active) + return(fs | I_INDICATOR) ; + + if (!(db = smt_get_mbuf(smc))) + return(fs) ; + + db->sm_len = mb->sm_len ; + db->sm_off = mb->sm_off ; + memcpy(((char *)(db->sm_data+db->sm_off)),(char *)sm, + (int)db->sm_len) ; + dump_smt(smc, + (struct smt_header *)(db->sm_data+db->sm_off), + "RAF") ; + smt_send_frame(smc,db,FC_SMT_INFO,0) ; + return(fs) ; + } + + /* + * The RAF frame is an Allocation Response ! + * check the parameters + */ + if (smt_check_para(smc,sm,plist_raf_alc_res)) { + DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; + return(fs) ; + } + + /* + * VERIFY THE FRAME IS WELL BUILT: + * + * 1. path index = primary ring only + * 2. resource type = sync bw only + * 3. trans action id = alloc_trans_id + * 4. reason code = success + * + * If any are violated, discard the RAF frame + */ + if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index + != PRIMARY_RING) || + (msg_res_type != SYNC_BW) || + (((struct smt_p_reason *)sm_to_para(smc,sm,SMT_P0012))->rdf_reason + != SMT_RDF_SUCCESS) || + (sm->smt_tid != smc->ess.alloc_trans_id)) { + + DB_ESS("ESS: Allocation Responce not accepted\n",0,0) ; + return(fs) ; + } + + /* + * Extract message parameters + */ + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + payload = ((struct smt_p_320f *)p)->mib_payload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + overhead = ((struct smt_p_3210 *)p)->mib_overhead ; + + DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; + + /* + * process the bandwidth allocation + */ + (void)process_bw_alloc(smc,(long)payload,(long)overhead) ; + + return(fs) ; + /* end of Process Allocation Request */ + + /* + * Process an ESS Change Request + */ + case CHANGE_ALLOCATION : + /* + * except only replies + */ + if (sm->smt_type != SMT_REQUEST) { + DB_ESS("ESS: Do not process Change Responses\n",0,0) ; + return(fs) ; + } + + /* + * check the para for the Change Request + */ + if (smt_check_para(smc,sm,plist_raf_chg_req)) { + DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; + return(fs) ; + } + + /* + * Verify the path index and resource + * type are correct. If any of + * these are false, don't process this + * change request frame. + */ + if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index + != PRIMARY_RING) || (msg_res_type != SYNC_BW)) { + DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ; + return(fs) ; + } + + /* + * Extract message queue parameters + */ + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + payload = ((struct smt_p_320f *)p)->mib_payload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + overhead = ((struct smt_p_3210 *)p)->mib_overhead ; + + DB_ESSN(2,"ESS: Change Request from %s\n", + addr_to_string(&sm->smt_source),0) ; + DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; + + /* + * process the bandwidth allocation + */ + if(!process_bw_alloc(smc,(long)payload,(long)overhead)) + return(fs) ; + + /* + * send an RAF Change Reply + */ + ess_send_response(smc,sm,CHANGE_ALLOCATION) ; + + return(fs) ; + /* end of Process Change Request */ + + /* + * Process Report Response + */ + case REPORT_ALLOCATION : + /* + * except only requests + */ + if (sm->smt_type != SMT_REQUEST) { + DB_ESS("ESS: Do not process a Report Reply\n",0,0) ; + return(fs) ; + } + + DB_ESSN(2,"ESS: Report Request from %s\n", + addr_to_string(&(sm->smt_source)),0) ; + + /* + * verify that the resource type is sync bw only + */ + if (msg_res_type != SYNC_BW) { + DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ; + return(fs) ; + } + + /* + * send an RAF Change Reply + */ + ess_send_response(smc,sm,REPORT_ALLOCATION) ; + + return(fs) ; + /* end of Process Report Request */ + + default: + /* + * error in frame + */ + DB_ESS("ESS: ignoring RAF with bad sba_cmd\n",0,0) ; + break ; + } + + return(fs) ; +} + +/* + * determines the synchronous bandwidth, set the TSYNC register and the + * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG. + */ +int process_bw_alloc(smc,payload,overhead) +struct s_smc *smc ; +long payload ; +long overhead ; +{ + /* + * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG, + * if the payload is greater than zero. + * For the SBAPayload and the SBAOverhead we have the following + * unite quations + * _ _ + * | bytes | + * SBAPayload = | 8000 ------ | + * | s | + * - - + * _ _ + * | bytes | + * SBAOverhead = | ------ | + * | T-NEG | + * - - + * + * T-NEG is discribed by the equation: + * + * (-) fddiMACT-NEG + * T-NEG = ------------------- + * 12500000 1/s + * + * The number of bytes we are able to send is the payload + * plus the overhead. + * + * bytes T-NEG SBAPayload 8000 bytes/s + * sync_bw = SBAOverhead ------ + ----------------------------- + * T-NEG T-NEG + * + * + * 1 + * sync_bw = SBAOverhead + ---- (-)fddiMACT-NEG * SBAPayload + * 1562 + * + */ + + /* + * set the mib attributes fddiPATHSbaOverhead, fddiPATHSbaPayload + */ +/* if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) { + DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ; + return(FALSE) ; + } + if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) { + DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ; + return(FALSE) ; + } */ + + /* premliminary */ + if (payload > MAX_PAYLOAD || overhead > 5000) { + DB_ESS("ESS: payload / overhead not accepted\n",0,0) ; + return(FALSE) ; + } + + /* + * start the iterative allocation process if the payload or the overhead + * are smaller than the parsed values + */ + if (smc->mib.fddiESSPayload && + ((u_long)payload != smc->mib.fddiESSPayload || + (u_long)overhead != smc->mib.fddiESSOverhead)) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->ess.timer_count = 0 ; + } + + /* + * evulate the Payload + */ + if (payload) { + DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit on\n",0,0) ; + smc->ess.sync_bw_available = TRUE ; + + smc->ess.sync_bw = overhead - + (long)smc->mib.m[MAC0].fddiMACT_Neg * + payload / 1562 ; + } + else { + DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit off\n",0,0) ; + smc->ess.sync_bw_available = FALSE ; + smc->ess.sync_bw = 0 ; + overhead = 0 ; + } + + smc->mib.a[PATH0].fddiPATHSbaPayload = payload ; + smc->mib.a[PATH0].fddiPATHSbaOverhead = overhead ; + + + DB_ESSN(2,"tsync = %lx\n",smc->ess.sync_bw,0) ; + + ess_config_fifo(smc) ; + set_formac_tsync(smc,smc->ess.sync_bw) ; + return(TRUE) ; +} + +static void ess_send_response(smc,sm,sba_cmd) +struct s_smc *smc ; +struct smt_header *sm ; +int sba_cmd ; +{ + struct smt_sba_chg *chg ; + SMbuf *mb ; + void *p ; + + /* + * get and initialize the responce frame + */ + if (sba_cmd == CHANGE_ALLOCATION) { + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, + sizeof(struct smt_sba_chg)))) + return ; + } + else { + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, + sizeof(struct smt_sba_rep_res)))) + return ; + } + + chg = smtod(mb,struct smt_sba_chg *) ; + chg->smt.smt_tid = sm->smt_tid ; + chg->smt.smt_dest = sm->smt_source ; + + /* set P15 */ + chg->s_type.para.p_type = SMT_P0015 ; + chg->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; + chg->s_type.res_type = SYNC_BW ; + + /* set P16 */ + chg->cmd.para.p_type = SMT_P0016 ; + chg->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; + chg->cmd.sba_cmd = sba_cmd ; + + /* set P320B */ + chg->path.para.p_type = SMT_P320B ; + chg->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; + chg->path.mib_index = SBAPATHINDEX ; + chg->path.path_pad = (u_short)NULL ; + chg->path.path_index = PRIMARY_RING ; + + /* set P320F */ + chg->payload.para.p_type = SMT_P320F ; + chg->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; + chg->payload.mib_index = SBAPATHINDEX ; + chg->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P3210 */ + chg->overhead.para.p_type = SMT_P3210 ; + chg->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; + chg->overhead.mib_index = SBAPATHINDEX ; + chg->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + if (sba_cmd == CHANGE_ALLOCATION) { + /* set P1A */ + chg->cat.para.p_type = SMT_P001A ; + chg->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; + p = (void *) sm_to_para(smc,sm,SMT_P001A) ; + chg->cat.category = ((struct smt_p_001a *)p)->category ; + } + dump_smt(smc,(struct smt_header *)chg,"RAF") ; + ess_send_frame(smc,mb) ; +} + + +void ess_timer_poll(smc) +struct s_smc *smc ; +{ + if (!smc->ess.raf_act_timer_poll) + return ; + + DB_ESSN(2,"ESS: timer_poll\n",0,0) ; + + smc->ess.timer_count++ ; + if (smc->ess.timer_count == 10) { + smc->ess.timer_count = 0 ; + ess_send_alc_req(smc) ; + } +} + +static void ess_send_alc_req(smc) +struct s_smc *smc ; +{ + struct smt_sba_alc_req *req ; + SMbuf *mb ; + + /* + * send never allocation request where the requested payload and + * overhead is zero or deallocate bandwidht when no bandwidth is + * parsed + */ + if (!smc->mib.fddiESSPayload) { + smc->mib.fddiESSOverhead = 0 ; + } + else { + if (!smc->mib.fddiESSOverhead) + smc->mib.fddiESSOverhead = DEFAULT_OV ; + } + + if (smc->mib.fddiESSOverhead == + smc->mib.a[PATH0].fddiPATHSbaOverhead && + smc->mib.fddiESSPayload == + smc->mib.a[PATH0].fddiPATHSbaPayload){ + smc->ess.raf_act_timer_poll = FALSE ; + smc->ess.timer_count = 7 ; /* next RAF alc req after 3 s */ + return ; + } + + /* + * get and initialize the responce frame + */ + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST, + sizeof(struct smt_sba_alc_req)))) + return ; + req = smtod(mb,struct smt_sba_alc_req *) ; + req->smt.smt_tid = smc->ess.alloc_trans_id = smt_get_tid(smc) ; + req->smt.smt_dest = smt_sba_da ; + + /* set P15 */ + req->s_type.para.p_type = SMT_P0015 ; + req->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; + req->s_type.res_type = SYNC_BW ; + + /* set P16 */ + req->cmd.para.p_type = SMT_P0016 ; + req->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; + req->cmd.sba_cmd = REQUEST_ALLOCATION ; + + /* + * set the parameter type and parameter lenght of all used + * parameters + */ + + /* set P320B */ + req->path.para.p_type = SMT_P320B ; + req->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; + req->path.mib_index = SBAPATHINDEX ; + req->path.path_pad = (u_short)NULL ; + req->path.path_index = PRIMARY_RING ; + + /* set P0017 */ + req->pl_req.para.p_type = SMT_P0017 ; + req->pl_req.para.p_len = sizeof(struct smt_p_0017) - PARA_LEN ; + req->pl_req.sba_pl_req = smc->mib.fddiESSPayload - + smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P0018 */ + req->ov_req.para.p_type = SMT_P0018 ; + req->ov_req.para.p_len = sizeof(struct smt_p_0018) - PARA_LEN ; + req->ov_req.sba_ov_req = smc->mib.fddiESSOverhead - + smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + /* set P320F */ + req->payload.para.p_type = SMT_P320F ; + req->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; + req->payload.mib_index = SBAPATHINDEX ; + req->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P3210 */ + req->overhead.para.p_type = SMT_P3210 ; + req->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; + req->overhead.mib_index = SBAPATHINDEX ; + req->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + /* set P19 */ + req->a_addr.para.p_type = SMT_P0019 ; + req->a_addr.para.p_len = sizeof(struct smt_p_0019) - PARA_LEN ; + req->a_addr.sba_pad = (u_short)NULL ; + req->a_addr.alloc_addr = null_addr ; + + /* set P1A */ + req->cat.para.p_type = SMT_P001A ; + req->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; + req->cat.category = smc->mib.fddiESSCategory ; + + /* set P1B */ + req->tneg.para.p_type = SMT_P001B ; + req->tneg.para.p_len = sizeof(struct smt_p_001b) - PARA_LEN ; + req->tneg.max_t_neg = smc->mib.fddiESSMaxTNeg ; + + /* set P1C */ + req->segm.para.p_type = SMT_P001C ; + req->segm.para.p_len = sizeof(struct smt_p_001c) - PARA_LEN ; + req->segm.min_seg_siz = smc->mib.fddiESSMinSegmentSize ; + + dump_smt(smc,(struct smt_header *)req,"RAF") ; + ess_send_frame(smc,mb) ; +} + +static void ess_send_frame(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + /* + * check if the frame must be send to the own ESS + */ + if (smc->ess.local_sba_active) { + /* + * Send the Change Reply to the local SBA + */ + DB_ESS("ESS:Send to the local SBA\n",0,0) ; + if (!smc->ess.sba_reply_pend) + smc->ess.sba_reply_pend = mb ; + else { + DB_ESS("Frame is lost - another frame was pending\n",0,0); + smt_free_mbuf(smc,mb) ; + } + } + else { + /* + * Send the SBA RAF Change Reply to the network + */ + DB_ESS("ESS:Send to the network\n",0,0) ; + smt_send_frame(smc,mb,FC_SMT_INFO,0) ; + } +} + +void ess_para_change(smc) +struct s_smc *smc ; +{ + (void)process_bw_alloc(smc,(long)smc->mib.a[PATH0].fddiPATHSbaPayload, + (long)smc->mib.a[PATH0].fddiPATHSbaOverhead) ; +} + +static void ess_config_fifo(smc) +struct s_smc *smc ; +{ + /* + * if nothing to do exit + */ + if (smc->mib.a[PATH0].fddiPATHSbaPayload) { + if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON && + (smc->hw.fp.fifo.fifo_config_mode&SEND_ASYNC_AS_SYNC) == + smc->mib.fddiESSSynchTxMode) { + return ; + } + } + else { + if (!(smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON)) { + return ; + } + } + + /* + * split up the FIFO and reinitialize the queues + */ + formac_reinit_tx(smc) ; +} + +#endif /* ESS */ + +#endif /* no SLIM_SMT */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/fplustm.c linux/drivers/net/skfp/fplustm.c --- v2.2.17/drivers/net/skfp/fplustm.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/fplustm.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,1645 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + * FORMAC+ Driver for tag mode + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "can.c" + +#ifndef lint +static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ; +#endif + +#ifndef UNUSED +#ifdef lint +#define UNUSED(x) (x) = (x) +#else +#define UNUSED(x) +#endif +#endif + +#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x)*1250L) + +/* + * prototypes for static function + */ +static void build_claim_beacon() ; +static int init_mac() ; +static void rtm_init() ; +static void smt_split_up_fifo() ; + +#if (!defined(NO_SMT_PANIC) || defined(DEBUG)) +static char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n"; +static char cam_warning [] = "E_SMT_004: CAM still busy\n"; +#endif + +#define DUMMY_READ() smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP)) + +#define CHECK_NPP() { unsigned k = 10000 ;\ + while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\ + if (!k) { \ + SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \ + } \ + } + +#define CHECK_CAM() { unsigned k = 10 ;\ + while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\ + if (!k) { \ + SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \ + } \ + } + +const struct fddi_addr fddi_broadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static const struct fddi_addr null_addr = {{0,0,0,0,0,0}}; +static const struct fddi_addr dbeacon_multi = {{0x01,0x80,0xc2,0x00,0x01,0x00}}; + +static const u_short my_said = 0xffff ; /* short address (n.u.) */ +static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */ + +/* + * define my address + */ +#ifdef USE_CAN_ADDR +#define MA smc->hw.fddi_canon_addr +#else +#define MA smc->hw.fddi_home_addr +#endif + + +/* + * usefull interrupt bits + */ +static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; +static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| + FM_STBURS | FM_STBURA0 ; + + /* delete FM_SRBFL after tests */ +static int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL | + FM_SMYCLM ; +static int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR | + FM_SERRCTR | FM_SLSTCTR | + FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ; + +static int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ; +static int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ; + +static int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC | + FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ; + + +static u_long mac_get_tneg(smc) +struct s_smc *smc ; +{ + u_long tneg ; + + tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ; + return((u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) | + 0xffe00000L)) ; +} + +void mac_update_counter(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACFrame_Ct = + (smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_FCNTR)) ; + smc->mib.m[MAC0].fddiMACLost_Ct = + (smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_LCNTR)) ; + smc->mib.m[MAC0].fddiMACError_Ct = + (smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_ECNTR)) ; + smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ; +#ifdef SMT_REAL_TOKEN_CT + /* + * If the token counter is emulated it is updated in smt_event. + */ + TBD +#else + smt_emulate_token_ct( smc, MAC0 ); +#endif +} + +/* + * write long value into buffer memory over memory data register (MDR), + */ +void write_mdr(smc,val) +struct s_smc *smc ; +u_long val; +{ + CHECK_NPP() ; + MDRW(val) ; +} + +/* + * read long value from buffer memory over memory data register (MDR), + */ +u_long read_mdr(smc,addr) +struct s_smc *smc ; +unsigned int addr; +{ + long p ; + CHECK_NPP() ; + MARR(addr) ; + outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ; + CHECK_NPP() ; /* needed for PCI to prevent from timeing violations */ +/* p = MDRR() ; */ /* bad read values if the workaround */ + /* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/ + /* is used */ + p = (u_long)inpw(FM_A(FM_MDRU))<<16 ; + p += (u_long)inpw(FM_A(FM_MDRL)) ; + return(p) ; +} +/* + * clear buffer memory + */ +static void init_ram(smc) +struct s_smc *smc ; +{ + u_short i ; + + smc->hw.fp.fifo.rbc_ram_start = 0 ; + smc->hw.fp.fifo.rbc_ram_end = + smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ; + CHECK_NPP() ; + MARW(smc->hw.fp.fifo.rbc_ram_start) ; + for (i = smc->hw.fp.fifo.rbc_ram_start; + i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++) + write_mdr(smc,0L) ; + /* Erase the last byte too */ + write_mdr(smc,0L) ; +} + +/* + * set receive FIFO pointer + */ +static void set_recvptr(smc) +struct s_smc *smc ; +{ + /* + * initialize the pointer for receive queue 1 + */ + outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* RPR1 */ + outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* SWPR1 */ + outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* WPR1 */ + outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ; /* EARV1 */ + + /* + * initialize the pointer for receive queue 2 + */ + if (smc->hw.fp.fifo.rx2_fifo_size) { + outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; + } + else { + outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; + } +} + +/* + * set transmit FIFO pointer + */ +static void set_txptr(smc) +struct s_smc *smc ; +{ + outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ; /* reset transmit queues */ + + /* + * initialize the pointer for asynchronous transmit queue + */ + outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* RPXA0 */ + outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* SWPXA0 */ + outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* WPXA0 */ + outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ; /* EAA0 */ + + /* + * initialize the pointer for synchronous transmit queue + */ + if (smc->hw.fp.fifo.tx_s_size) { + outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; + } + else { + outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; + } +} + +/* + * init memory buffer management registers + */ +static void init_rbc(smc) +struct s_smc *smc ; +{ + u_short rbc_ram_addr ; + + /* + * set unused pointers or permanent pointers + */ + rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ; + + outpw(FM_A(FM_RPXA1),rbc_ram_addr) ; /* a1-send pointer */ + outpw(FM_A(FM_WPXA1),rbc_ram_addr) ; + outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ; + outpw(FM_A(FM_EAA1),rbc_ram_addr) ; + + set_recvptr(smc) ; + set_txptr(smc) ; +} + +/* + * init rx pointer + */ +static void init_rx(smc) +struct s_smc *smc ; +{ + struct s_smt_rx_queue *queue ; + + /* + * init all tx data structures for receive queue 1 + */ + smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ; + queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ; + queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ; + + /* + * init all tx data structures for receive queue 2 + */ + smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ; + queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ; + queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ; +} + +/* + * set the TSYNC register of the FORMAC to regulate synchronous transmission + */ +void set_formac_tsync(smc,sync_bw) +struct s_smc *smc ; +long sync_bw ; +{ + outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ; +} + +/* + * init all tx data structures + */ +static void init_tx(smc) +struct s_smc *smc ; +{ + struct s_smt_tx_queue *queue ; + + /* + * init all tx data structures for the synchronous queue + */ + smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ; + queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ; + queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ; + +#ifdef ESS + set_formac_tsync(smc,smc->ess.sync_bw) ; +#endif + + /* + * init all tx data structures for the asynchronous queue 0 + */ + smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ; + queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ; + queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ; + + + llc_recover_tx(smc) ; +} + +static void mac_counter_init(smc) +struct s_smc *smc ; +{ + int i ; + u_long *ec ; + + /* + * clear FORMAC+ frame-, lost- and error counter + */ + outpw(FM_A(FM_FCNTR),0) ; + outpw(FM_A(FM_LCNTR),0) ; + outpw(FM_A(FM_ECNTR),0) ; + /* + * clear internal error counter stucture + */ + ec = (u_long *)&smc->hw.fp.err_stats ; + for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--) + *ec++ = 0L ; + smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ; +} + +/* + * set FORMAC address, and t_request + */ +static void set_formac_addr(smc) +struct s_smc *smc ; +{ + long t_requ = smc->mib.m[MAC0].fddiMACT_Req ; + + outpw(FM_A(FM_SAID),my_said) ; /* set short address */ + outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) + + smc->hw.fddi_home_addr.a[5])) ; + outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) + + smc->hw.fddi_home_addr.a[3])) ; + outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) + + smc->hw.fddi_home_addr.a[1])) ; + + outpw(FM_A(FM_SAGP),my_sagp) ; /* set short group address */ + + outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) + + smc->hw.fp.group_addr.a[5])) ; + outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) + + smc->hw.fp.group_addr.a[3])) ; + outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) + + smc->hw.fp.group_addr.a[1])) ; + + /* set r_request regs. (MSW & LSW of TRT ) */ + outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ; + outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ; +} + +void set_int(p,l) +char *p; +int l; +{ + p[0] = (char)(l >> 24) ; + p[1] = (char)(l >> 16) ; + p[2] = (char)(l >> 8) ; + p[3] = (char)(l >> 0) ; +} + +/* + * copy TX descriptor to buffer mem + * append FC field and MAC frame + * if more bit is set in descr + * append pointer to descriptor (endless loop) + * else + * append 'end of chain' pointer + */ +static void copy_tx_mac(smc,td,mac,off,len) +struct s_smc *smc ; +u_long td; /* transmit descriptor */ +struct fddi_mac *mac; /* mac frame pointer */ +unsigned off; /* start address within buffer memory */ +int len ; /* lenght of the frame including the FC */ +{ + int i ; + u_int *p ; + + CHECK_NPP() ; + MARW(off) ; /* set memory address reg for writes */ + + p = (u_int *) mac ; + for (i = (len + 3)/4 ; i ; i--) { + if (i == 1) { + /* last word, set the tag bit */ + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; + } + write_mdr(smc,MDR_REVERSE(*p)) ; + p++ ; + } + + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ + write_mdr(smc,td) ; /* write over memory data reg to buffer */ +} + +/* + BEGIN_MANUAL_ENTRY(module;tests;3) + How to test directed beacon frames + ---------------------------------------------------------------- + + o Insert a break point in the function build_claim_beacon() + before calling copy_tx_mac() for building the claim frame. + o Modify the RM3_DETECT case so that the RM6_DETECT state + will always entered from the RM3_DETECT state (function rmt_fsm(), + rmt.c) + o Compile the driver. + o Set the parameter TREQ in the protocol.ini or net.cfg to a + small value to make sure your station will win the claim + process. + o Start the driver. + o When you reach the break point, modify the SA and DA address + of the claim frame (e.g. SA = DA = 10005affffff). + o When you see RM3_DETECT and RM6_DETECT, observe the direct + beacon frames on the UPPSLANA. + + END_MANUAL_ENTRY + */ +static void directed_beacon(smc) +struct s_smc *smc ; +{ + SK_LOC_DECL(u_int,a[2]) ; + + /* + * set UNA in frame + * enable FORMAC to send endless queue of directed beacon + * important: the UNA starts at byte 1 (not at byte 0) + */ + * (char *) a = (char) ((long)DBEACON_INFO<<24L) ; + a[1] = 0 ; + memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ; + + CHECK_NPP() ; + /* set memory address reg for writes */ + MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ; + write_mdr(smc,MDR_REVERSE(a[0])) ; + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ + write_mdr(smc,MDR_REVERSE(a[1])) ; + + outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ; +} + +/* + setup claim & beacon pointer + NOTE : + special frame packets end with a pointer to their own + descriptor, and the MORE bit is set in the descriptor +*/ +static void build_claim_beacon(smc,t_request) +struct s_smc *smc ; +u_long t_request; +{ + u_int td ; + int len ; + struct fddi_mac_sf *mac ; + + /* + * build claim packet + */ + len = 17 ; + td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; + mac = &smc->hw.fp.mac_sfb ; + mac->mac_fc = FC_CLAIM ; + /* DA == SA in claim frame */ + mac->mac_source = mac->mac_dest = MA ; + /* 2's complement */ + set_int((char *)mac->mac_info,(int)t_request) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ; + /* set CLAIM start pointer */ + outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ; + + /* + * build beacon packet + */ + len = 17 ; + td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; + mac->mac_fc = FC_BEACON ; + mac->mac_source = MA ; + mac->mac_dest = null_addr ; /* DA == 0 in beacon frame */ + set_int((char *) mac->mac_info,((int)BEACON_INFO<<24) + 0 ) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ; + /* set beacon start pointer */ + outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ; + + /* + * build directed beacon packet + * contains optional UNA + */ + len = 23 ; + td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; + mac->mac_fc = FC_BEACON ; + mac->mac_source = MA ; + mac->mac_dest = dbeacon_multi ; /* multicast */ + set_int((char *) mac->mac_info,((int)DBEACON_INFO<<24) + 0 ) ; + set_int((char *) mac->mac_info+4,0) ; + set_int((char *) mac->mac_info+8,0) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF,len) ; + + /* end of claim/beacon queue */ + outpw(FM_A(FM_EACB),smc->hw.fp.fifo.rx1_fifo_start-1) ; + + outpw(FM_A(FM_WPXSF),0) ; + outpw(FM_A(FM_RPXSF),0) ; +} + +void formac_rcv_restart(smc) +struct s_smc *smc ; +{ + /* enable receive function */ + SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; + + outpw(FM_A(FM_CMDREG1),FM_ICLLR) ; /* clear receive lock */ +} + +void formac_tx_restart(smc) +struct s_smc *smc ; +{ + outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ +} + +static void enable_formac(smc) +struct s_smc *smc ; +{ + /* set formac IMSK : 0 enables irq */ + outpw(FM_A(FM_IMSK1U),~mac_imsk1u) ; + outpw(FM_A(FM_IMSK1L),~mac_imsk1l) ; + outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ; + outpw(FM_A(FM_IMSK2L),~mac_imsk2l) ; + outpw(FM_A(FM_IMSK3U),~mac_imsk3u) ; + outpw(FM_A(FM_IMSK3L),~mac_imsk3l) ; +} + +#if 0 /* Removed because the driver should use the ASICs TX complete IRQ. */ + /* The FORMACs tx complete IRQ should be used any longer */ + +/* + BEGIN_MANUAL_ENTRY(if,func;others;4) + + void enable_tx_irq(smc, queue) + struct s_smc *smc ; + u_short queue ; + +Function DOWNCALL (SMT, fplustm.c) + enable_tx_irq() enables the FORMACs transmit complete + interrupt of the queue. + +Para queue = QUEUE_S: synchronous queue + = QUEUE_A0: asynchronous queue + +Note After any ring operational change the transmit complete + interrupts are disabled. + The operating system dependent module must enable + the transmit complete interrupt of a queue, + - when it queues the first frame, + because of no transmit resources are beeing + available and + - when it escapes from the function llc_restart_tx + while some frames are still queued. + + END_MANUAL_ENTRY + */ +void enable_tx_irq(smc, queue) +struct s_smc *smc ; +u_short queue ; /* 0 = synchronous queue, 1 = asynchronous queue 0 */ +{ + u_short imask ; + + imask = ~(inpw(FM_A(FM_IMSK1U))) ; + + if (queue == 0) { + outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMS)) ; + } + if (queue == 1) { + outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMA0)) ; + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;4) + + void disable_tx_irq(smc, queue) + struct s_smc *smc ; + u_short queue ; + +Function DOWNCALL (SMT, fplustm.c) + disable_tx_irq disables the FORMACs transmit complete + interrupt of the queue + +Para queue = QUEUE_S: synchronous queue + = QUEUE_A0: asynchronous queue + +Note The operating system dependent module should disable + the transmit complete interrupts if it escapes from the + function llc_restart_tx and no frames are queued. + + END_MANUAL_ENTRY + */ +void disable_tx_irq(smc, queue) +struct s_smc *smc ; +u_short queue ; /* 0 = synchronous queue, 1 = asynchronous queue 0 */ +{ + u_short imask ; + + imask = ~(inpw(FM_A(FM_IMSK1U))) ; + + if (queue == 0) { + outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMS)) ; + } + if (queue == 1) { + outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMA0)) ; + } +} +#endif + +static void disable_formac(smc) +struct s_smc *smc ; +{ + /* clear formac IMSK : 1 disables irq */ + outpw(FM_A(FM_IMSK1U),MW) ; + outpw(FM_A(FM_IMSK1L),MW) ; + outpw(FM_A(FM_IMSK2U),MW) ; + outpw(FM_A(FM_IMSK2L),MW) ; + outpw(FM_A(FM_IMSK3U),MW) ; + outpw(FM_A(FM_IMSK3L),MW) ; +} + + +static void mac_ring_up(smc,up) +struct s_smc *smc ; +int up; +{ + if (up) { + formac_rcv_restart(smc) ; /* enable receive function */ + smc->hw.mac_ring_is_up = TRUE ; + llc_restart_tx(smc) ; /* TX queue */ + } + else { + /* disable receive function */ + SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; + + /* abort current transmit activity */ + outpw(FM_A(FM_CMDREG2),FM_IACTR) ; + + smc->hw.mac_ring_is_up = FALSE ; + } +} + +/*--------------------------- ISR handling ----------------------------------*/ +/* + * mac1_irq is in drvfbi.c + */ + +/* + * mac2_irq: status bits for the receive queue 1, and ring status + * ring status indication bits + */ +void mac2_irq(smc,code_s2u,code_s2l) +struct s_smc *smc ; +u_short code_s2u ; +u_short code_s2l ; +{ + u_short change_s2l ; + u_short change_s2u ; + + /* (jd) 22-Feb-1999 + * Restart 2_DMax Timer after end of claiming or beaconing + */ + if (code_s2u & (FM_SCLM|FM_SHICLM|FM_SBEC|FM_SOTRBEC)) { + queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; + } + else if (code_s2l & (FM_STKISS)) { + queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; + } + + /* + * XOR current st bits with the last to avoid useless RMT event queuing + */ + change_s2l = smc->hw.fp.s2l ^ code_s2l ; + change_s2u = smc->hw.fp.s2u ^ code_s2u ; + + if ((change_s2l & FM_SRNGOP) || + (!smc->hw.mac_ring_is_up && ((code_s2l & FM_SRNGOP)))) { + if (code_s2l & FM_SRNGOP) { + mac_ring_up(smc,1) ; + queue_event(smc,EVENT_RMT,RM_RING_OP) ; + smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; + } + else { + mac_ring_up(smc,0) ; + queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; + } + goto mac2_end ; + } + if (code_s2l & FM_SMISFRM) { /* missed frame */ + smc->mib.m[MAC0].fddiMACNotCopied_Ct++ ; + } + if (code_s2u & (FM_SRCVOVR | /* recv. FIFO overflow */ + FM_SRBFL)) { /* recv. buffer full */ + smc->hw.mac_ct.mac_r_restart_counter++ ; +/* formac_rcv_restart(smc) ; */ + smt_stat_counter(smc,1) ; +/* goto mac2_end ; */ + } + if (code_s2u & FM_SOTRBEC) + queue_event(smc,EVENT_RMT,RM_OTHER_BEACON) ; + if (code_s2u & FM_SMYBEC) + queue_event(smc,EVENT_RMT,RM_MY_BEACON) ; + if (change_s2u & code_s2u & FM_SLOCLM) { + DB_RMTN(2,"RMT : lower claim received\n",0,0) ; + } + if ((code_s2u & FM_SMYCLM) && !(code_s2l & FM_SDUPCLM)) { + /* + * This is my claim and that claim is not detected as a + * duplicate one. + */ + queue_event(smc,EVENT_RMT,RM_MY_CLAIM) ; + } + if (code_s2l & FM_SDUPCLM) { + /* + * If a duplicate claim frame (same SA but T_Bid != T_Req) + * this flag will be set. + * In the RMT state machine we need a RM_VALID_CLAIM event + * to do the appropriate state change. + * RM(34c) + */ + queue_event(smc,EVENT_RMT,RM_VALID_CLAIM) ; + } + if (change_s2u & code_s2u & FM_SHICLM) { + DB_RMTN(2,"RMT : higher claim received\n",0,0) ; + } + if ( (code_s2l & FM_STRTEXP) || + (code_s2l & FM_STRTEXR) ) + queue_event(smc,EVENT_RMT,RM_TRT_EXP) ; + if (code_s2l & FM_SMULTDA) { + /* + * The MAC has found a 2. MAC with the same address. + * Signal dup_addr_test = failed to RMT state machine. + * RM(25) + */ + smc->r.dup_addr_test = DA_FAILED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + } + if (code_s2u & FM_SBEC) + smc->hw.fp.err_stats.err_bec_stat++ ; + if (code_s2u & FM_SCLM) + smc->hw.fp.err_stats.err_clm_stat++ ; + if (code_s2l & FM_STVXEXP) + smc->mib.m[MAC0].fddiMACTvxExpired_Ct++ ; + if ((code_s2u & (FM_SBEC|FM_SCLM))) { + if (!(change_s2l & FM_SRNGOP) && (smc->hw.fp.s2l & FM_SRNGOP)) { + mac_ring_up(smc,0) ; + queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; + + mac_ring_up(smc,1) ; + queue_event(smc,EVENT_RMT,RM_RING_OP) ; + smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; + } + } + if (code_s2l & FM_SPHINV) + smc->hw.fp.err_stats.err_phinv++ ; + if (code_s2l & FM_SSIFG) + smc->hw.fp.err_stats.err_sifg_det++ ; + if (code_s2l & FM_STKISS) + smc->hw.fp.err_stats.err_tkiss++ ; + if (code_s2l & FM_STKERR) + smc->hw.fp.err_stats.err_tkerr++ ; + if (code_s2l & FM_SFRMCTR) + smc->mib.m[MAC0].fddiMACFrame_Ct += 0x10000L ; + if (code_s2l & FM_SERRCTR) + smc->mib.m[MAC0].fddiMACError_Ct += 0x10000L ; + if (code_s2l & FM_SLSTCTR) + smc->mib.m[MAC0].fddiMACLost_Ct += 0x10000L ; + if (code_s2u & FM_SERRSF) { + SMT_PANIC(smc,SMT_E0114, SMT_E0114_MSG) ; + } +mac2_end: + /* notice old status */ + smc->hw.fp.s2l = code_s2l ; + smc->hw.fp.s2u = code_s2u ; + outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ; +} + +/* + * mac3_irq: receive queue 2 bits and address detection bits + */ +void mac3_irq(smc,code_s3u,code_s3l) +struct s_smc *smc ; +u_short code_s3u ; +u_short code_s3l ; +{ + UNUSED(code_s3l) ; + + if (code_s3u & (FM_SRCVOVR2 | /* recv. FIFO overflow */ + FM_SRBFL2)) { /* recv. buffer full */ + smc->hw.mac_ct.mac_r_restart_counter++ ; + smt_stat_counter(smc,1); + } + + + if (code_s3u & FM_SRPERRQ2) { /* parity error receive queue 2 */ + SMT_PANIC(smc,SMT_E0115, SMT_E0115_MSG) ; + } + if (code_s3u & FM_SRPERRQ1) { /* parity error receive queue 2 */ + SMT_PANIC(smc,SMT_E0116, SMT_E0116_MSG) ; + } +} + + +/* + * take formac offline + */ +static void formac_offline(smc) +struct s_smc *smc ; +{ + outpw(FM_A(FM_CMDREG2),FM_IACTR) ;/* abort current transmit activity */ + + /* disable receive function */ + SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; + + /* FORMAC+ 'Initialize Mode' */ + SETMASK(FM_A(FM_MDREG1),FM_MINIT,FM_MMODE) ; + + disable_formac(smc) ; + smc->hw.mac_ring_is_up = FALSE ; + smc->hw.hw_state = STOPPED ; +} + +/* + * bring formac online + */ +static void formac_online(smc) +struct s_smc *smc ; +{ + enable_formac(smc) ; + SETMASK(FM_A(FM_MDREG1),FM_MONLINE | FM_SELRA | MDR1INIT | + smc->hw.fp.rx_mode, FM_MMODE | FM_SELRA | FM_ADDRX) ; +} + +/* + * FORMAC+ full init. (tx, rx, timer, counter, claim & beacon) + */ +int init_fplus(smc) +struct s_smc *smc ; +{ + smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; + smc->hw.fp.rx_mode = FM_MDAMA ; + smc->hw.fp.group_addr = fddi_broadcast ; + smc->hw.fp.func_addr = 0 ; + smc->hw.fp.frselreg_init = 0 ; + + init_driver_fplus(smc) ; + if (smc->s.sas == SMT_DAS) + smc->hw.fp.mdr3init |= FM_MENDAS ; + + smc->hw.mac_ct.mac_nobuf_counter = 0 ; + smc->hw.mac_ct.mac_r_restart_counter = 0 ; + + smc->hw.fp.fm_st1u = (HW_PTR) ADDR(B0_ST1U) ; + smc->hw.fp.fm_st1l = (HW_PTR) ADDR(B0_ST1L) ; + smc->hw.fp.fm_st2u = (HW_PTR) ADDR(B0_ST2U) ; + smc->hw.fp.fm_st2l = (HW_PTR) ADDR(B0_ST2L) ; + smc->hw.fp.fm_st3u = (HW_PTR) ADDR(B0_ST3U) ; + smc->hw.fp.fm_st3l = (HW_PTR) ADDR(B0_ST3L) ; + + smc->hw.fp.s2l = smc->hw.fp.s2u = 0 ; + smc->hw.mac_ring_is_up = 0 ; + + mac_counter_init(smc) ; + + /* convert BCKL units to symbol time */ + smc->hw.mac_pa.t_neg = (u_long)0 ; + smc->hw.mac_pa.t_pri = (u_long)0 ; + + /* make sure all PCI settings are correct */ + mac_do_pci_fix(smc) ; + + return(init_mac(smc,1)) ; + /* enable_formac(smc) ; */ +} + +static int init_mac(smc,all) +struct s_smc *smc ; +int all ; +{ + u_short t_max,x ; + u_long time=0 ; + + /* + * clear memory + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; /* FORMAC+ init mode */ + set_formac_addr(smc) ; + outpw(FM_A(FM_MDREG1),FM_MMEMACT) ; /* FORMAC+ memory activ mode */ + /* Note: Mode register 2 is set here, incase parity is enabled. */ + outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; + + if (all) { + init_ram(smc) ; + } + else { + /* + * reset the HPI, the Master and the BMUs + */ + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + time = hwt_quick_read(smc) ; + } + + /* + * set all pointers, frames etc + */ + smt_split_up_fifo(smc) ; + + init_tx(smc) ; + init_rx(smc) ; + init_rbc(smc) ; + + build_claim_beacon(smc,smc->mib.m[MAC0].fddiMACT_Req) ; + + /* set RX threshold */ + /* see Errata #SN2 Phantom receive overflow */ + outpw(FM_A(FM_FRMTHR),14<<12) ; /* switch on */ + + /* set formac work mode */ + outpw(FM_A(FM_MDREG1),MDR1INIT | FM_SELRA | smc->hw.fp.rx_mode) ; + outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; + outpw(FM_A(FM_MDREG3),smc->hw.fp.mdr3init) ; + outpw(FM_A(FM_FRSELREG),smc->hw.fp.frselreg_init) ; + + /* set timer */ + /* + * errata #22 fplus: + * T_MAX must not be FFFE + * or one of FFDF, FFB8, FF91 (-0x27 etc..) + */ + t_max = (u_short)(smc->mib.m[MAC0].fddiMACT_Max/32) ; + x = t_max/0x27 ; + x *= 0x27 ; + if ((t_max == 0xfffe) || (t_max - x == 0x16)) + t_max-- ; + outpw(FM_A(FM_TMAX),(u_short)t_max) ; + + /* BugFix for report #10204 */ + if (smc->mib.m[MAC0].fddiMACTvxValue < (u_long) (- US2BCLK(52))) { + outpw(FM_A(FM_TVX), (u_short) (- US2BCLK(52))/255 & MB) ; + } else { + outpw(FM_A(FM_TVX), + (u_short)((smc->mib.m[MAC0].fddiMACTvxValue/255) & MB)) ; + } + + outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLR); /* clear receive lock */ + + /* Auto unlock receice threshold for receive queue 1 and 2 */ + outpw(FM_A(FM_UNLCKDLY),(0xff|(0xff<<8))) ; + + rtm_init(smc) ; /* RT-Monitor */ + + if (!all) { + /* + * after 10ms, reset the BMUs and repair the rings + */ + hwt_wait_time(smc,time,MS2BCLK(10)) ; + outpd(ADDR(B0_R1_CSR),CSR_SET_RESET) ; + outpd(ADDR(B0_XA_CSR),CSR_SET_RESET) ; + outpd(ADDR(B0_XS_CSR),CSR_SET_RESET) ; + outp(ADDR(B0_CTRL), CTRL_HPI_CLR) ; + outpd(ADDR(B0_R1_CSR),CSR_CLR_RESET) ; + outpd(ADDR(B0_XA_CSR),CSR_CLR_RESET) ; + outpd(ADDR(B0_XS_CSR),CSR_CLR_RESET) ; + if (!smc->hw.hw_is_64bit) { + outpd(ADDR(B4_R1_F), RX_WATERMARK) ; + outpd(ADDR(B5_XA_F), TX_WATERMARK) ; + outpd(ADDR(B5_XS_F), TX_WATERMARK) ; + } + smc->hw.hw_state = STOPPED ; + mac_drv_repair_descr(smc) ; + } + smc->hw.hw_state = STARTED ; + + return(0) ; +} + + +/* + * called by CFM + */ +void config_mux(smc,mux) +struct s_smc *smc ; +int mux; +{ + plc_config_mux(smc,mux) ; + + SETMASK(FM_A(FM_MDREG1),FM_SELRA,FM_SELRA) ; +} + +/* + * called by RMT + * enable CLAIM/BEACON interrupts + * (only called if these events are of interest, e.g. in DETECT state + * the interrupt must not be permanently enabled + * RMT calls this function periodically (timer driven polling) + */ +void sm_mac_check_beacon_claim(smc) +struct s_smc *smc ; +{ + /* set formac IMSK : 0 enables irq */ + outpw(FM_A(FM_IMSK2U),~(mac_imsk2u | mac_beacon_imsk2u)) ; + /* the driver must receive the directed beacons */ + formac_rcv_restart(smc) ; + process_receive(smc) ; +} + +/*-------------------------- interface functions ----------------------------*/ +/* + * control ODL output + */ +void sm_pm_control(smc,mode) +struct s_smc *smc ; +int mode; +{ + SK_UNUSED(smc) ; + + /* + * if PCM logic has set LS_REQUEST = Transmit QUIET Line State + * /FOTOFF signal turn activ -> ODL disable + */ + switch(mode) { + case PM_TRANSMIT_DISABLE : + break ; + case PM_TRANSMIT_ENABLE : + break ; + } +} + +/* + * control MAC layer (called by RMT) + */ +void sm_ma_control(smc,mode) +struct s_smc *smc ; +int mode; +{ + switch(mode) { + case MA_OFFLINE : + /* Add to make the MAC offline in RM0_ISOLATED state */ + formac_offline(smc) ; + break ; + case MA_RESET : + (void)init_mac(smc,0) ; + break ; + case MA_BEACON : + formac_online(smc) ; + break ; + case MA_DIRECTED : + directed_beacon(smc) ; + break ; + case MA_TREQ : + /* + * no actions necessary, TREQ is already set + */ + break ; + } +} + +int sm_mac_get_tx_state(smc) +struct s_smc *smc ; +{ + return((inpw(FM_A(FM_STMCHN))>>4)&7) ; +} + +/* + * multicast functions + */ + +static struct s_fpmc *mac_get_mc_table(smc,user,own,del,can) +struct s_smc *smc ; +struct fddi_addr *user ; +struct fddi_addr *own ; +int del ; +int can ; +{ + struct s_fpmc *tb ; + struct s_fpmc *slot ; + u_char *p ; + int i ; + + /* + * set own = can(user) + */ + *own = *user ; + if (can) { + p = own->a ; + for (i = 0 ; i < 6 ; i++, p++) + *p = canonical[*p] ; + } + slot = 0 ; + for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ + if (!tb->n) { /* not used */ + if (!del && !slot) /* if !del save first free */ + slot = tb ; + continue ; + } + if (memcmp((char *)&tb->a,(char *)own,6)) + continue ; + return(tb) ; + } + return(slot) ; /* return first free or NULL */ +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_clear_multicast(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, fplustm.c) + Clear all multicast entries + + END_MANUAL_ENTRY() + */ +void mac_clear_multicast(smc) +struct s_smc *smc ; +{ + struct s_fpmc *tb ; + int i ; + + smc->hw.fp.os_slots_used = 0 ; /* note the SMT addresses */ + /* will not be deleted */ + for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ + if (!tb->perm) { + tb->n = 0 ; + } + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + int mac_set_func_addr(smc,f_addr) + struct s_smc *smc ; + u_long f_addr ; + +Function DOWNCALL (SMT, fplustm.c) + Set a Token-Ring functional address, the address will + be activated after calling mac_update_multicast() + +Para f_addr functional bits in non-canonical format + +Returns 0: always success + + END_MANUAL_ENTRY() + */ +int mac_set_func_addr(smc,f_addr) +struct s_smc *smc ; +u_long f_addr ; +{ + smc->hw.fp.func_addr = f_addr ; + return(0) ; +} + + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + int mac_add_multicast(smc,addr,can) + struct s_smc *smc ; + struct fddi_addr *addr ; + int can ; + +Function DOWNCALL (SMC, fplustm.c) + Add an entry to the multicast table + +Para addr pointer to a multicast address + can = 0: the multicast address has the physical format + = 1: the multicast address has the canonical format + | 0x80 permanent + +Returns 0: success + 1: address table full + +Note After a 'driver reset' or a 'station set address' all + entries of the multicast table are cleared. + In this case the driver has to fill the multicast table again. + After the operating system dependent module filled + the multicast table it must call mac_update_multicast + to activate the new multicast addresses! + + END_MANUAL_ENTRY() + */ +int mac_add_multicast(smc,addr,can) +struct s_smc *smc ; +struct fddi_addr *addr ; +int can ; +{ + SK_LOC_DECL(struct fddi_addr,own) ; + struct s_fpmc *tb ; + + /* + * check if there are free table entries + */ + if (can & 0x80) { + if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) { + return(1) ; + } + } + else { + if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) { + return(1) ; + } + } + + /* + * find empty slot + */ + if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80))) + return(1) ; + tb->n++ ; + tb->a = own ; + tb->perm = (can & 0x80) ? 1 : 0 ; + + if (can & 0x80) + smc->hw.fp.smt_slots_used++ ; + else + smc->hw.fp.os_slots_used++ ; + + return(0) ; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_del_multicast(smc,addr,can) + struct s_smc *smc ; + struct fddi_addr *addr ; + int can ; + +Function DOWNCALL (SMT, fplustm.c) + Delete an entry from the multicast table + +Para addr pointer to a multicast address + can = 0: the multicast address has the physical format + = 1: the multicast address has the canonical format + | 0x80 permanent + + END_MANUAL_ENTRY() + */ +void mac_del_multicast(smc,addr,can) +struct s_smc *smc ; +struct fddi_addr *addr ; +int can ; +{ + SK_LOC_DECL(struct fddi_addr,own) ; + struct s_fpmc *tb ; + + if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80))) + return ; + /* + * permanent addresses must be deleted with perm bit + * and vice versa + */ + if (( tb->perm && (can & 0x80)) || + (!tb->perm && !(can & 0x80))) { + /* + * delete it + */ + if (tb->n) { + tb->n-- ; + if (tb->perm) { + smc->hw.fp.smt_slots_used-- ; + } + else { + smc->hw.fp.os_slots_used-- ; + } + } + } +} + +/* + * mode + */ + +#define RX_MODE_PROM 0x1 +#define RX_MODE_ALL_MULTI 0x2 + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_update_multicast(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, fplustm.c) + Update FORMAC multicast registers + + END_MANUAL_ENTRY() + */ +void mac_update_multicast(smc) +struct s_smc *smc ; +{ + struct s_fpmc *tb ; + u_char *fu ; + int i ; + + /* + * invalidate the CAM + */ + outpw(FM_A(FM_AFCMD),FM_IINV_CAM) ; + + /* + * set the functional address + */ + if (smc->hw.fp.func_addr) { + fu = (u_char *) &smc->hw.fp.func_addr ; + outpw(FM_A(FM_AFMASK2),0xffff) ; + outpw(FM_A(FM_AFMASK1),(u_short) ~((fu[0] << 8) + fu[1])) ; + outpw(FM_A(FM_AFMASK0),(u_short) ~((fu[2] << 8) + fu[3])) ; + outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; + outpw(FM_A(FM_AFCOMP2), 0xc000) ; + outpw(FM_A(FM_AFCOMP1), 0x0000) ; + outpw(FM_A(FM_AFCOMP0), 0x0000) ; + outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; + } + + /* + * set the mask and the personality register(s) + */ + outpw(FM_A(FM_AFMASK0),0xffff) ; + outpw(FM_A(FM_AFMASK1),0xffff) ; + outpw(FM_A(FM_AFMASK2),0xffff) ; + outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; + + for (i = 0, tb = smc->hw.fp.mc.table; i < FPMAX_MULTICAST; i++, tb++) { + if (tb->n) { + CHECK_CAM() ; + + /* + * wirte the multicast addres into the CAM + */ + outpw(FM_A(FM_AFCOMP2), + (u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ; + outpw(FM_A(FM_AFCOMP1), + (u_short)((tb->a.a[2]<<8)+tb->a.a[3])) ; + outpw(FM_A(FM_AFCOMP0), + (u_short)((tb->a.a[4]<<8)+tb->a.a[5])) ; + outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; + } + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;3) + + void mac_set_rx_mode(smc,mode) + struct s_smc *smc ; + int mode ; + +Function DOWNCALL/INTERN (SMT, fplustm.c) + This function enables / disables the selected receive. + Don't call this function if the hardware module is + used -- use mac_drv_rx_mode() instead of. + +Para mode = 1 RX_ENABLE_ALLMULTI enable all multicasts + 2 RX_DISABLE_ALLMULTI disable "enable all multicasts" + 3 RX_ENABLE_PROMISC enable promiscous + 4 RX_DISABLE_PROMISC disable promiscous + 5 RX_ENABLE_NSA enable reception of NSA frames + 6 RX_DISABLE_NSA disable reception of NSA frames + +Note The selected receive modes will be lost after 'driver reset' + or 'set station address' + + END_MANUAL_ENTRY + */ +void mac_set_rx_mode(smc,mode) +struct s_smc *smc ; +int mode ; +{ + switch (mode) { + case RX_ENABLE_ALLMULTI : + smc->hw.fp.rx_prom |= RX_MODE_ALL_MULTI ; + break ; + case RX_DISABLE_ALLMULTI : + smc->hw.fp.rx_prom &= ~RX_MODE_ALL_MULTI ; + break ; + case RX_ENABLE_PROMISC : + smc->hw.fp.rx_prom |= RX_MODE_PROM ; + break ; + case RX_DISABLE_PROMISC : + smc->hw.fp.rx_prom &= ~RX_MODE_PROM ; + break ; + case RX_ENABLE_NSA : + smc->hw.fp.nsa_mode = FM_MDAMA ; + smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | + smc->hw.fp.nsa_mode ; + break ; + case RX_DISABLE_NSA : + smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; + smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | + smc->hw.fp.nsa_mode ; + break ; + } + if (smc->hw.fp.rx_prom & RX_MODE_PROM) { + smc->hw.fp.rx_mode = FM_MLIMPROM ; + } + else if (smc->hw.fp.rx_prom & RX_MODE_ALL_MULTI) { + smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode | FM_EXGPA0 ; + } + else + smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode ; + SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; + mac_update_multicast(smc) ; +} + +/* + BEGIN_MANUAL_ENTRY(module;tests;3) + How to test the Restricted Token Monitor + ---------------------------------------------------------------- + + o Insert a break point in the function rtm_irq() + o Remove all stations with a restricted token monitor from the + network. + o Connect a UPPS ISA or EISA station to the network. + o Give the FORMAC of UPPS station the command to send + restricted tokens until the ring becomes instable. + o Now connect your test test client. + o The restricted token monitor should detect the restricted token, + and your break point will be reached. + o You can ovserve how the station will clean the ring. + + END_MANUAL_ENTRY + */ +void rtm_irq(smc) +struct s_smc *smc ; +{ + outpw(ADDR(B2_RTM_CRTL),TIM_CL_IRQ) ; /* clear IRQ */ + if (inpw(ADDR(B2_RTM_CRTL)) & TIM_RES_TOK) { + outpw(FM_A(FM_CMDREG1),FM_ICL) ; /* force claim */ + DB_RMT("RMT: fddiPATHT_Rmode expired\n",0,0) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, + (u_long) FDDI_SMT_EVENT, + (u_long) FDDI_RTT, smt_get_event_word(smc)); + } + outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable RTM monitoring */ +} + +static void rtm_init(smc) +struct s_smc *smc ; +{ + outpd(ADDR(B2_RTM_INI),0) ; /* timer = 0 */ + outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable IRQ */ +} + +void rtm_set_timer(smc) +struct s_smc *smc ; +{ + /* + * MIB timer and hardware timer have the same resolution of 80nS + */ + DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns \n", + (int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ; + outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ; +} + +static void smt_split_up_fifo(smc) +struct s_smc *smc ; +{ + +/* + BEGIN_MANUAL_ENTRY(module;mem;1) + ------------------------------------------------------------- + RECEIVE BUFFER MEMORY DIVERSION + ------------------------------------------------------------- + + R1_RxD == SMT_R1_RXD_COUNT + R2_RxD == SMT_R2_RXD_COUNT + + SMT_R1_RXD_COUNT must be unequal zero + + | R1_RxD R2_RxD |R1_RxD R2_RxD | R1_RxD R2_RxD + | x 0 | x 1-3 | x < 3 + ---------------------------------------------------------------------- + | 63,75 kB | 54,75 | R1_RxD + rx queue 1 | RX_FIFO_SPACE | RX_LARGE_FIFO| ------------- * 63,75 kB + | | | R1_RxD+R2_RxD + ---------------------------------------------------------------------- + | | 9 kB | R2_RxD + rx queue 2 | 0 kB | RX_SMALL_FIFO| ------------- * 63,75 kB + | (not used) | | R1_RxD+R2_RxD + + END_MANUAL_ENTRY +*/ + + if (SMT_R1_RXD_COUNT == 0) { + SMT_PANIC(smc,SMT_E0117, SMT_E0117_MSG) ; + } + + switch(SMT_R2_RXD_COUNT) { + case 0: + smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE ; + smc->hw.fp.fifo.rx2_fifo_size = 0 ; + break ; + case 1: + case 2: + case 3: + smc->hw.fp.fifo.rx1_fifo_size = RX_LARGE_FIFO ; + smc->hw.fp.fifo.rx2_fifo_size = RX_SMALL_FIFO ; + break ; + default: /* this is not the real defaule */ + smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE * + SMT_R1_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; + smc->hw.fp.fifo.rx2_fifo_size = RX_FIFO_SPACE * + SMT_R2_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; + break ; + } + +/* + BEGIN_MANUAL_ENTRY(module;mem;1) + ------------------------------------------------------------- + TRANSMIT BUFFER MEMORY DIVERSION + ------------------------------------------------------------- + + + | no sync bw | sync bw available and | sync bw available and + | available | SynchTxMode = SPLIT | SynchTxMode = ALL + ----------------------------------------------------------------------- + sync tx | 0 kB | 32 kB | 55 kB + queue | | TX_MEDIUM_FIFO | TX_LARGE_FIFO + ----------------------------------------------------------------------- + async tx | 64 kB | 32 kB | 9 k + queue | TX_FIFO_SPACE| TX_MEDIUM_FIFO | TX_SMALL_FIFO + + END_MANUAL_ENTRY +*/ + + /* + * set the tx mode bits + */ + if (smc->mib.a[PATH0].fddiPATHSbaPayload) { +#ifdef ESS + smc->hw.fp.fifo.fifo_config_mode |= + smc->mib.fddiESSSynchTxMode | SYNC_TRAFFIC_ON ; +#endif + } + else { + smc->hw.fp.fifo.fifo_config_mode &= + ~(SEND_ASYNC_AS_SYNC|SYNC_TRAFFIC_ON) ; + } + + /* + * split up the FIFO + */ + if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON) { + if (smc->hw.fp.fifo.fifo_config_mode & SEND_ASYNC_AS_SYNC) { + smc->hw.fp.fifo.tx_s_size = TX_LARGE_FIFO ; + smc->hw.fp.fifo.tx_a0_size = TX_SMALL_FIFO ; + } + else { + smc->hw.fp.fifo.tx_s_size = TX_MEDIUM_FIFO ; + smc->hw.fp.fifo.tx_a0_size = TX_MEDIUM_FIFO ; + } + } + else { + smc->hw.fp.fifo.tx_s_size = 0 ; + smc->hw.fp.fifo.tx_a0_size = TX_FIFO_SPACE ; + } + + smc->hw.fp.fifo.rx1_fifo_start = smc->hw.fp.fifo.rbc_ram_start + + RX_FIFO_OFF ; + smc->hw.fp.fifo.tx_s_start = smc->hw.fp.fifo.rx1_fifo_start + + smc->hw.fp.fifo.rx1_fifo_size ; + smc->hw.fp.fifo.tx_a0_start = smc->hw.fp.fifo.tx_s_start + + smc->hw.fp.fifo.tx_s_size ; + smc->hw.fp.fifo.rx2_fifo_start = smc->hw.fp.fifo.tx_a0_start + + smc->hw.fp.fifo.tx_a0_size ; + + DB_SMT("FIFO split: mode = %x\n",smc->hw.fp.fifo.fifo_config_mode,0) ; + DB_SMT("rbc_ram_start = %x rbc_ram_end = %x\n", + smc->hw.fp.fifo.rbc_ram_start, smc->hw.fp.fifo.rbc_ram_end) ; + DB_SMT("rx1_fifo_start = %x tx_s_start = %x\n", + smc->hw.fp.fifo.rx1_fifo_start, smc->hw.fp.fifo.tx_s_start) ; + DB_SMT("tx_a0_start = %x rx2_fifo_start = %x\n", + smc->hw.fp.fifo.tx_a0_start, smc->hw.fp.fifo.rx2_fifo_start) ; +} + +void formac_reinit_tx(smc) +struct s_smc *smc ; +{ + /* + * Split up the FIFO and reinitialize the MAC if synchronous + * bandwidth becomes available but no synchronous queue is + * configured. + */ + if (!smc->hw.fp.fifo.tx_s_size && smc->mib.a[PATH0].fddiPATHSbaPayload){ + (void)init_mac(smc,0) ; + } +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/cmtdef.h linux/drivers/net/skfp/h/cmtdef.h --- v2.2.17/drivers/net/skfp/h/cmtdef.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/cmtdef.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,801 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _CMTDEF_ +#define _CMTDEF_ + +/* **************************************************************** */ + +/* + * implementation specific constants + * MODIIFY THE FOLLWOING THREE DEFINES + */ +#define AMDPLC /* if Amd PLC chip used */ +#ifdef CONC +#define NUMPHYS 12 /* 2 for SAS or DAS, more for Concentrator */ +#else +#ifdef CONC_II +#define NUMPHYS 24 /* 2 for SAS or DAS, more for Concentrator */ +#else +#define NUMPHYS 2 /* 2 for SAS or DAS, more for Concentrator */ +#endif +#endif +#define NUMMACS 1 /* only 1 supported at the moment */ +#define NUMPATHS 2 /* primary and secondary path supported */ + +/* + * DO NOT MODIFY BEYOND THIS POINT + */ + +/* **************************************************************** */ + +#if NUMPHYS > 2 +#define CONCENTRATOR +#endif + +/* + * Definitions for comfortable LINT usage + */ +#ifdef lint +#define LINT_USE(x) (x)=(x) +#else +#define LINT_USE(x) +#endif + +#ifdef DEBUG +#define DB_PR(flag,a,b,c) { if (flag) printf(a,b,c) ; } +#else +#define DB_PR(flag,a,b,c) +#endif + +#ifdef DEBUG_BRD +#define DB_ECM(a,b,c) DB_PR((smc->debug.d_smt&1),a,b,c) +#define DB_ECMN(n,a,b,c) DB_PR((smc->debug.d_ecm >=(n)),a,b,c) +#define DB_RMT(a,b,c) DB_PR((smc->debug.d_smt&2),a,b,c) +#define DB_RMTN(n,a,b,c) DB_PR((smc->debug.d_rmt >=(n)),a,b,c) +#define DB_CFM(a,b,c) DB_PR((smc->debug.d_smt&4),a,b,c) +#define DB_CFMN(n,a,b,c) DB_PR((smc->debug.d_cfm >=(n)),a,b,c) +#define DB_PCM(a,b,c) DB_PR((smc->debug.d_smt&8),a,b,c) +#define DB_PCMN(n,a,b,c) DB_PR((smc->debug.d_pcm >=(n)),a,b,c) +#define DB_SMT(a,b,c) DB_PR((smc->debug.d_smtf),a,b,c) +#define DB_SMTN(n,a,b,c) DB_PR((smc->debug.d_smtf >=(n)),a,b,c) +#define DB_SBA(a,b,c) DB_PR((smc->debug.d_sba),a,b,c) +#define DB_SBAN(n,a,b,c) DB_PR((smc->debug.d_sba >=(n)),a,b,c) +#define DB_ESS(a,b,c) DB_PR((smc->debug.d_ess),a,b,c) +#define DB_ESSN(n,a,b,c) DB_PR((smc->debug.d_ess >=(n)),a,b,c) +#else +#define DB_ECM(a,b,c) DB_PR((debug.d_smt&1),a,b,c) +#define DB_ECMN(n,a,b,c) DB_PR((debug.d_ecm >=(n)),a,b,c) +#define DB_RMT(a,b,c) DB_PR((debug.d_smt&2),a,b,c) +#define DB_RMTN(n,a,b,c) DB_PR((debug.d_rmt >=(n)),a,b,c) +#define DB_CFM(a,b,c) DB_PR((debug.d_smt&4),a,b,c) +#define DB_CFMN(n,a,b,c) DB_PR((debug.d_cfm >=(n)),a,b,c) +#define DB_PCM(a,b,c) DB_PR((debug.d_smt&8),a,b,c) +#define DB_PCMN(n,a,b,c) DB_PR((debug.d_pcm >=(n)),a,b,c) +#define DB_SMT(a,b,c) DB_PR((debug.d_smtf),a,b,c) +#define DB_SMTN(n,a,b,c) DB_PR((debug.d_smtf >=(n)),a,b,c) +#define DB_SBA(a,b,c) DB_PR((debug.d_sba),a,b,c) +#define DB_SBAN(n,a,b,c) DB_PR((debug.d_sba >=(n)),a,b,c) +#define DB_ESS(a,b,c) DB_PR((debug.d_ess),a,b,c) +#define DB_ESSN(n,a,b,c) DB_PR((debug.d_ess >=(n)),a,b,c) +#endif + +#ifndef SS_NOT_DS +#define SK_LOC_DECL(type,var) type var +#else +#define SK_LOC_DECL(type,var) static type var +#endif +/* + * PHYs and PORTS + * Note: Don't touch the definition of PA and PB. Those might be used + * by some "for" loops. + */ +#define PA 0 +#define PB 1 +#if defined(SUPERNET_3) || defined(CONC_II) +/* + * The port indices have to be different, + * because the MAC output goes through the 2. PLC + * Conc II: It has to be the first port in the row. + */ +#define PS 0 /* Internal PLC which is the same as PA */ +#else +#define PS 1 +#endif +#define PM 2 /* PM .. PA+NUM_PHYS-1 */ + +/* + * PHY types - as in path descriptor 'fddiPHYType' + */ +#define TA 0 /* A port */ +#define TB 1 /* B port */ +#define TS 2 /* S port */ +#define TM 3 /* M port */ +#define TNONE 4 + + +/* + * indexes in MIB + */ +#define INDEX_MAC 1 +#define INDEX_PATH 1 +#define INDEX_PORT 1 + + +/* + * policies + */ +#define POLICY_AA (1<<0) /* reject AA */ +#define POLICY_AB (1<<1) /* reject AB */ +#define POLICY_AS (1<<2) /* reject AS */ +#define POLICY_AM (1<<3) /* reject AM */ +#define POLICY_BA (1<<4) /* reject BA */ +#define POLICY_BB (1<<5) /* reject BB */ +#define POLICY_BS (1<<6) /* reject BS */ +#define POLICY_BM (1<<7) /* reject BM */ +#define POLICY_SA (1<<8) /* reject SA */ +#define POLICY_SB (1<<9) /* reject SB */ +#define POLICY_SS (1<<10) /* reject SS */ +#define POLICY_SM (1<<11) /* reject SM */ +#define POLICY_MA (1<<12) /* reject MA */ +#define POLICY_MB (1<<13) /* reject MB */ +#define POLICY_MS (1<<14) /* reject MS */ +#define POLICY_MM (1<<15) /* reject MM */ + +/* + * commands + */ + +/* + * EVENTS + * event classes + */ +#define EVENT_ECM 1 /* event class ECM */ +#define EVENT_CFM 2 /* event class CFM */ +#define EVENT_RMT 3 /* event class RMT */ +#define EVENT_SMT 4 /* event class SMT */ +#define EVENT_PCM 5 /* event class PCM */ +#define EVENT_PCMA 5 /* event class PCMA */ +#define EVENT_PCMB 6 /* event class PCMB */ + +/* WARNING : + * EVENT_PCM* must be last in the above list + * if more then two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1 + * are used ! + */ + +#define EV_TOKEN(class,event) (((u_long)(class)<<16L)|((u_long)(event))) +#define EV_T_CLASS(token) ((int)((token)>>16)&0xffff) +#define EV_T_EVENT(token) ((int)(token)&0xffff) + +/* + * ECM events + */ +#define EC_CONNECT 1 /* connect request */ +#define EC_DISCONNECT 2 /* disconnect request */ +#define EC_TRACE_PROP 3 /* trace propagation */ +#define EC_PATH_TEST 4 /* path test */ +#define EC_TIMEOUT_TD 5 /* timer TD_min */ +#define EC_TIMEOUT_TMAX 6 /* timer trace_max */ +#define EC_TIMEOUT_IMAX 7 /* timer I_max */ +#define EC_TIMEOUT_INMAX 8 /* timer IN_max */ +#define EC_TEST_DONE 9 /* path test done */ + +/* + * CFM events + */ +#define CF_LOOP 1 /* cf_loop flag from PCM */ +#define CF_LOOP_A 1 /* cf_loop flag from PCM */ +#define CF_LOOP_B 2 /* cf_loop flag from PCM */ +#define CF_JOIN 3 /* cf_join flag from PCM */ +#define CF_JOIN_A 3 /* cf_join flag from PCM */ +#define CF_JOIN_B 4 /* cf_join flag from PCM */ + +/* + * PCM events + */ +#define PC_START 1 +#define PC_STOP 2 +#define PC_LOOP 3 +#define PC_JOIN 4 +#define PC_SIGNAL 5 +#define PC_REJECT 6 +#define PC_MAINT 7 +#define PC_TRACE 8 +#define PC_PDR 9 +#define PC_ENABLE 10 +#define PC_DISABLE 11 + +/* + * must be ordered as in LineStateType + */ +#define PC_QLS 12 +#define PC_ILS 13 +#define PC_MLS 14 +#define PC_HLS 15 +#define PC_LS_PDR 16 +#define PC_LS_NONE 17 +#define LS2MIB(x) ((x)-PC_QLS) +#define MIB2LS(x) ((x)+PC_QLS) + +#define PC_TIMEOUT_TB_MAX 18 /* timer TB_max */ +#define PC_TIMEOUT_TB_MIN 19 /* timer TB_min */ +#define PC_TIMEOUT_C_MIN 20 /* timer C_Min */ +#define PC_TIMEOUT_T_OUT 21 /* timer T_Out */ +#define PC_TIMEOUT_TL_MIN 22 /* timer TL_Min */ +#define PC_TIMEOUT_T_NEXT 23 /* timer t_next[] */ +#define PC_TIMEOUT_LCT 24 +#define PC_NSE 25 /* NOISE hardware timer */ +#define PC_LEM 26 /* LEM done */ + +/* + * RMT events meaning from + */ +#define RM_RING_OP 1 /* ring operational MAC */ +#define RM_RING_NON_OP 2 /* ring not operational MAC */ +#define RM_MY_BEACON 3 /* recvd my beacon MAC */ +#define RM_OTHER_BEACON 4 /* recvd other beacon MAC */ +#define RM_MY_CLAIM 5 /* recvd my claim MAC */ +#define RM_TRT_EXP 6 /* TRT exp MAC */ +#define RM_VALID_CLAIM 7 /* claim from dup addr MAC */ +#define RM_JOIN 8 /* signal rm_join CFM */ +#define RM_LOOP 9 /* signal rm_loop CFM */ +#define RM_DUP_ADDR 10 /* dup_addr_test hange SMT-NIF */ +#define RM_ENABLE_FLAG 11 /* enable flag */ + +#define RM_TIMEOUT_NON_OP 12 /* timeout T_Non_OP */ +#define RM_TIMEOUT_T_STUCK 13 /* timeout T_Stuck */ +#define RM_TIMEOUT_ANNOUNCE 14 /* timeout T_Announce */ +#define RM_TIMEOUT_T_DIRECT 15 /* timeout T_Direct */ +#define RM_TIMEOUT_D_MAX 16 /* timeout D_Max */ +#define RM_TIMEOUT_POLL 17 /* claim/beacon poller */ +#define RM_TX_STATE_CHANGE 18 /* To restart timer for D_Max */ + +/* + * SMT events + */ +#define SM_TIMER 1 /* timer */ +#define SM_FAST 2 /* smt_force_irq */ + +/* PC modes */ +#define PM_NONE 0 +#define PM_PEER 1 +#define PM_TREE 2 + +/* + * PCM withhold codes + * MIB PC-WithholdType ENUM + */ +#define PC_WH_NONE 0 /* ok */ +#define PC_WH_M_M 1 /* M to M */ +#define PC_WH_OTHER 2 /* other incompatible phys */ +#define PC_WH_PATH 3 /* path not available */ +/* + * LCT duration + */ +#define LC_SHORT 1 /* short LCT */ +#define LC_MEDIUM 2 /* medium LCT */ +#define LC_LONG 3 /* long LCT */ +#define LC_EXTENDED 4 /* extended LCT */ + +/* + * path_test values + */ +#define PT_NONE 0 +#define PT_TESTING 1 /* test is running */ +#define PT_PASSED 2 /* test passed */ +#define PT_FAILED 3 /* test failed */ +#define PT_PENDING 4 /* path test follows */ +#define PT_EXITING 5 /* disconnected while in trace/leave */ + +/* + * duplicate address test + * MIB DupAddressTest ENUM + */ +#define DA_NONE 0 /* */ +#define DA_PASSED 1 /* test passed */ +#define DA_FAILED 2 /* test failed */ + + +/* + * optical bypass + */ +#define BP_DEINSERT 0 /* disable bypass */ +#define BP_INSERT 1 /* enable bypass */ + +/* + * ODL enable/disable + */ +#define PM_TRANSMIT_DISABLE 0 /* disable xmit */ +#define PM_TRANSMIT_ENABLE 1 /* enable xmit */ + +/* + * parameter for config_mux + * note : number is index in config_endec table ! + */ +#define MUX_THRUA 0 /* through A */ +#define MUX_THRUB 1 /* through B */ +#define MUX_WRAPA 2 /* wrap A */ +#define MUX_WRAPB 3 /* wrap B */ +#define MUX_ISOLATE 4 /* isolated */ +#define MUX_WRAPS 5 /* SAS */ + +/* + * MAC control + */ +#define MA_RESET 0 +#define MA_BEACON 1 +#define MA_CLAIM 2 +#define MA_DIRECTED 3 /* directed beacon */ +#define MA_TREQ 4 /* change T_Req */ +#define MA_OFFLINE 5 /* switch MAC to offline */ + + +/* + * trace prop + * bit map for trace propagation + */ +#define ENTITY_MAC (NUMPHYS) +#define ENTITY_PHY(p) (p) +#define ENTITY_BIT(m) (1<<(m)) + +/* + * Resource Tag Types + */ +#define PATH_ISO 0 /* isolated */ +#define PATH_PRIM 3 /* primary path */ +#define PATH_THRU 5 /* through path */ + +#define RES_MAC 2 /* resource type MAC */ +#define RES_PORT 4 /* resource type PORT */ + + +/* + * CFM state + * oops: MUST MATCH CF-StateType in SMT7.2 ! + */ +#define SC0_ISOLATED 0 /* isolated */ +#define SC1_WRAP_A 5 /* wrap A (not used) */ +#define SC2_WRAP_B 6 /* wrap B (not used) */ +#define SC4_THRU_A 12 /* through A */ +#define SC5_THRU_B 7 /* through B (used in SMT 6.2) */ +#define SC7_WRAP_S 8 /* SAS (not used) */ +#define SC9_C_WRAP_A 9 /* c wrap A */ +#define SC10_C_WRAP_B 10 /* c wrap B */ +#define SC11_C_WRAP_S 11 /* c wrap S */ + +/* + * convert MIB time in units of 80nS to uS + */ +#define MIB2US(t) ((t)/12) +#define SEC2MIB(s) ((s)*12500000L) +/* + * SMT timer + */ +struct smt_timer { + struct smt_timer *tm_next ; /* linked list */ + struct s_smc *tm_smc ; /* pointer to context */ + u_long tm_delta ; /* delta time */ + u_long tm_token ; /* token value */ + u_short tm_active ; /* flag : active/inactive */ + u_short tm_pad ; /* pad field */ +} ; + +/* + * communication structures + */ +struct mac_parameter { + u_long t_neg ; /* T_Neg parameter */ + u_long t_pri ; /* T_Pri register in MAC */ +} ; + +/* + * MAC counters + */ +struct mac_counter { + u_long mac_nobuf_counter ; /* MAC SW counter: no buffer */ + u_long mac_r_restart_counter ; /* MAC SW counter: rx restarted */ +} ; + +/* + * para struct context for SMT parameters + */ +struct s_pcon { + int pc_len ; + int pc_err ; + int pc_badset ; + void *pc_p ; +} ; + + +/* + * link error monitor + */ +#define LEM_AVG 5 +struct lem_counter { +#ifdef AM29K + int lem_on ; + u_long lem_errors ; + u_long lem_symbols ; + u_long lem_tsymbols ; + int lem_s_count ; + int lem_n_s ; + int lem_values ; + int lem_index ; + int lem_avg_ber[LEM_AVG] ; + int lem_sum ; +#else + u_short lem_float_ber ; /* 10E-nn bit error rate */ + u_long lem_errors ; /* accumulated error count */ + u_short lem_on ; +#endif +} ; + +#define NUMBITS 10 + + +#ifdef AMDPLC + +/* + * PLC state table + */ +struct s_plc { + u_short p_state ; /* current state */ + u_short p_bits ; /* number of bits to send */ + u_short p_start ; /* first bit pos */ + u_short p_pad ; /* padding for alignment */ + u_long soft_err ; /* error counter */ + u_long parity_err ; /* error counter */ + u_long ebuf_err ; /* error counter */ + u_long ebuf_cont ; /* continous error counter */ + u_long phyinv ; /* error counter */ + u_long vsym_ctr ; /* error counter */ + u_long mini_ctr ; /* error counter */ + u_long tpc_exp ; /* error counter */ + u_long np_err ; /* error counter */ + u_long b_pcs ; /* error counter */ + u_long b_tpc ; /* error counter */ + u_long b_tne ; /* error counter */ + u_long b_qls ; /* error counter */ + u_long b_ils ; /* error counter */ + u_long b_hls ; /* error counter */ +} ; +#endif + +#ifdef PROTOTYP_INC +#include "fddi/driver.pro" +#else /* PROTOTYP_INC */ +/* + * function prototypes + */ +#include "h/mbuf.h" /* Type definitions for MBUFs */ +void hwt_restart( /* hwt.c */ +#ifdef ANSIC + struct s_smc *smc +#endif + ) ; + +SMbuf *smt_build_frame( /* smt.c */ +#ifdef ANSIC + struct s_smc *smc, + int class, + int type, + int length +#endif + ) ; + +SMbuf *smt_get_mbuf( /* drvsr.c */ +#ifdef ANSIC + struct s_smc *smc +#endif + ) ; + +void *sm_to_para( /* smt.c */ +#ifdef ANSIC + struct s_smc *smc, + struct smt_header *sm, + int para +#endif + ) ; + +#ifndef SK_UNUSED +#define SK_UNUSED(var) (void)(var) +#endif + +void queue_event() ; +void ecm() ; +void ecm_init() ; +void rmt() ; +void rmt_init() ; +void pcm() ; +void pcm_init() ; +void cfm() ; +void cfm_init() ; +void smt_timer_start() ; +void smt_timer_stop() ; +void pcm_status_state() ; +void plc_config_mux() ; +void sm_lem_evaluate() ; +void smt_clear_una_dna() ; +void mac_status_para() ; +void mac_update_counter() ; +void sm_pm_ls_latch() ; +void sm_ma_control() ; +void sm_mac_check_beacon_claim() ; +void config_mux() ; +void smt_agent_init() ; +void smt_timer_init() ; +void smt_received_pack() ; +void smt_add_para() ; +void smt_swap_para() ; +void ev_init() ; +void hwt_init() ; +u_long hwt_read() ; +void hwt_stop() ; +void hwt_start() ; +void smt_send_mbuf() ; +void smt_free_mbuf() ; +void sm_pm_bypass_req() ; +void rmt_indication() ; +void cfm_state_change() ; +void rx_indication() ; +void tx_indication() ; +#ifndef NO_SMT_PANIC +void smt_panic() ; +#else +#ifdef DEBUG +void smt_panic() ; +#else +#define smt_panic(smc,text) +#endif /* DEBUG */ +#endif /* NO_SMT_PANIC */ +void smt_stat_counter() ; +void smt_timer_poll() ; +u_long smt_get_time() ; +u_long smt_get_tid() ; +void smt_timer_done() ; +void smt_set_defaults() ; +void smt_fixup_mib() ; +void smt_reset_defaults() ; +void smt_agent_task() ; +void smt_please_reconnect() ; +int smt_check_para() ; +void driver_get_bia() ; +#ifdef SUPERNET_3 +void drv_reset_indication() ; +#endif /* SUPERNET_3 */ +void smt_start_watchdog() ; + +void smt_event() ; +void pcm_event() ; +void rmt_event() ; +void cfm_event() ; +void timer_event() ; +void ev_dispatcher() ; + +void smt_get_state() ; +void ecm_get_state() ; +void pcm_get_state() ; +void rmt_get_state() ; + +void ecm_state_change() ; +int sm_pm_bypass_present() ; +void pcm_state_change() ; +void rmt_state_change() ; +int sm_pm_get_ls() ; +int pcm_get_s_port() ; +int pcm_rooted_station() ; +int cfm_get_mac_input() ; +int cfm_get_mac_output() ; +int port_to_mib() ; +int cem_build_path() ; +int sm_mac_get_tx_state() ; +int is_individual() ; +int is_my_addr() ; +int is_broadcast() ; +int is_equal() ; +char *get_pcmstate() ; + +int smt_action() ; +u_short smt_online() ; +void smt_force_irq() ; +void smt_pmf_received_pack() ; +void smt_send_frame() ; +void smt_set_timestamp() ; +void mac_set_rx_mode() ; +int mac_add_multicast() ; +int mac_set_func_addr() ; +void mac_del_multicast() ; +void mac_update_multicast() ; +void mac_clear_multicast() ; +void mac_rx_directed_beacon() ; +void set_formac_tsync() ; +void formac_reinit_tx() ; +void formac_tx_restart() ; +void process_receive() ; +void init_driver_fplus() ; + +void rtm_irq() ; +void rtm_set_timer() ; +void ring_status_indication() ; +void llc_recover_tx() ; +void llc_restart_tx() ; +void plc_clear_irq() ; +void plc_irq() ; +int smt_set_mac_opvalues() ; +#ifdef TAG_MODE +void mac_drv_pci_fix() ; +void mac_do_pci_fix() ; +void mac_drv_clear_tx_queue() ; +void mac_drv_repair_descr() ; +u_long hwt_quick_read() ; +void hwt_wait_time() ; +#endif + +#ifdef SMT_PNMI +#ifdef ANSIC +int pnmi_init (struct s_smc* smc); +int pnmi_process_ndis_id (struct s_smc* smc, u_long ndis_oid, void* buf, + int len, int* BytesAccessed, int* BytesNeeded, u_char action); +#else +int pnmi_init (); +int pnmi_process_ndis_id (); +#endif +#endif + +#ifdef SBA +#ifndef _H2INC +void sba() ; +#endif +void sba_raf_received_pack() ; +void sba_timer_poll() ; +void smt_init_sba() ; +#endif +#ifdef ESS +int ess_raf_received_pack() ; +void ess_timer_poll() ; +void ess_para_change() ; +#endif + +#ifdef BOOT +#define smt_srf_event(a,b,c,d) +#define smt_init_evc(a) +#else +void smt_init_evc() ; +void smt_srf_event() ; +#endif + +#ifndef SMT_REAL_TOKEN_CT +void smt_emulate_token_ct(); +#endif + +#if defined(DEBUG) && !defined(BOOT) +void dump_smt() ; +#else +#define dump_smt(smc,sm,text) +#endif + +#ifdef DEBUG +char *addr_to_string() ; +void dump_hex() ; +#endif +#endif /* PROTOTYP_INC */ + +/* PNMI default defines */ +#ifndef PNMI_INIT +#define PNMI_INIT(smc) /* Nothing */ +#endif +#ifndef PNMI_GET_ID +#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \ + ( 1 ? (-1) : (-1) ) +#endif +#ifndef PNMI_SET_ID +#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \ + set_type) ( 1 ? (-1) : (-1) ) +#endif + +/* + * SMT_PANIC defines + */ +#ifndef SMT_PANIC +#define SMT_PANIC(smc,nr,msg) smt_panic (smc, msg) +#endif + +#ifndef SMT_ERR_LOG +#define SMT_ERR_LOG(smc,nr,msg) SMT_PANIC (smc, nr, msg) +#endif + +#ifndef SMT_EBASE +#define SMT_EBASE 100 +#endif + +#define SMT_E0100 SMT_EBASE + 0 +#define SMT_E0100_MSG "cfm FSM: illegal ce_type" +#define SMT_E0101 SMT_EBASE + 1 +#define SMT_E0101_MSG "CEM: case ???" +#define SMT_E0102 SMT_EBASE + 2 +#define SMT_E0102_MSG "CEM A: illegal state" +#define SMT_E0103 SMT_EBASE + 3 +#define SMT_E0103_MSG "CEM B: illegal state" +#define SMT_E0104 SMT_EBASE + 4 +#define SMT_E0104_MSG "CEM M: illegal state" +#define SMT_E0105 SMT_EBASE + 5 +#define SMT_E0105_MSG "CEM S: illegal state" +#define SMT_E0106 SMT_EBASE + 6 +#define SMT_E0106_MSG "CFM : illegal state" +#define SMT_E0107 SMT_EBASE + 7 +#define SMT_E0107_MSG "ECM : illegal state" +#define SMT_E0108 SMT_EBASE + 8 +#define SMT_E0108_MSG "prop_actions : NAC in DAS CFM" +#define SMT_E0109 SMT_EBASE + 9 +#define SMT_E0109_MSG "ST2U.FM_SERRSF error in special frame" +#define SMT_E0110 SMT_EBASE + 10 +#define SMT_E0110_MSG "ST2U.FM_SRFRCTOV recv. count. overflow" +#define SMT_E0111 SMT_EBASE + 11 +#define SMT_E0111_MSG "ST2U.FM_SNFSLD NP & FORMAC simult. load" +#define SMT_E0112 SMT_EBASE + 12 +#define SMT_E0112_MSG "ST2U.FM_SRCVFRM single-frame recv.-mode" +#define SMT_E0113 SMT_EBASE + 13 +#define SMT_E0113_MSG "FPLUS: Buffer Memory Error" +#define SMT_E0114 SMT_EBASE + 14 +#define SMT_E0114_MSG "ST2U.FM_SERRSF error in special frame" +#define SMT_E0115 SMT_EBASE + 15 +#define SMT_E0115_MSG "ST3L: parity error in receive queue 2" +#define SMT_E0116 SMT_EBASE + 16 +#define SMT_E0116_MSG "ST3L: parity error in receive queue 1" +#define SMT_E0117 SMT_EBASE + 17 +#define SMT_E0117_MSG "E_SMT_001: RxD count for receive queue 1 = 0" +#define SMT_E0118 SMT_EBASE + 18 +#define SMT_E0118_MSG "PCM : illegal state" +#define SMT_E0119 SMT_EBASE + 19 +#define SMT_E0119_MSG "smt_add_para" +#define SMT_E0120 SMT_EBASE + 20 +#define SMT_E0120_MSG "smt_set_para" +#define SMT_E0121 SMT_EBASE + 21 +#define SMT_E0121_MSG "illegal event in dispatcher" +#define SMT_E0122 SMT_EBASE + 22 +#define SMT_E0122_MSG "RMT : illegal state" +#define SMT_E0123 SMT_EBASE + 23 +#define SMT_E0123_MSG "SBA: state machine has illegal state" +#define SMT_E0124 SMT_EBASE + 24 +#define SMT_E0124_MSG "sba_free_session() called with NULL pointer" +#define SMT_E0125 SMT_EBASE + 25 +#define SMT_E0125_MSG "SBA : illegal session pointer" +#define SMT_E0126 SMT_EBASE + 26 +#define SMT_E0126_MSG "smt_free_mbuf() called with NULL pointer\n" +#define SMT_E0127 SMT_EBASE + 27 +#define SMT_E0127_MSG "sizeof evcs" +#define SMT_E0128 SMT_EBASE + 28 +#define SMT_E0128_MSG "evc->evc_cond_state = 0" +#define SMT_E0129 SMT_EBASE + 29 +#define SMT_E0129_MSG "evc->evc_multiple = 0" +#define SMT_E0130 SMT_EBASE + 30 +#define SMT_E0130_MSG write_mdr_warning +#define SMT_E0131 SMT_EBASE + 31 +#define SMT_E0131_MSG cam_warning +#define SMT_E0132 SMT_EBASE + 32 +#define SMT_E0132_MSG "ST1L.FM_SPCEPDx parity/coding error" +#define SMT_E0133 SMT_EBASE + 33 +#define SMT_E0133_MSG "ST1L.FM_STBURx tx buffer underrun" +#define SMT_E0134 SMT_EBASE + 34 +#define SMT_E0134_MSG "ST1L.FM_SPCEPDx parity error" +#define SMT_E0135 SMT_EBASE + 35 +#define SMT_E0135_MSG "RMT: duplicate MAC address detected. Ring left!" +#define SMT_E0136 SMT_EBASE + 36 +#define SMT_E0136_MSG "Elasticity Buffer hang-up" +#define SMT_E0137 SMT_EBASE + 37 +#define SMT_E0137_MSG "SMT: queue overrun" +#define SMT_E0138 SMT_EBASE + 38 +#define SMT_E0138_MSG "RMT: duplicate MAC address detected. Ring NOT left!" +#endif /* _CMTDEF_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/fddi.h linux/drivers/net/skfp/h/fddi.h --- v2.2.17/drivers/net/skfp/h/fddi.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/fddi.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _FDDI_ +#define _FDDI_ + +struct fddi_addr { + u_char a[6] ; +} ; + +#define GROUP_ADDR 0x80 /* MSB in a[0] */ + +struct fddi_mac { + struct fddi_addr mac_dest ; + struct fddi_addr mac_source ; + u_char mac_info[4478] ; +} ; + +#define FDDI_MAC_SIZE (12) +#define FDDI_RAW_MTU (4500-5) /* exl. Pr,SD, ED/FS */ +#define FDDI_RAW (4500) + +/* + * FC values + */ +#define FC_VOID 0x40 /* void frame */ +#define FC_TOKEN 0x80 /* token */ +#define FC_RES_TOKEN 0xc0 /* restricted token */ +#define FC_SMT_INFO 0x41 /* SMT Info frame */ +/* + * FC_SMT_LAN_LOC && FC_SMT_LOC are SK specific ! + */ +#define FC_SMT_LAN_LOC 0x42 /* local SMT Info frame */ +#define FC_SMT_LOC 0x43 /* local SMT Info frame */ +#define FC_SMT_NSA 0x4f /* SMT NSA frame */ +#define FC_MAC 0xc0 /* MAC frame */ +#define FC_BEACON 0xc2 /* MAC beacon frame */ +#define FC_CLAIM 0xc3 /* MAC claim frame */ +#define FC_SYNC_LLC 0xd0 /* sync. LLC frame */ +#define FC_ASYNC_LLC 0x50 /* async. LLC frame */ +#define FC_SYNC_BIT 0x80 /* sync. bit in FC */ + +#define FC_LLC_PRIOR 0x07 /* priority bits */ + +#define BEACON_INFO 0 /* beacon type */ +#define DBEACON_INFO 1 /* beacon type DIRECTED */ + + +/* + * indicator bits + */ +#define C_INDICATOR (1<<0) +#define A_INDICATOR (1<<1) +#define E_INDICATOR (1<<2) +#define I_INDICATOR (1<<6) /* SK specific */ +#define L_INDICATOR (1<<7) /* SK specific */ + +#endif /* _FDDI_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/fddimib.h linux/drivers/net/skfp/h/fddimib.h --- v2.2.17/drivers/net/skfp/h/fddimib.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/fddimib.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,349 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * FDDI MIB + */ + +/* + * typedefs + */ + +typedef u_long Counter ; +typedef u_char TimeStamp[8] ; +typedef struct fddi_addr LongAddr ; +typedef u_long Timer_2 ; +typedef u_long Timer ; +typedef u_short ResId ; +typedef u_short SMTEnum ; +typedef u_char SMTFlag ; + +typedef struct { + Counter count ; + TimeStamp timestamp ; +} SetCountType ; + +/* + * bits for bit string "available_path" + */ +#define MIB_PATH_P (1<<0) +#define MIB_PATH_S (1<<1) +#define MIB_PATH_L (1<<2) + +/* + * bits for bit string PermittedPaths & RequestedPaths (SIZE(8)) + */ +#define MIB_P_PATH_LOCAL (1<<0) +#define MIB_P_PATH_SEC_ALTER (1<<1) +#define MIB_P_PATH_PRIM_ALTER (1<<2) +#define MIB_P_PATH_CON_ALTER (1<<3) +#define MIB_P_PATH_SEC_PREFER (1<<4) +#define MIB_P_PATH_PRIM_PREFER (1<<5) +#define MIB_P_PATH_CON_PREFER (1<<6) +#define MIB_P_PATH_THRU (1<<7) + +/* + * enum current path + */ +#define MIB_PATH_ISOLATED 0 +#define MIB_PATH_LOCAL 1 +#define MIB_PATH_SECONDARY 2 +#define MIB_PATH_PRIMARY 3 +#define MIB_PATH_CONCATENATED 4 +#define MIB_PATH_THRU 5 + +/* + * enum PMDClass + */ +#define MIB_PMDCLASS_MULTI 0 +#define MIB_PMDCLASS_SINGLE1 1 +#define MIB_PMDCLASS_SINGLE2 2 +#define MIB_PMDCLASS_SONET 3 +#define MIB_PMDCLASS_LCF 4 +#define MIB_PMDCLASS_TP 5 +#define MIB_PMDCLASS_UNKNOWN 6 +#define MIB_PMDCLASS_UNSPEC 7 + +/* + * enum SMTStationStatus + */ +#define MIB_SMT_STASTA_CON 0 +#define MIB_SMT_STASTA_SEPA 1 +#define MIB_SMT_STASTA_THRU 2 + + +struct fddi_mib { + /* + * private + */ + u_char fddiPRPMFPasswd[8] ; + struct smt_sid fddiPRPMFStation ; + +#ifdef ESS + /* + * private variables for static allocation of the + * End Station Support + */ + u_long fddiESSPayload ; /* payload for static alloc */ + u_long fddiESSOverhead ; /* frame ov for static alloc */ + u_long fddiESSMaxTNeg ; /* maximum of T-NEG */ + u_long fddiESSMinSegmentSize ; /* min size of the sync frames */ + u_long fddiESSCategory ; /* category for the Alloc req */ + short fddiESSSynchTxMode ; /* send all LLC frames as sync */ +#endif /* ESS */ +#ifdef SBA + /* + * private variables for the Synchronous Bandwidth Allocator + */ + char fddiSBACommand ; /* holds the parsed SBA cmd */ + u_char fddiSBAAvailable ; /* SBA allocatable value */ +#endif /* SBA */ + + /* + * SMT standard mib + */ + struct smt_sid fddiSMTStationId ; + u_short fddiSMTOpVersionId ; + u_short fddiSMTHiVersionId ; + u_short fddiSMTLoVersionId ; + u_char fddiSMTManufacturerData[32] ; + u_char fddiSMTUserData[32] ; + u_short fddiSMTMIBVersionId ; + + /* + * ConfigGrp + */ + u_char fddiSMTMac_Ct ; + u_char fddiSMTNonMaster_Ct ; + u_char fddiSMTMaster_Ct ; + u_char fddiSMTAvailablePaths ; + u_short fddiSMTConfigCapabilities ; + u_short fddiSMTConfigPolicy ; + u_short fddiSMTConnectionPolicy ; + u_short fddiSMTTT_Notify ; + u_char fddiSMTStatRptPolicy ; + u_long fddiSMTTrace_MaxExpiration ; + u_short fddiSMTPORTIndexes[NUMPHYS] ; + u_short fddiSMTMACIndexes ; + u_char fddiSMTBypassPresent ; + + /* + * StatusGrp + */ + SMTEnum fddiSMTECMState ; + SMTEnum fddiSMTCF_State ; + SMTEnum fddiSMTStationStatus ; + u_char fddiSMTRemoteDisconnectFlag ; + u_char fddiSMTPeerWrapFlag ; + + /* + * MIBOperationGrp + */ + TimeStamp fddiSMTTimeStamp ; + TimeStamp fddiSMTTransitionTimeStamp ; + SetCountType fddiSMTSetCount ; + struct smt_sid fddiSMTLastSetStationId ; + + struct fddi_mib_m { + u_short fddiMACFrameStatusFunctions ; + Timer_2 fddiMACT_MaxCapabilitiy ; + Timer_2 fddiMACTVXCapabilitiy ; + + /* ConfigGrp */ + u_char fddiMACMultiple_N ; /* private */ + u_char fddiMACMultiple_P ; /* private */ + u_char fddiMACDuplicateAddressCond ;/* private */ + u_char fddiMACAvailablePaths ; + u_short fddiMACCurrentPath ; + LongAddr fddiMACUpstreamNbr ; + LongAddr fddiMACDownstreamNbr ; + LongAddr fddiMACOldUpstreamNbr ; + LongAddr fddiMACOldDownstreamNbr ; + SMTEnum fddiMACDupAddressTest ; + u_short fddiMACRequestedPaths ; + SMTEnum fddiMACDownstreamPORTType ; + ResId fddiMACIndex ; + + /* AddressGrp */ + LongAddr fddiMACSMTAddress ; + + /* OperationGrp */ + Timer_2 fddiMACT_Min ; /* private */ + Timer_2 fddiMACT_ReqMIB ; + Timer_2 fddiMACT_Req ; /* private */ + Timer_2 fddiMACT_Neg ; + Timer_2 fddiMACT_MaxMIB ; + Timer_2 fddiMACT_Max ; /* private */ + Timer_2 fddiMACTvxValueMIB ; + Timer_2 fddiMACTvxValue ; /* private */ + Timer_2 fddiMACT_Pri0 ; + Timer_2 fddiMACT_Pri1 ; + Timer_2 fddiMACT_Pri2 ; + Timer_2 fddiMACT_Pri3 ; + Timer_2 fddiMACT_Pri4 ; + Timer_2 fddiMACT_Pri5 ; + Timer_2 fddiMACT_Pri6 ; + + /* CountersGrp */ + Counter fddiMACFrame_Ct ; + Counter fddiMACCopied_Ct ; + Counter fddiMACTransmit_Ct ; + Counter fddiMACToken_Ct ; + Counter fddiMACError_Ct ; + Counter fddiMACLost_Ct ; + Counter fddiMACTvxExpired_Ct ; + Counter fddiMACNotCopied_Ct ; + Counter fddiMACRingOp_Ct ; + + Counter fddiMACSMTCopied_Ct ; /* private */ + Counter fddiMACSMTTransmit_Ct ; /* private */ + + /* private for delta ratio */ + Counter fddiMACOld_Frame_Ct ; + Counter fddiMACOld_Copied_Ct ; + Counter fddiMACOld_Error_Ct ; + Counter fddiMACOld_Lost_Ct ; + Counter fddiMACOld_NotCopied_Ct ; + + /* FrameErrorConditionGrp */ + u_short fddiMACFrameErrorThreshold ; + u_short fddiMACFrameErrorRatio ; + + /* NotCopiedConditionGrp */ + u_short fddiMACNotCopiedThreshold ; + u_short fddiMACNotCopiedRatio ; + + /* StatusGrp */ + SMTEnum fddiMACRMTState ; + SMTFlag fddiMACDA_Flag ; + SMTFlag fddiMACUNDA_Flag ; + SMTFlag fddiMACFrameErrorFlag ; + SMTFlag fddiMACNotCopiedFlag ; + SMTFlag fddiMACMA_UnitdataAvailable ; + SMTFlag fddiMACHardwarePresent ; + SMTFlag fddiMACMA_UnitdataEnable ; + + } m[NUMMACS] ; +#define MAC0 0 + + struct fddi_mib_a { + ResId fddiPATHIndex ; + u_long fddiPATHSbaPayload ; + u_long fddiPATHSbaOverhead ; + /* fddiPATHConfiguration is built on demand */ + /* u_long fddiPATHConfiguration ; */ + Timer fddiPATHT_Rmode ; + u_long fddiPATHSbaAvailable ; + Timer_2 fddiPATHTVXLowerBound ; + Timer_2 fddiPATHT_MaxLowerBound ; + Timer_2 fddiPATHMaxT_Req ; + } a[NUMPATHS] ; +#define PATH0 0 + + struct fddi_mib_p { + /* ConfigGrp */ + SMTEnum fddiPORTMy_Type ; + SMTEnum fddiPORTNeighborType ; + u_char fddiPORTConnectionPolicies ; + struct { + u_char T_val ; + u_char R_val ; + } fddiPORTMacIndicated ; + SMTEnum fddiPORTCurrentPath ; + /* must be 4: is 32 bit in SMT format + * indices : + * 1 none + * 2 tree + * 3 peer + */ + u_char fddiPORTRequestedPaths[4] ; + u_short fddiPORTMACPlacement ; + u_char fddiPORTAvailablePaths ; + u_char fddiPORTConnectionCapabilities ; + SMTEnum fddiPORTPMDClass ; + ResId fddiPORTIndex ; + + /* OperationGrp */ + SMTEnum fddiPORTMaint_LS ; + SMTEnum fddiPORTPC_LS ; + u_char fddiPORTBS_Flag ; + + /* ErrorCtrsGrp */ + Counter fddiPORTLCTFail_Ct ; + Counter fddiPORTEBError_Ct ; + Counter fddiPORTOldEBError_Ct ; + + /* LerGrp */ + Counter fddiPORTLem_Reject_Ct ; + Counter fddiPORTLem_Ct ; + u_char fddiPORTLer_Estimate ; + u_char fddiPORTLer_Cutoff ; + u_char fddiPORTLer_Alarm ; + + /* StatusGrp */ + SMTEnum fddiPORTConnectState ; + SMTEnum fddiPORTPCMState ; /* real value */ + SMTEnum fddiPORTPCMStateX ; /* value for MIB */ + SMTEnum fddiPORTPC_Withhold ; + SMTFlag fddiPORTHardwarePresent ; + u_char fddiPORTLerFlag ; + + u_char fddiPORTMultiple_U ; /* private */ + u_char fddiPORTMultiple_P ; /* private */ + u_char fddiPORTEB_Condition ; /* private */ + } p[NUMPHYS] ; + struct { + Counter fddiPRIVECF_Req_Rx ; /* ECF req received */ + Counter fddiPRIVECF_Reply_Rx ; /* ECF repl received */ + Counter fddiPRIVECF_Req_Tx ; /* ECF req transm */ + Counter fddiPRIVECF_Reply_Tx ; /* ECF repl transm */ + Counter fddiPRIVPMF_Get_Rx ; /* PMF Get rec */ + Counter fddiPRIVPMF_Set_Rx ; /* PMF Set rec */ + Counter fddiPRIVRDF_Rx ; /* RDF received */ + Counter fddiPRIVRDF_Tx ; /* RDF transmitted */ + } priv ; +} ; + +/* + * OIDs for statistics + */ +#define SMT_OID_CF_STATE 1 /* fddiSMTCF_State */ +#define SMT_OID_PCM_STATE_A 2 /* fddiPORTPCMState port A */ +#define SMT_OID_PCM_STATE_B 17 /* fddiPORTPCMState port B */ +#define SMT_OID_RMT_STATE 3 /* fddiMACRMTState */ +#define SMT_OID_UNA 4 /* fddiMACUpstreamNbr */ +#define SMT_OID_DNA 5 /* fddiMACOldDownstreamNbr */ +#define SMT_OID_ERROR_CT 6 /* fddiMACError_Ct */ +#define SMT_OID_LOST_CT 7 /* fddiMACLost_Ct */ +#define SMT_OID_LEM_CT 8 /* fddiPORTLem_Ct */ +#define SMT_OID_LEM_CT_A 11 /* fddiPORTLem_Ct port A */ +#define SMT_OID_LEM_CT_B 12 /* fddiPORTLem_Ct port B */ +#define SMT_OID_LCT_FAIL_CT 9 /* fddiPORTLCTFail_Ct */ +#define SMT_OID_LCT_FAIL_CT_A 13 /* fddiPORTLCTFail_Ct port A */ +#define SMT_OID_LCT_FAIL_CT_B 14 /* fddiPORTLCTFail_Ct port B */ +#define SMT_OID_LEM_REJECT_CT 10 /* fddiPORTLem_Reject_Ct */ +#define SMT_OID_LEM_REJECT_CT_A 15 /* fddiPORTLem_Reject_Ct port A */ +#define SMT_OID_LEM_REJECT_CT_B 16 /* fddiPORTLem_Reject_Ct port B */ + +/* + * SK MIB + */ +#define SMT_OID_ECF_REQ_RX 20 /* ECF requests received */ +#define SMT_OID_ECF_REPLY_RX 21 /* ECF replies received */ +#define SMT_OID_ECF_REQ_TX 22 /* ECF requests transmitted */ +#define SMT_OID_ECF_REPLY_TX 23 /* ECF replies transmitted */ +#define SMT_OID_PMF_GET_RX 24 /* PMF get requests received */ +#define SMT_OID_PMF_SET_RX 25 /* PMF set requests received */ +#define SMT_OID_RDF_RX 26 /* RDF received */ +#define SMT_OID_RDF_TX 27 /* RDF transmitted */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/fplustm.h linux/drivers/net/skfp/h/fplustm.h --- v2.2.17/drivers/net/skfp/h/fplustm.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/fplustm.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,278 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * AMD Fplus in tag mode data structs + * defs for fplustm.c + */ + +#ifndef _FPLUS_ +#define _FPLUS_ + +#ifndef HW_PTR +#ifdef MEM_MAPPED_IO +#define HW_PTR u_long +#else +#define HW_PTR u_short +#endif +#endif + +/* + * fplus error statistic structure + */ +struct err_st { + u_long err_valid ; /* memory status valid */ + u_long err_abort ; /* memory status receive abort */ + u_long err_e_indicator ; /* error indicator */ + u_long err_crc ; /* error detected (CRC or length) */ + u_long err_llc_frame ; /* LLC frame */ + u_long err_mac_frame ; /* MAC frame */ + u_long err_smt_frame ; /* SMT frame */ + u_long err_imp_frame ; /* implementer frame */ + u_long err_no_buf ; /* no buffer available */ + u_long err_too_long ; /* longer than max. buffer */ + u_long err_bec_stat ; /* beacon state entered */ + u_long err_clm_stat ; /* claim state entered */ + u_long err_sifg_det ; /* short interframe gap detect */ + u_long err_phinv ; /* PHY invalid */ + u_long err_tkiss ; /* token issued */ + u_long err_tkerr ; /* token error */ +} ; + +/* + * Transmit Descriptor struct + */ +struct s_smt_fp_txd { + u_int txd_tbctrl ; /* transmit buffer control */ + u_int txd_txdscr ; /* transmit frame status word */ + u_int txd_tbadr ; /* physical tx buffer address */ + u_int txd_ntdadr ; /* physical pointer to the next TxD */ +#ifdef ENA_64BIT_SUP + u_int txd_tbadr_hi ; /* physical tx buffer addr (high dword)*/ +#endif + char far *txd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next TxD */ + struct s_smt_fp_txd volatile far *txd_next ; + struct s_txd_os txd_os ; /* OS - specific struct */ +} ; + +/* + * Receive Descriptor struct + */ +struct s_smt_fp_rxd { + u_int rxd_rbctrl ; /* receive buffer control */ + u_int rxd_rfsw ; /* receive frame status word */ + u_int rxd_rbadr ; /* physical rx buffer address */ + u_int rxd_nrdadr ; /* physical pointer to the next RxD */ +#ifdef ENA_64BIT_SUP + u_int rxd_rbadr_hi ; /* physical tx buffer addr (high dword)*/ +#endif + char far *rxd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next RxD */ + struct s_smt_fp_rxd volatile far *rxd_next ; + struct s_rxd_os rxd_os ; /* OS - specific struct */ +} ; + +/* + * Descriptor Union Definition + */ +union s_fp_descr { + struct s_smt_fp_txd t ; /* pointer to the TxD */ + struct s_smt_fp_rxd r ; /* pointer to the RxD */ +} ; + +/* + * TxD Ring Control struct + */ +struct s_smt_tx_queue { + struct s_smt_fp_txd volatile *tx_curr_put ; /* next free TxD */ + struct s_smt_fp_txd volatile *tx_prev_put ; /* shadow put pointer */ + struct s_smt_fp_txd volatile *tx_curr_get ; /* next TxD to release*/ + u_short tx_free ; /* count of free TxD's */ + u_short tx_used ; /* count of used TxD's */ + HW_PTR tx_bmu_ctl ; /* BMU addr for tx start */ + HW_PTR tx_bmu_dsc ; /* BMU addr for curr dsc. */ +} ; + +/* + * RxD Ring Control struct + */ +struct s_smt_rx_queue { + struct s_smt_fp_rxd volatile *rx_curr_put ; /* next RxD to queue into */ + struct s_smt_fp_rxd volatile *rx_prev_put ; /* shadow put pointer */ + struct s_smt_fp_rxd volatile *rx_curr_get ; /* next RxD to fill */ + u_short rx_free ; /* count of free RxD's */ + u_short rx_used ; /* count of used RxD's */ + HW_PTR rx_bmu_ctl ; /* BMU addr for rx start */ + HW_PTR rx_bmu_dsc ; /* BMU addr for curr dsc. */ +} ; + +#define VOID_FRAME_OFF 0x00 +#define CLAIM_FRAME_OFF 0x08 +#define BEACON_FRAME_OFF 0x10 +#define DBEACON_FRAME_OFF 0x18 +#define RX_FIFO_OFF 0x21 /* to get a prime number for */ + /* the RX_FIFO_SPACE */ + +#define RBC_MEM_SIZE 0x8000 +#define SEND_ASYNC_AS_SYNC 0x1 +#define SYNC_TRAFFIC_ON 0x2 + +/* big FIFO memory */ +#define RX_FIFO_SPACE 0x4000 - RX_FIFO_OFF +#define TX_FIFO_SPACE 0x4000 + +#define TX_SMALL_FIFO 0x0900 +#define TX_MEDIUM_FIFO TX_FIFO_SPACE / 2 +#define TX_LARGE_FIFO TX_FIFO_SPACE - TX_SMALL_FIFO + +#define RX_SMALL_FIFO 0x0900 +#define RX_LARGE_FIFO RX_FIFO_SPACE - RX_SMALL_FIFO + +struct s_smt_fifo_conf { + u_short rbc_ram_start ; /* FIFO start address */ + u_short rbc_ram_end ; /* FIFO size */ + u_short rx1_fifo_start ; /* rx queue start address */ + u_short rx1_fifo_size ; /* rx queue size */ + u_short rx2_fifo_start ; /* rx queue start address */ + u_short rx2_fifo_size ; /* rx queue size */ + u_short tx_s_start ; /* sync queue start address */ + u_short tx_s_size ; /* sync queue size */ + u_short tx_a0_start ; /* async queue A0 start address */ + u_short tx_a0_size ; /* async queue A0 size */ + u_short fifo_config_mode ; /* FIFO configuration mode */ +} ; + +#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) + +struct s_smt_fp { + u_short mdr2init ; /* mode register 2 init value */ + u_short mdr3init ; /* mode register 3 init value */ + u_short frselreg_init ; /* frame selection register init val */ + u_short rx_mode ; /* address mode broad/multi/promisc */ + u_short nsa_mode ; + u_short rx_prom ; + u_short exgpa ; + + struct err_st err_stats ; /* error statistics */ + + /* + * MAC buffers + */ + struct fddi_mac_sf { /* special frame build buffer */ + u_char mac_fc ; + struct fddi_addr mac_dest ; + struct fddi_addr mac_source ; + u_char mac_info[0x20] ; + } mac_sfb ; + + + /* + * queues + */ +#define QUEUE_S 0 +#define QUEUE_A0 1 +#define QUEUE_R1 0 +#define QUEUE_R2 1 +#define USED_QUEUES 2 + + /* + * queue pointers; points to the queue dependent variables + */ + struct s_smt_tx_queue *tx[USED_QUEUES] ; + struct s_smt_rx_queue *rx[USED_QUEUES] ; + + /* + * queue dependent variables + */ + struct s_smt_tx_queue tx_q[USED_QUEUES] ; + struct s_smt_rx_queue rx_q[USED_QUEUES] ; + + /* + * FIFO configuration struct + */ + struct s_smt_fifo_conf fifo ; + + /* last formac status */ + u_short s2u ; + u_short s2l ; + + /* calculated FORMAC+ reg.addr. */ + HW_PTR fm_st1u ; + HW_PTR fm_st1l ; + HW_PTR fm_st2u ; + HW_PTR fm_st2l ; + HW_PTR fm_st3u ; + HW_PTR fm_st3l ; + + + /* + * multicast table + */ +#define FPMAX_MULTICAST 32 +#define SMT_MAX_MULTI 4 + struct { + struct s_fpmc { + struct fddi_addr a ; /* mc address */ + u_char n ; /* usage counter */ + u_char perm ; /* flag: permanent */ + } table[FPMAX_MULTICAST] ; + } mc ; + struct fddi_addr group_addr ; + u_long func_addr ; /* functional address */ + int smt_slots_used ; /* count of table entries for the SMT */ + int os_slots_used ; /* count of table entries */ + /* used by the os-specific module */ +} ; + +/* + * modes for mac_set_rx_mode() + */ +#define RX_ENABLE_ALLMULTI 1 /* enable all multicasts */ +#define RX_DISABLE_ALLMULTI 2 /* disable "enable all multicasts" */ +#define RX_ENABLE_PROMISC 3 /* enable promiscous */ +#define RX_DISABLE_PROMISC 4 /* disable promiscous */ +#define RX_ENABLE_NSA 5 /* enable reception of NSA frames */ +#define RX_DISABLE_NSA 6 /* disable reception of NSA frames */ + + +/* + * support for byte reversal in AIX + * (descriptors and pointers must be byte reversed in memory + * CPU is big endian; M-Channel is little endian) + */ +#ifdef AIX +#define MDR_REV +#define AIX_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#else +#ifndef AIX_REVERSE +#define AIX_REVERSE(x) (x) +#endif +#endif + +#ifdef MDR_REV +#define MDR_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#else +#ifndef MDR_REVERSE +#define MDR_REVERSE(x) (x) +#endif +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/hwmtm.h linux/drivers/net/skfp/h/hwmtm.h --- v2.2.17/drivers/net/skfp/h/hwmtm.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/hwmtm.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,424 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _HWM_ +#define _HWM_ + +#include "h/mbuf.h" + +/* + * MACRO for DMA synchronization: + * The descriptor 'desc' is flushed for the device 'flag'. + * Devices are the CPU (DDI_DMA_SYNC_FORCPU) and the + * adapter (DDI_DMA_SYNC_FORDEV). + * + * 'desc' Pointer to a Rx or Tx descriptor. + * 'flag' Flag for direction (view for CPU or DEVICE) that + * should be synchronized. + * + * Empty macros and defines are specified here. The real macro + * is os-specific and should be defined in osdef1st.h. + */ +#ifndef DRV_BUF_FLUSH +#define DRV_BUF_FLUSH(desc,flag) +#define DDI_DMA_SYNC_FORCPU +#define DDI_DMA_SYNC_FORDEV +#endif + + /* + * hardware modul dependent receive modes + */ +#define RX_ENABLE_PASS_SMT 21 +#define RX_DISABLE_PASS_SMT 22 +#define RX_ENABLE_PASS_NSA 23 +#define RX_DISABLE_PASS_NSA 24 +#define RX_ENABLE_PASS_DB 25 +#define RX_DISABLE_PASS_DB 26 +#define RX_DISABLE_PASS_ALL 27 +#define RX_DISABLE_LLC_PROMISC 28 +#define RX_ENABLE_LLC_PROMISC 29 + + +#ifndef DMA_RD +#define DMA_RD 1 /* memory -> hw */ +#endif +#ifndef DMA_WR +#define DMA_WR 2 /* hw -> memory */ +#endif +#define SMT_BUF 0x80 + + /* + * bits of the frame status byte + */ +#define EN_IRQ_EOF 0x02 /* get IRQ after end of frame transmission */ +#define LOC_TX 0x04 /* send frame to the local SMT */ +#define LAST_FRAG 0x08 /* last TxD of the frame */ +#define FIRST_FRAG 0x10 /* first TxD of the frame */ +#define LAN_TX 0x20 /* send frame to network if set */ +#define RING_DOWN 0x40 /* error: unable to send, ring down */ +#define OUT_OF_TXD 0x80 /* error: not enough TxDs available */ + + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef LITTLE_ENDIAN +#define HWM_REVERSE(x) (x) +#else +#define HWM_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#endif + +#define C_INDIC (1L<<25) +#define A_INDIC (1L<<26) +#define RD_FS_LOCAL 0x80 + + /* + * DEBUG FLAGS + */ +#define DEBUG_SMTF 1 +#define DEBUG_SMT 2 +#define DEBUG_ECM 3 +#define DEBUG_RMT 4 +#define DEBUG_CFM 5 +#define DEBUG_PCM 6 +#define DEBUG_SBA 7 +#define DEBUG_ESS 8 + +#define DB_HWM_RX 10 +#define DB_HWM_TX 11 +#define DB_HWM_GEN 12 + +struct s_mbuf_pool { +#ifndef MB_OUTSIDE_SMC + SMbuf mb[MAX_MBUF] ; /* mbuf pool */ +#endif + SMbuf *mb_start ; /* points to the first mb */ + SMbuf *mb_free ; /* free queue */ +} ; + +struct hwm_r { + /* + * hardware modul specific receive variables + */ + u_int len ; /* length of the whole frame */ + char *mb_pos ; /* SMbuf receive position */ +} ; + +struct hw_modul { + /* + * All hardware modul specific variables + */ + struct s_mbuf_pool mbuf_pool ; + struct hwm_r r ; + + union s_fp_descr volatile *descr_p ; /* points to the desriptor area */ + + u_short pass_SMT ; /* pass SMT frames */ + u_short pass_NSA ; /* pass all NSA frames */ + u_short pass_DB ; /* pass Direct Beacon Frames */ + u_short pass_llc_promisc ; /* pass all llc frames (default ON) */ + + SMbuf *llc_rx_pipe ; /* points to the first queued llc fr */ + SMbuf *llc_rx_tail ; /* points to the last queued llc fr */ + int queued_rx_frames ; /* number of queued frames */ + + SMbuf *txd_tx_pipe ; /* points to first mb in the txd ring */ + SMbuf *txd_tx_tail ; /* points to last mb in the txd ring */ + int queued_txd_mb ; /* number of SMT MBufs in txd ring */ + + int rx_break ; /* rev. was breaked because ind. off */ + int leave_isr ; /* leave fddi_isr immedeately if set */ + int isr_flag ; /* set, when HWM is entered from isr */ + /* + * varaibles for the current transmit frame + */ + struct s_smt_tx_queue *tx_p ; /* pointer to the transmit queue */ + u_long tx_descr ; /* tx descriptor for FORMAC+ */ + int tx_len ; /* tx frame length */ + SMbuf *tx_mb ; /* SMT tx MBuf pointer */ + char *tx_data ; /* data pointer to the SMT tx Mbuf */ + + int detec_count ; /* counter for out of RxD condition */ + u_long rx_len_error ; /* rx len FORMAC != sum of fragments */ +} ; + + +/* + * DEBUG structs and macros + */ + +#ifdef DEBUG +struct os_debug { + int hwm_rx ; + int hwm_tx ; + int hwm_gen ; +} ; +#endif + +#ifdef DEBUG +#ifdef DEBUG_BRD +#define DB_P smc->debug +#else +#define DB_P debug +#endif + +#define DB_RX(a,b,c,lev) if (DB_P.d_os.hwm_rx >= (lev)) printf(a,b,c) +#define DB_TX(a,b,c,lev) if (DB_P.d_os.hwm_tx >= (lev)) printf(a,b,c) +#define DB_GEN(a,b,c,lev) if (DB_P.d_os.hwm_gen >= (lev)) printf(a,b,c) +#else /* DEBUG */ +#define DB_RX(a,b,c,lev) +#define DB_TX(a,b,c,lev) +#define DB_GEN(a,b,c,lev) +#endif /* DEBUG */ + +#ifndef SK_BREAK +#define SK_BREAK() +#endif + + +/* + * HWM Macros + */ + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_PHYS) + * u_long HWM_GET_TX_PHYS(txd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the physical address of the specified TxD. + * + * para txd pointer to the TxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_PHYS(txd) (u_long)AIX_REVERSE((txd)->txd_tbadr) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_LEN) + * int HWM_GET_TX_LEN(txd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the fragment length of the specified TxD + * + * para rxd pointer to the TxD + * + * return the length of the fragment in bytes + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_LEN(txd) ((int)AIX_REVERSE((txd)->txd_tbctrl)& RD_LENGTH) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_USED) + * txd *HWM_GET_TX_USED(smc,queue) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * number of used TxDs for the queue, specified by the index. + * + * para queue the number of the send queue: Can be specified by + * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) + * + * return number of used TxDs for this send queue + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_USED(smc,queue) (int) (smc)->hw.fp.tx_q[queue].tx_used + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_TXD) + * txd *HWM_GET_CURR_TXD(smc,queue) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * pointer to the TxD which points to the current queue put + * position. + * + * para queue the number of the send queue: Can be specified by + * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) + * + * return pointer to the current TxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_CURR_TXD(smc,queue) (struct s_smt_fp_txd volatile *)\ + (smc)->hw.fp.tx_q[queue].tx_curr_put + +/* + * BEGIN_MANUAL_ENTRY(HWM_TX_CHECK) + * void HWM_TX_CHECK(smc,frame_status,low_water) + * + * function MACRO (hardware module, hwmtm.h) + * This macro is invoked by the OS-specific before it left it's + * driver_send function. This macro calls mac_drv_clear_txd + * if the free TxDs of the current transmit queue is equal or + * lower than the given low water mark. + * + * para frame_status status of the frame, see design description + * low_water low water mark of free TxD's + * + * END_MANUAL_ENTRY + */ +#ifndef HWM_NO_FLOW_CTL +#define HWM_TX_CHECK(smc,frame_status,low_water) {\ + if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\ + mac_drv_clear_txd(smc) ;\ + }\ +} +#else +#define HWM_TX_CHECK(smc,frame_status,low_water) mac_drv_clear_txd(smc) +#endif + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN) + * int HWM_GET_RX_FRAG_LEN(rxd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the fragment length of the specified RxD + * + * para rxd pointer to the RxD + * + * return the length of the fragment in bytes + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_FRAG_LEN(rxd) ((int)AIX_REVERSE((rxd)->rxd_rbctrl)& \ + RD_LENGTH) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_PHYS) + * u_long HWM_GET_RX_PHYS(rxd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the physical address of the specified RxD. + * + * para rxd pointer to the RxD + * + * return the RxD's physical pointer to the data fragment + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_PHYS(rxd) (u_long)AIX_REVERSE((rxd)->rxd_rbadr) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_USED) + * int HWM_GET_RX_USED(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get + * the count of used RXDs in receive queue 1. + * + * return the used RXD count of receive queue 1 + * + * NOTE: Remember, because of an ASIC bug at least one RXD should be unused + * in the descriptor ring ! + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_USED(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_used) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FREE) + * int HWM_GET_RX_FREE(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get + * the rxd_free count of receive queue 1. + * + * return the rxd_free count of receive queue 1 + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_FREE(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_free-1) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_RXD) + * rxd *HWM_GET_CURR_RXD(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * pointer to the RxD which points to the current queue put + * position. + * + * return pointer to the current RxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_CURR_RXD(smc) (struct s_smt_fp_rxd volatile *)\ + (smc)->hw.fp.rx_q[QUEUE_R1].rx_curr_put + +/* + * BEGIN_MANUAL_ENTRY(HWM_RX_CHECK) + * void HWM_RX_CHECK(smc,low_water) + * + * function MACRO (hardware module, hwmtm.h) + * This macro is invoked by the OS-specific before it left the + * function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd + * if the number of used RxDs is equal or lower than the + * the given low water mark. + * + * para low_water low water mark of used RxD's + * + * END_MANUAL_ENTRY + */ +#ifndef HWM_NO_FLOW_CTL +#define HWM_RX_CHECK(smc,low_water) {\ + if ((low_water) >= (smc)->hw.fp.rx_q[QUEUE_R1].rx_used) {\ + mac_drv_fill_rxd(smc) ;\ + }\ +} +#else +#define HWM_RX_CHECK(smc,low_water) mac_drv_fill_rxd(smc) +#endif + +#ifndef HWM_EBASE +#define HWM_EBASE 500 +#endif + +#define HWM_E0001 HWM_EBASE + 1 +#define HWM_E0001_MSG "HWM: Wrong size of s_rxd_os struct" +#define HWM_E0002 HWM_EBASE + 2 +#define HWM_E0002_MSG "HWM: Wrong size of s_txd_os struct" +#define HWM_E0003 HWM_EBASE + 3 +#define HWM_E0003_MSG "HWM: smt_free_mbuf() called with NULL pointer" +#define HWM_E0004 HWM_EBASE + 4 +#define HWM_E0004_MSG "HWM: Parity error rx queue 1" +#define HWM_E0005 HWM_EBASE + 5 +#define HWM_E0005_MSG "HWM: Encoding error rx queue 1" +#define HWM_E0006 HWM_EBASE + 6 +#define HWM_E0006_MSG "HWM: Encoding error async tx queue" +#define HWM_E0007 HWM_EBASE + 7 +#define HWM_E0007_MSG "HWM: Encoding error sync tx queue" +#define HWM_E0008 HWM_EBASE + 8 +#define HWM_E0008_MSG "" +#define HWM_E0009 HWM_EBASE + 9 +#define HWM_E0009_MSG "HWM: Out of RxD condition detected" +#define HWM_E0010 HWM_EBASE + 10 +#define HWM_E0010_MSG "HWM: A protocol layer has tried to send a frame with an invalid frame control" +#define HWM_E0011 HWM_EBASE + 11 +#define HWM_E0011_MSG "HWM: mac_drv_clear_tx_queue was called although the hardware wasn't stopped" +#define HWM_E0012 HWM_EBASE + 12 +#define HWM_E0012_MSG "HWM: mac_drv_clear_rx_queue was called although the hardware wasn't stopped" +#define HWM_E0013 HWM_EBASE + 13 +#define HWM_E0013_MSG "HWM: mac_drv_repair_descr was called although the hardware wasn't stopped" + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/lnkstat.h linux/drivers/net/skfp/h/lnkstat.h --- v2.2.17/drivers/net/skfp/h/lnkstat.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/lnkstat.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * Definition of the Error Log Structure + * This structure will be copied into the Error Log buffer + * during the NDIS General Request ReadErrorLog by the MAC Driver + */ + +struct s_error_log { + + /* + * place holder for token ring adapter error log (zeros) + */ + u_char reserved_0 ; /* byte 0 inside Error Log */ + u_char reserved_1 ; /* byte 1 */ + u_char reserved_2 ; /* byte 2 */ + u_char reserved_3 ; /* byte 3 */ + u_char reserved_4 ; /* byte 4 */ + u_char reserved_5 ; /* byte 5 */ + u_char reserved_6 ; /* byte 6 */ + u_char reserved_7 ; /* byte 7 */ + u_char reserved_8 ; /* byte 8 */ + u_char reserved_9 ; /* byte 9 */ + u_char reserved_10 ; /* byte 10 */ + u_char reserved_11 ; /* byte 11 */ + u_char reserved_12 ; /* byte 12 */ + u_char reserved_13 ; /* byte 13 */ + + /* + * FDDI link statistics + */ +/* + * smt error low + */ +#define SMT_ERL_AEB (1<<15) /* A elast. buffer */ +#define SMT_ERL_BLC (1<<14) /* B link error condition */ +#define SMT_ERL_ALC (1<<13) /* A link error condition */ +#define SMT_ERL_NCC (1<<12) /* not copied condition */ +#define SMT_ERL_FEC (1<<11) /* frame error condition */ + +/* + * smt event low + */ +#define SMT_EVL_NCE (1<<5) + + u_short smt_error_low ; /* byte 14/15 */ + u_short smt_error_high ; /* byte 16/17 */ + u_short smt_event_low ; /* byte 18/19 */ + u_short smt_event_high ; /* byte 20/21 */ + u_short connection_policy_violation ; /* byte 22/23 */ + u_short port_event ; /* byte 24/25 */ + u_short set_count_low ; /* byte 26/27 */ + u_short set_count_high ; /* byte 28/29 */ + u_short aci_id_code ; /* byte 30/31 */ + u_short purge_frame_counter ; /* byte 32/33 */ + + /* + * CMT and RMT state machines + */ + u_short ecm_state ; /* byte 34/35 */ + u_short pcm_a_state ; /* byte 36/37 */ + u_short pcm_b_state ; /* byte 38/39 */ + u_short cfm_state ; /* byte 40/41 */ + u_short rmt_state ; /* byte 42/43 */ + + u_short not_used[30] ; /* byte 44-103 */ + + u_short ucode_version_level ; /* byte 104/105 */ + + u_short not_used_1 ; /* byte 106/107 */ + u_short not_used_2 ; /* byte 108/109 */ +} ; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/mbuf.h linux/drivers/net/skfp/h/mbuf.h --- v2.2.17/drivers/net/skfp/h/mbuf.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/mbuf.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _MBUF_ +#define _MBUF_ + +#ifndef PCI +#define M_SIZE 4550 +#else +#define M_SIZE 4504 +#endif + +#ifndef MAX_MBUF +#define MAX_MBUF 4 +#endif + +#ifndef NO_STD_MBUF +#define sm_next m_next +#define sm_off m_off +#define sm_len m_len +#define sm_data m_data +#define SMbuf Mbuf +#define mtod smtod +#define mtodoff smtodoff +#endif + +struct s_mbuf { + struct s_mbuf *sm_next ; /* low level linked list */ + short sm_off ; /* offset in m_data */ + u_int sm_len ; /* len of data */ +#ifdef PCI + int sm_use_count ; +#endif + char sm_data[M_SIZE] ; +} ; + +typedef struct s_mbuf SMbuf ; + +/* mbuf head, to typed data */ +#define smtod(x,t) ((t)((x)->sm_data + (x)->sm_off)) +#define smtodoff(x,t,o) ((t)((x)->sm_data + (o))) + +#endif /* _MBUF_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/osdef1st.h linux/drivers/net/skfp/h/osdef1st.h --- v2.2.17/drivers/net/skfp/h/osdef1st.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/osdef1st.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,121 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * Operating system-dependant definitions that have to be defined + * before any other header files are included. + */ + +// HWM (HardWare Module) Definitions +// ----------------------- + +#ifdef __LITTLE_ENDIAN +#define LITTLE_ENDIAN +#else +#define BIG_ENDIAN +#endif + +// this is set in the makefile +// #define PCI /* only PCI adapters supported by this driver */ +// #define MEM_MAPPED_IO /* use memory mapped I/O */ + + +#define USE_CAN_ADDR /* DA and SA in MAC header are canonical. */ + +#define MB_OUTSIDE_SMC /* SMT Mbufs outside of smc struct. */ + +// ----------------------- + + +// SMT Definitions +// ----------------------- +#define SYNC /* allow synchronous frames */ + +// #define SBA /* Synchronous Bandwidth Allocator support */ + /* not available as free source */ + +#define ESS /* SBA End Station Support */ + +#define SMT_PANIC(smc, nr, msg) printk(KERN_INFO "SMT PANIC: code: %d, msg: %s\n",nr,msg) + + +#ifdef DEBUG +#define printf(s,args...) printk(KERN_INFO s, ## args) +#endif + +// #define HW_PTR u_long +// ----------------------- + + + +// HWM and OS-specific buffer definitions +// ----------------------- + +// default number of receive buffers. +#define NUM_RECEIVE_BUFFERS 10 + +// default number of transmit buffers. +#define NUM_TRANSMIT_BUFFERS 10 + +// Number of SMT buffers (Mbufs). +#define NUM_SMT_BUF 4 + +// Number of TXDs for asynchronous transmit queue. +#define HWM_ASYNC_TXD_COUNT (NUM_TRANSMIT_BUFFERS + NUM_SMT_BUF) + +// Number of TXDs for synchronous transmit queue. +#define HWM_SYNC_TXD_COUNT HWM_ASYNC_TXD_COUNT + + +// Number of RXDs for receive queue #1. +// Note: Workaround for ASIC Errata #7: One extra RXD is required. +#if (NUM_RECEIVE_BUFFERS > 100) +#define SMT_R1_RXD_COUNT (1 + 100) +#else +#define SMT_R1_RXD_COUNT (1 + NUM_RECEIVE_BUFFERS) +#endif + +// Number of RXDs for receive queue #2. +#define SMT_R2_RXD_COUNT 0 // Not used. +// ----------------------- + + + +/* + * OS-specific part of the transmit/receive descriptor structure (TXD/RXD). + * + * Note: The size of these structures must follow this rule: + * + * sizeof(struct) + 2*sizeof(void*) == n * 16, n >= 1 + * + */ + +struct s_txd_os { // os-specific part of transmit descriptor + struct sk_buff *skb; + long padding; +} ; + +struct s_rxd_os { // os-specific part of receive descriptor + struct sk_buff *skb; + long padding; +} ; + + +/* + * So we do not need to make too many modifications to the generic driver + * parts, we take advantage of the AIX byte swapping macro interface. + */ + +#define AIX_REVERSE(x) ((u32)le32_to_cpu((u32)(x))) +#define MDR_REVERSE(x) ((u32)le32_to_cpu((u32)(x))) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/sba.h linux/drivers/net/skfp/h/sba.h --- v2.2.17/drivers/net/skfp/h/sba.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/sba.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,142 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * Synchronous Bandwith Allocation (SBA) structs + */ + +#ifndef _SBA_ +#define _SBA_ + +#include "h/mbuf.h" +#include "h/sba_def.h" + +#ifdef SBA + +/* Timer Cell Template */ +struct timer_cell { + struct timer_cell *next_ptr ; + struct timer_cell *prev_ptr ; + u_long start_time ; + struct s_sba_node_vars *node_var ; +} ; + +/* + * Node variables + */ +struct s_sba_node_vars { + u_char change_resp_flag ; + u_char report_resp_flag ; + u_char change_req_flag ; + u_char report_req_flag ; + long change_amount ; + long node_overhead ; + long node_payload ; + u_long node_status ; + u_char deallocate_status ; + u_char timer_state ; + u_short report_cnt ; + long lastrep_req_tranid ; + struct fddi_addr mac_address ; + struct s_sba_sessions *node_sessions ; + struct timer_cell timer ; +} ; + +/* + * Session variables + */ +struct s_sba_sessions { + u_long deallocate_status ; + long session_overhead ; + u_long min_segment_size ; + long session_payload ; + u_long session_status ; + u_long sba_category ; + long lastchg_req_tranid ; + u_short session_id ; + u_char class ; + u_char fddi2 ; + u_long max_t_neg ; + struct s_sba_sessions *next_session ; +} ; + +struct s_sba { + + struct s_sba_node_vars node[MAX_NODES] ; + struct s_sba_sessions session[MAX_SESSIONS] ; + + struct s_sba_sessions *free_session ; /* points to the first */ + /* free session */ + + struct timer_cell *tail_timer ; /* points to the last timer cell */ + + /* + * variables for allocation actions + */ + long total_payload ; /* Total Payload */ + long total_overhead ; /* Total Overhead */ + long sba_allocatable ; /* allocatable sync bandwidth */ + + /* + * RAF message receive parameters + */ + long msg_path_index ; /* Path Type */ + long msg_sba_pl_req ; /* Payload Request */ + long msg_sba_ov_req ; /* Overhead Request */ + long msg_mib_pl ; /* Current Payload for this Path */ + long msg_mib_ov ; /* Current Overhead for this Path*/ + long msg_category ; /* Category of the Allocation */ + u_long msg_max_t_neg ; /* longest T_Neg acceptable */ + u_long msg_min_seg_siz ; /* minimum segement size */ + struct smt_header *sm ; /* points to the rec message */ + struct fddi_addr *msg_alloc_addr ; /* Allocation Address */ + + /* + * SBA variables + */ + u_long sba_t_neg ; /* holds the last T_NEG */ + long sba_max_alloc ; /* the parsed value of SBAAvailable */ + + /* + * SBA state machine variables + */ + short sba_next_state ; /* the next state of the SBA */ + char sba_command ; /* holds the execuded SBA cmd */ + u_char sba_available ; /* parsed value after possible check */ +} ; + +#endif /* SBA */ + + /* + * variables for the End Station Support + */ +struct s_ess { + + /* + * flags and counters + */ + u_char sync_bw_available ; /* is set if sync bw is allocated */ + u_char local_sba_active ; /* set when a local sba is available */ + char raf_act_timer_poll ; /* activate the timer to send allc req */ + char timer_count ; /* counts every timer function call */ + + SMbuf *sba_reply_pend ; /* local reply for the sba is pending */ + + /* + * variables for the ess bandwidth control + */ + long sync_bw ; /* holds the allocaed sync bw */ + u_long alloc_trans_id ; /* trans id of the last alloc req */ +} ; +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/sba_def.h linux/drivers/net/skfp/h/sba_def.h --- v2.2.17/drivers/net/skfp/h/sba_def.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/sba_def.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#define PHYS 0 /* physical addr */ +#define PERM_ADDR 0x80 /* permanet address */ +#define SB_STATIC 0x00000001 +#define MAX_PAYLOAD 1562 +#define PRIMARY_RING 0x00000001 +#ifndef NULL +#define NULL 0x00 +#endif + +/*********************** SB_Input Variable Values ***********************/ +/* may be needed when ever the SBA state machine is called */ + +#define UNKNOWN_SYNC_SOURCE 0x0001 +#define REQ_ALLOCATION 0x0002 +#define REPORT_RESP 0x0003 +#define CHANGE_RESP 0x0004 +#define TNEG 0x0005 +#define NIF 0x0006 +#define SB_STOP 0x0007 +#define SB_START 0x0008 +#define REPORT_TIMER 0x0009 +#define CHANGE_REQUIRED 0x000A + +#define DEFAULT_OV 50 + +#ifdef SBA +/**************************** SBA STATES *****************************/ + +#define SBA_STANDBY 0x00000000 +#define SBA_ACTIVE 0x00000001 +#define SBA_RECOVERY 0x00000002 +#define SBA_REPORT 0x00000003 +#define SBA_CHANGE 0x00000004 + +/**************************** OTHERS *********************************/ + +#define FIFTY_PERCENT 50 /* bytes per second */ +#define MAX_SESSIONS 150 +#define TWO_MINUTES 13079 /* 9.175 ms/tick */ +#define FIFTY_BYTES 50 +#define SBA_DENIED 0x0000000D +#define I_NEED_ONE 0x00000000 +#define MAX_NODES 50 +/*#define T_REPORT 0x59682F00L*/ /* 120s/80ns in Hex */ +#define TWO_MIN 120 /* seconds */ +#define SBA_ST_UNKNOWN 0x00000002 +#define SBA_ST_ACTIVE 0x00000001 +#define S_CLEAR 0x00000000L +#define ZERO 0x00000000 +#define FULL 0x00000000 /* old: 0xFFFFFFFFF */ +#define S_SET 0x00000001L +#define LOW_PRIO 0x02 /* ??????? */ +#define OK 0x01 /* ??????? */ +#define NOT_OK 0x00 /* ??????? */ + +/****************************************/ +/* deallocate_status[ni][si] values */ +/****************************************/ +#define TX_CHANGE 0X00000001L +#define PENDING 0x00000002L +#define NONE 0X00000000L +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/skfbi.h linux/drivers/net/skfp/h/skfbi.h --- v2.2.17/drivers/net/skfp/h/skfbi.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/skfbi.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,1920 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _SKFBI_H_ +#define _SKFBI_H_ + +#ifdef SYNC +#define exist_board_far exist_board +#define get_board_para_far get_board_para +#endif + +/* + * physical address offset + IO-Port base address + */ +#ifndef PCI +#define ADDR(a) ((a)+smc->hw.iop) +#define ADDRS(smc,a) ((a)+(smc)->hw.iop) +#endif + +/* + * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)}) + * address calculation & function defines + */ + +#ifdef EISA + +/* + * Configuration PROM: !! all 8-Bit IO's !! + * |<- MAC-Address ->| + * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ + * val: |PROD_ID0..3| | free | |00|00|5A|40| |nn|mm|00|00| + * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ + * IO- ^ ^ ^ ^ ^ + * port 0C80 0C83 0C88 0C90 0C98 + * | \ + * | \ + * | \______________________________________________ + * EISA Expansion Board Product ID: \ + * BIT: |7 6 5 4 3 2 1 0| \ + * | PROD_ID0 | PROD_ID1 | PROD_ID2 | PROD_ID3 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0| MAN_C0 | MAN_C1 | MAN_C2 | PROD1 | PROD0 | REV1 | REV0 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ^=reserved | product numb. | revision numb | + * MAN_Cx = compressed manufacterer code (x:=0..2) + * ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!) + */ + +#ifndef MULT_OEM +#ifndef OEM_CONCEPT +#define MAN_C0 ('S'-0x40) +#define MAN_C1 ('K'-0x40) +#define MAN_C2 ('D'-0x40) +#define PROD_ID0 (u_char)((MAN_C0<<2) | (MAN_C1>>3)) +#define PROD_ID1 (u_char)(((MAN_C1<<5) & 0xff) | MAN_C2) +#define PROD_ID2 (u_char)(1) /* prod. nr. */ +#define PROD_ID3 (u_char)(0) /* rev. nr. */ + +#ifndef OEM_USER_DATA +#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" +#endif +#else /* OEM_CONCEPT */ + +/* MAN_C(0|1|2) no longer present (ra). */ +#define PROD_ID0 (u_char)OEM_PROD_ID0 +#define PROD_ID1 (u_char)OEM_PROD_ID1 +#define PROD_ID2 (u_char)OEM_PROD_ID2 +#define PROD_ID3 (u_char)OEM_PROD_ID3 +#endif /* OEM_CONCEPT */ + +#define SKLOGO PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3 +#endif /* MULT_OEM */ + +#define SADDRL (0) /* start address SKLOGO */ +#define SA_MAC (0x10) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (4) +#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ + +#define SKFDDI_PSZ 32 /* address PROM size */ + +/* + * address transmision from logical to physical offset address on board + */ +#define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */ +#define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */ +#define P2A(a) (0x0840|((a)<<1)) /* PLC2 (r/w) */ +#define TIA(a) (0x0880|((a)<<1)) /* Timer (r/w) */ +#define PRA(a) (0x0c80| (a)) /* configuration PROM */ +#define C0A(a) (0x0c84| (a)) /* config. RAM */ +#define C1A(a) (0x0ca0| (a)) /* IRQ-, DMA-nr., EPROM type */ +#define C2A(a) (0x0ca4| (a)) /* EPROM and PAGE selector */ + +#define CONF C0A(0) /* config RAM (card enable bit port) */ +#define PGRA C2A(0) /* Flash page register */ +#define CDID PRA(0) /* Card ID I/O port addr. offset */ + + +/* + * physical address offset + slot specific IO-Port base address + */ +#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ +#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ +#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ +#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ +#define PR_A(a) (PRA(a)+smc->hw.iop) /* config. PROM */ +#define C0_A(a) (C0A(a)+smc->hw.iop) /* config. RAM */ +#define C1_A(a) (C1A(a)+smc->hw.iop) /* config. RAM */ +#define C2_A(a) (C2A(a)+smc->hw.iop) /* config. RAM */ + + +#define CSRA 0x0008 /* control/status register address (r/w) */ +#define ISRA 0x0008 /* int. source register address (upper 8Bits) */ +#define PLC1I 0x001a /* clear PLC1 interrupt (write only) */ +#define PLC2I 0x0020 /* clear PLC2 interrupt (write only) */ +#define CSFA 0x001c /* control/status FIFO BUSY flags (read only) */ +#define RQAA 0x001c /* Request reg. (write only) */ +#define WCTA 0x001e /* word counter (r/w) */ +#define FFLAG 0x005e /* FLAG/V_FULL (FIFO almost full, write only)*/ + +#define CSR_A (CSRA+smc->hw.iop) /* control/status register address (r/w) */ +#ifdef UNIX +#define CSR_AS(smc) (CSRA+(smc)->hw.iop) /* control/status register address (r/w) */ +#endif +#define ISR_A (ISRA+smc->hw.iop) /* int. source register address (upper 8Bits) */ +#define PLC1_I (PLC1I+smc->hw.iop) /* clear PLC1 internupt (write only) */ +#define PLC2_I (PLC2I+smc->hw.iop) /* clear PLC2 interrupt (write only) */ +#define CSF_A (CSFA+smc->hw.iop) /* control/status FIFO BUSY flags (r/w) */ +#define RQA_A (RQAA+smc->hw.iop) /* Request reg. (write only) */ +#define WCT_A (WCTA+smc->hw.iop) /* word counter (r/w) */ +#define FFLAG_A (FFLAG+smc->hw.iop) /* FLAG/V_FULL (FIFO almost full, write only)*/ + +/* + * control/status register CSRA bits + */ +/* write */ +#define CS_CRESET 0x01 /* Card reset (0=reset) */ +#define CS_RESET_FIFO 0x02 /* FIFO reset (0=reset) */ +#define CS_IMSK 0x04 /* enable IRQ (1=enable, 0=disable) */ +#define CS_EN_IRQ_TC 0x08 /* enable IRQ from transfer counter */ +#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ +#define CS_LED_0 0x40 /* switch LED 0 */ +#define CS_LED_1 0x80 /* switch LED 1 */ +/* read */ +#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ +#define CS_SAS 0x80 /* single attachement station (=1) */ + +/* + * control/status register CSFA bits (FIFO) + */ +#define CSF_MUX0 0x01 +#define CSF_MUX1 0x02 +#define CSF_HSREQ0 0x04 +#define CSF_HSREQ1 0x08 +#define CSF_HSREQ2 0x10 +#define CSF_BUSY_DMA 0x40 +#define CSF_BUSY_FIFO 0x80 + +/* + * Interrupt source register ISRA (upper 8 data bits) read only & low activ. + */ +#define IS_MINTR1 0x0100 /* FORMAC ST1U/L & ~IMSK1U/L*/ +#define IS_MINTR2 0x0200 /* FORMAC ST2U/L & ~IMSK2U/L*/ +#define IS_PLINT1 0x0400 /* PLC1 */ +#define IS_PLINT2 0x0800 /* PLC2 */ +#define IS_TIMINT 0x1000 /* Timer 82C54-2 */ +#define IS_TC 0x2000 /* transf. counter */ + +#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC) + +/* + * CONFIG<0> RAM (C0_A()) + */ +#define CFG_CARD_EN 0x01 /* card enable */ + +/* + * CONFIG<1> RAM (C1_A()) + */ +#define CFG_IRQ_SEL 0x03 /* IRQ select (4 nr.) */ +#define CFG_IRQ_TT 0x04 /* IRQ trigger type (LEVEL/EDGE) */ +#define CFG_DRQ_SEL 0x18 /* DMA requ. (4 nr.) */ +#define CFG_BOOT_EN 0x20 /* 0=BOOT-, 1=Application Software */ +#define CFG_PROG_EN 0x40 /* V_Prog for FLASH_PROM (1=on) */ + +/* + * CONFIG<2> RAM (C2_A()) + */ +#define CFG_EPROM_SEL 0x0f /* FPROM start address selection */ +#define CFG_PAGE 0xf0 /* FPROM page selection */ + + +#define READ_PROM(a) ((u_char)inp(a)) +#define GET_PAGE(i) outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE)) +#define FPROM_SW() (inp(C1_A(0)) & CFG_BOOT_EN) + +#define MAX_PAGES 16 /* 16 pages */ +#define MAX_FADDR 0x2000 /* 8K per page */ +#define VPP_ON() outp(C1_A(0),inp(C1_A(0)) | CFG_PROG_EN) +#define VPP_OFF() outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN) + +#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) +#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) +#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) +#define BUS_CHECK() + +#ifdef UNISYS +/* For UNISYS use another macro with drv_usecewait function */ +#define CHECK_DMA() {u_long k = 1000000; \ + while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } +#else +#define CHECK_DMA() {u_long k = 1000000 ;\ + while (k && (DMA_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } +#endif + +#define CHECK_FIFO() {u_long k = 1000000 ;\ + while (k && (FIFO_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } + +#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ + while (k && (DMA_FIFO_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } + +#define GET_ISR() ~inpw(ISR_A) +#define CHECK_ISR() ~inpw(ISR_A) + +#ifndef UNIX +#ifndef WINNT +#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ + (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) +#else /* WINNT */ +#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A)&\ + (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) +#endif /* WINNT */ +#else /* UNIX */ +#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ + (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led) +#endif + +#ifndef UNIX +#define STI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ + (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led) +#else +#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ + (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led) +#endif + +/* EISA DMA Controller */ +#define DMA_WRITE_SINGLE_MASK_BIT_M 0x0a /* Master DMA Controller */ +#define DMA_WRITE_SINGLE_MASK_BIT_S 0xd4 /* Slave DMA Controller */ +#define DMA_CLEAR_BYTE_POINTER_M 0x0c +#define DMA_CLEAR_BYTE_POINTER_S 0xd8 + +#endif /* EISA */ + +#ifdef MCA + +/* + * POS Register: !! all I/O's are 8-Bit !! + */ +#define POS_SYS_SETUP 0x94 /* system setup register */ +#define POS_SYSTEM 0xff /* system mode */ + +#define POS_CHANNEL_POS 0x96 /* register slot ID */ +#define POS_CHANNEL_BIT 0x08 /* mask for -"- */ + +#define POS_BASE 0x100 /* POS base address */ +#define POS_ID_LOW POS_BASE /* card ID low */ +#define POS_ID_HIGH (POS_BASE+1) /* card ID high */ +#define POS_102 (POS_BASE+2) /* card en., arbitration level .. */ +#define POS_103 (POS_BASE+3) /* FPROM addr, page */ +#define POS_104 (POS_BASE+4) /* I/O, IRQ */ +#define POS_105 (POS_BASE+5) /* POS_CHCK */ +#define POS_106 (POS_BASE+6) /* to read VPD */ +#define POS_107 (POS_BASE+7) /* added without function */ + +/* FM1 card IDs */ +#define FM1_CARD_ID0 0x83 +#define FM1_CARD_ID1 0 + +#define FM1_IBM_ID0 0x9c +#define FM1_IBM_ID1 0x8f + + +/* FM2 card IDs */ +#define FM2_CARD_ID0 0xab +#define FM2_CARD_ID1 0 + +#define FM2_IBM_ID0 0x7e +#define FM2_IBM_ID1 0x8f + +/* Board revision. */ +#define FM1_REV 0 +#define FM2_REV 1 + +#define MAX_SLOT 8 + +/* + * POS_102 + */ +#define POS_CARD_EN 0x01 /* card enable =1 */ +#define POS_SDAT_EN 0x02 /* enable 32-bit streaming data mode */ +#define POS_EN_CHKINT 0x04 /* enable int. from check line asserted */ +#define POS_EN_BUS_ERR 0x08 /* enable int. on invalid busmaster transf. */ +#define POS_FAIRNESS 0x10 /* fairnes on =1 */ +/* attention: arbitration level used with bit 0 POS 105 */ +#define POS_LARBIT 0xe0 /* arbitration level (0,0,0)->level = 0x8 + (1,1,1)->level = 0xf */ +/* + * POS_103 + */ +#define POS_PAGE 0x07 /* FPROM page selection */ +#define POS_BOOT_EN 0x08 /* boot PROM enable =1 */ +#define POS_MSEL 0x70 /* memory start address for FPROM mapping */ +#define PROG_EN 0x80 /* FM1: Vpp prog on/off */ +#define POS_SDR 0x80 /* FM2: Streaming data bit */ + +/* + * POS_104 + */ +#define POS_IOSEL 0x3f /* selected I/O base address */ +#define POS_IRQSEL 0xc0 /* selected interrupt */ + +/* + * POS_105 + */ +#define POS_CHCK 0x80 +#define POS_SYNC_ERR 0x20 /* FM2: synchronous error reporting */ +#define POS_PAR_DATA 0x10 /* FM2: data parity enable bit */ +#define POS_PAR_ADDR 0x08 /* FM2: address parity enable bit */ +#define POS_IRQHSEL 0x02 /* FM2: Highest bit for IRQ_selection */ +#define POS_HARBIT 0x01 /* Highest bit in Bus arbitration selection */ + +#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (0) +#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ + +/* + * address transmision from logical to physical offset address on board + */ +#define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */ +#define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */ +#define P1(a) (0x0080|((a)<<1)) /* PLC1 (r/w) */ +#define TI(a) (0x0060|((a)<<1)) /* Timer (r/w) */ +#define PR(a) (0x0040|((a)<<1)) /* configuration PROM */ +#define CS(a) (0x0020| (a)) /* control/status */ +#define FF(a) (0x0010|((a)<<1)) /* FIFO ASIC */ +#define CT(a) (0x0000|((a)<<1)) /* counter */ + +/* + * counter + */ +#define ACLA CT(0) /* address counter low */ +#define ACHA CT(1) /* address counter high */ +#define BCN CT(2) /* byte counter */ +#define MUX CT(3) /* MUX-register */ +#define WCN CT(0x08) /* word counter */ +#define FFLG CT(0x09) /* FIFO Flags */ + +/* + * test/control register (FM2 only) + */ +#define CNT_TST 0x018 /* Counter test control register */ +#define CNT_STP 0x01a /* Counter test step reg. (8 Bit) */ + +/* + * CS register (read only) + */ +#define CSRA CS(0) /* control/status register address */ +#define CSFA CS(2) /* control/status FIFO BUSY ... */ +#define ISRA CS(4) /* first int. source register address */ +#define ISR2 CS(6) /* second int. source register address */ +#define LEDR CS(0x0c) /* LED register r/w */ +#define CSIL CS(0x10) /* I/O mapped POS_ID_low (100) */ +#define CSIH CS(0x12) /* - " - POS_ID_HIGH (101) */ +#define CSA CS(0x14) /* - " - POS_102 */ +#define CSM CS(0x0e) /* - " - POS_103 */ +#define CSM_FM1 CS(0x16) /* - " - POS_103 (copy in FM1) */ +#define CSI CS(0x18) /* - " - POS_104 */ +#define CSS CS(0x1a) /* - " - POS_105 */ +#define CSP_06 CS(0x1c) /* - " - POS_106 */ +#define WDOG_ST 0x1c /* Watchdog status (FM2 only) */ +#define WDOG_EN 0x1c /* Watchdog enabling (FM2 only, 8Bit) */ +#define WDOG_DIS 0x1e /* Watchdog disabling (FM2 only, 8Bit) */ + +#define PGRA CSM /* Flash page register */ + + +#define WCTA FF(0) /* word counter */ +#define FFLAG FF(1) /* FLAG/V_FULL (FIFO almost full, write only)*/ + +/* + * Timer register (FM2 only) + */ +#define RTM_CNT 0x28 /* RTM Counter */ +#define TI_DIV 0x60 /* Timer Prescaler */ +#define TI_CH1 0x62 /* Timer channel 1 counter */ +#define TI_STOP 0x64 /* Stop timer on channel 1 */ +#define TI_STRT 0x66 /* Start timer on channel 1 */ +#define TI_INI2 0x68 /* Timer: Bus master preemption */ +#define TI_CNT2 0x6a /* Timer */ +#define TI_INI3 0x6c /* Timer: Streaming data */ +#define TI_CNT3 0x6e /* Timer */ +#define WDOG_LO 0x70 /* Watchdog counter low */ +#define WDOG_HI 0x72 /* Watchdog counter high */ +#define RTM_PRE 0x74 /* restr. token prescaler */ +#define RTM_TIM 0x76 /* restr. token timer */ + +/* + * Recommended Timeout values (for FM2 timer only) + */ +#define TOUT_BM_PRE 188 /* 3.76 usec */ +#define TOUT_S_DAT 374 /* 7.48 usec */ + +/* + * CS register (write only) + */ +#define HSR(p) CS(0x18|(p)) /* Host request register */ + +#define RTM_PUT 0x36 /* restr. token counter write */ +#define RTM_GET 0x28 /* - " - clear */ +#define RTM_CLEAR 0x34 /* - " - read */ + +/* + * BCN Bit definitions + */ +#define BCN_BUSY 0x8000 /* DMA Busy flag */ +#define BCN_AZERO 0x4000 /* Almost zero flag (BCN < 4) */ +#define BCN_STREAM 0x2000 /* Allow streaming data (BCN >= 8) */ + +/* + * WCN Bit definitions + */ +#define WCN_ZERO 0x2000 /* Zero flag (counted to zero) */ +#define WCN_AZERO 0x1000 /* Almost zero flag (BCN < 4) */ + +/* + * CNT_TST Bit definitions + */ +#define CNT_MODE 0x01 /* Go into test mode */ +#define CNT_D32 0x02 /* 16/32 BIT test mode */ + +/* + * FIFO Flag FIFO Flags/Vfull register + */ +#define FF_VFULL 0x003f /* V_full value mask */ +#define FFLG_FULL 0x2000 /* FULL flag */ +#define FFLG_A_FULL 0x1000 /* Almost full flag */ +#define FFLG_VFULL 0x0800 /* V_full Flag */ +#define FFLG_A_EMP 0x0400 /* almost empty flag */ +#define FFLG_EMP 0x0200 /* empty flag */ +#define FFLG_T_EMP 0x0100 /* totally empty flag */ + +/* + * WDOG Watchdog status register + */ +#define WDOG_ALM 0x01 /* Watchdog alarm Bit */ +#define WDOG_ACT 0x02 /* Watchdog active Bit */ + +/* + * CS(0) CONTROLS + */ +#define CS_CRESET 0x0001 +#define FIFO_RST 0x0002 +#define CS_IMSK 0x0004 +#define EN_IRQ_CHCK 0x0008 +#define EN_IRQ_TOKEN 0x0010 +#define EN_IRQ_TC 0x0020 +#define TOKEN_STATUS 0x0040 +#define RTM_CHANGE 0x0080 + +#define CS_SAS 0x0100 +#define CS_BYSTAT 0x0200 /* bypass connected (0=conn.) */ +#define CS_BYPASS 0x0400 /* bypass on/off indication */ + +/* + * CS(2) FIFOSTAT + */ +#define HSREQ 0x0007 +#define BIGDIR 0x0008 +#define CSF_BUSY_FIFO 0x0010 +#define CSF_BUSY_DMA 0x0020 +#define SLOT_32 0x0040 + +#define LED_0 0x0001 +#define LED_1 0x0002 +#define LED_2 0x0100 + +#define MAX_PAGES 8 /* pages */ +#define MAX_FADDR 0x4000 /* 16K per page */ + +/* + * IRQ = ISRA || ISR2 ; + * + * ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ; + * ISR2 = IRQ_TC_EN && IS_TC ; + * + * IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) || + * (IRQ_EN_TOKEN && IS_TOKEN) ; + * IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ; + */ +/* + * ISRA !!! activ high !!! + */ +#define IS_MINTR1 0x0001 /* FORMAC ST1U/L & ~IMSK1U/L*/ +#define IS_MINTR2 0x0002 /* FORMAC ST2U/L & ~IMSK2U/L*/ +#define IS_PLINT1 0x0004 /* PLC1 */ +#define IS_PLINT2 0x0008 /* PLC2 */ +#define IS_TIMINT 0x0010 /* Timer 82C54-2 */ +#define IS_TOKEN 0x0020 /* restrictet token monitoring */ +#define IS_CHCK_L 0x0040 /* check line asserted */ +#define IS_BUSERR 0x0080 /* bus error */ +/* + * ISR2 + */ +#define IS_TC 0x0001 /* terminal count irq */ +#define IS_SFDBKRTN 0x0002 /* selected feedback return */ +#define IS_D16 0x0004 /* DS16 */ +#define IS_D32 0x0008 /* DS32 */ +#define IS_DPEI 0x0010 /* Data Parity Indication */ + +#define ALL_IRSR 0x00ff + +#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */ +#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */ +#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */ +#define TI_A(a) ADDR(TI(a)) /* Timer (r/w) FM1 only! */ +#define PR_A(a) ADDR(PR(a)) /* config. PROM */ +#define CS_A(a) ADDR(CS(a)) /* control/status */ + +#define ISR1_A ADDR(ISRA) /* first int. source register address */ +#define ISR2_A ADDR(ISR2) /* second -"- */ +#define CSR_A ADDR(CSRA) /* control/status register address */ +#define CSF_A ADDR(CSFA) /* control/status FIFO BUSY flags (r/w) */ + +#define CSIL_A ADDR(CSIL) /* I/O mapped POS_ID_low (102) */ +#define CSIH_A ADDR(CSIH) /* - " - POS_ID_HIGH (101) */ +#define CSA_A ADDR(CSA) /* - " - POS_102 */ +#define CSI_A ADDR(CSI) /* - " - POS_104 */ +#define CSM_A ADDR(CSM) /* - " - POS_103 */ +#define CSM_FM1_A ADDR(CSM_FM1) /* - " - POS_103 (2nd copy, FM1) */ +#define CSP_06_A ADDR(CSP_06) /* - " - POS_106 */ + +#define WCT_A ADDR(WCTA) /* word counter (r/w) */ +#define FFLAG_A ADDR(FFLAG) /* FLAG/V_FULL (FIFO almost full, write only)*/ + +#define ACL_A ADDR(ACLA) /* address counter low */ +#define ACH_A ADDR(ACHA) /* address counter high */ +#define BCN_A ADDR(BCN) /* byte counter */ +#define MUX_A ADDR(MUX) /* MUX-register */ + +#define ISR_A ADDR(ISRA) /* Interrupt Source Register */ +#define FIFO_RESET_A ADDR(FIFO_RESET) /* reset the FIFO */ +#define FIFO_EN_A ADDR(FIFO_EN) /* enable the FIFO */ + +#define WDOG_EN_A ADDR(WDOG_EN) /* reset and start the WDOG */ +#define WDOG_DIS_A ADDR(WDOG_DIS) /* disable the WDOG */ +/* + * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A) + */ +#define HSR_A(p) ADDR(HSR(p)) /* Host request register */ + +#define STAT_BYP 0 /* bypass station */ +#define STAT_INS 2 /* insert station */ +#define BYPASS(o) CS(0x10|(o)) /* o=STAT_BYP || STAT_INS */ + +#define IRQ_TC_EN CS(0x0b) /* enable/disable IRQ on TC */ +#define IRQ_TC_DIS CS(0x0a) +#define IRQ_TOKEN_EN CS(9) /* enable/disable IRQ on restr. Token */ +#define IRQ_TOKEN_DIS CS(8) +#define IRQ_CHCK_EN CS(7) /* -"- IRQ after CHCK line */ +#define IRQ_CHCK_DIS CS(6) +#define IRQ_OTH_EN CS(5) /* -"- other IRQ's */ +#define IRQ_OTH_DIS CS(4) +#define FIFO_EN CS(3) /* disable (reset), enable FIFO */ +#define FIFO_RESET CS(2) +#define CARD_EN CS(1) /* disable (reset), enable card */ +#define CARD_DIS CS(0) + +#define LEDR_A ADDR(LEDR) /* D0=green, D1=yellow, D8=L2 */ +#define PAGE_RG_A ADDR(CSM) /* D<2..0> */ +#define IRQ_CHCK_EN_A ADDR(IRQ_CHCK_EN) +#define IRQ_CHCK_DIS_A ADDR(IRQ_CHCK_DIS) + +#define GET_PAGE(bank) outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\ + (~POS_PAGE)) |(int) (bank)) +#define VPP_ON() if (smc->hw.rev == FM1_REV) { \ + outpw(PAGE_RG_A, \ + (inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \ + } +#define VPP_OFF() if (smc->hw.rev == FM1_REV) { \ + outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \ + } + +#define SKFDDI_PSZ 16 /* address PROM size */ + +#define READ_PROM(a) ((u_char)inp(a)) + +#define GET_ISR() ~inpw(ISR1_A) +#ifndef TCI +#define CHECK_ISR() ~inpw(ISR1_A) +#define CHECK_ISR_SMP(iop) ~inpw((iop)+ISRA) +#else +#define CHECK_ISR() (~inpw(ISR1_A) | ~inpw(ISR2_A)) +#define CHECK_ISR_SMP(iop) (~inpw((iop)+ISRA) | ~inpw((iop)+ISR2)) +#endif + +#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) +#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) +#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) +#define BUS_CHECK() { int i ; \ + if ((i = GET_ISR()) & IS_BUSERR) \ + SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \ + if (i & IS_CHCK_L) \ + SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \ + } + +#define CHECK_DMA() { u_long k = 10000 ; \ + while (k && (DMA_BUSY())) { \ + k-- ; \ + BUS_CHECK() ; \ + } \ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } + +#define CHECK_FIFO() {u_long k = 1000000 ;\ + while (k && (FIFO_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } + +#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ + while (k && (DMA_FIFO_BUSY())) { \ + k-- ;\ + BUS_CHECK() ; \ + } \ + if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } + +#ifndef UNIX +#define CLI_FBI() outp(ADDR(IRQ_OTH_DIS),0) +#else +#define CLI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_DIS),0) +#endif + +#ifndef TCI +#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) +#else +#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) ;\ + outp((iop)+IRQ_TC_DIS,0) +#endif + +#ifndef UNIX +#define STI_FBI() outp(ADDR(IRQ_OTH_EN),0) +#else +#define STI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_EN),0) +#endif + +/* + * Terminal count primitives + */ +#define CLI_TCI(smc) outp(ADDRS((smc),IRQ_TC_DIS),0) +#define STI_TCI(smc) outp(ADDRS((smc),IRQ_TC_EN),0) +#define CHECK_TC(smc,k) {(k) = 10000 ;\ + while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; } + +#endif /* MCA */ + +#ifdef ISA + +/* + * address transmision from logic NPADDR6-0 to physical offset address on board + */ +#define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */ +#define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/ +#define P1A(a) (0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC1 (r/w) */ +#define P2A(a) (0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC2 (r/w) */ +#define TIA(a) (0x6000|(((a)&0x03)<<1)) /* Timer (r/w) */ + +#define ISRA 0x0000 /* int. source register address (read only) */ +#define ACLA 0x0000 /* address counter low address (write only) */ +#define ACHA 0x0002 /* address counter high address (write only) */ +#define TRCA 0x0004 /* transfer counter address (write only) */ +#define PGRA 0x0006 /* page register address (write only) */ +#define RQAA 0x2000 /* Request reg. (write only) */ +#define CSRA 0x3000 /* control/status register address (r/w) */ + +/* + * physical address offset + IO-Port base address + */ +#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ +#define PR_A(a) (PRA(a)+smc->hw.iop) /* PROM (read only)*/ +#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ +#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ +#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ + +#define ISR_A (0x0000+smc->hw.iop) /* int. source register address (read only) */ +#define ACL_A (0x0000+smc->hw.iop) /* address counter low address (write only) */ +#define ACH_A (0x0002+smc->hw.iop) /* address counter high address (write only)*/ +#define TRC_A (0x0004+smc->hw.iop) /* transfer counter address (write only) */ +#define PGR_A (0x0006+smc->hw.iop) /* page register address (write only) */ +#define RQA_A (0x2000+smc->hw.iop) /* Request reg. (write only) */ +#define CSR_A (0x3000+smc->hw.iop) /* control/status register address (r/w) */ +#ifdef UNIX +#define CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */ +#endif +#define PLC1_I (0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */ +#define PLC2_I (0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */ + +#ifndef MULT_OEM +#ifndef OEM_CONCEPT +#define SKLOGO_STR "SKFDDI" +#else /* OEM_CONCEPT */ +#define SKLOGO_STR OEM_FDDI_LOGO +#endif /* OEM_CONCEPT */ +#endif /* MULT_OEM */ +#define SADDRL (24) /* start address SKLOGO */ +#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (0) +#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ + +#define CDID (PRA(SADDRL)) /* Card ID int/O port addr. offset */ +#define NEXT_CDID ((PRA(SADDRL+1)) - CDID) + +#define SKFDDI_PSZ 32 /* address PROM size */ + +#define READ_PROM(a) ((u_char)inpw(a)) +#define GET_PAGE(i) outpw(PGR_A,(int)(i)) + +#define MAX_PAGES 16 /* 16 pages */ +#define MAX_FADDR 0x2000 /* 8K per page */ +#define VPP_OFF() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS))) +#define VPP_ON() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \ + CS_VPPSW) + +/* + * control/status register CSRA bits (log. addr: 0x3000) + */ +/* write */ +#define CS_CRESET 0x01 /* Card reset (0=reset) */ +#define CS_IMSK 0x02 /* enable IRQ (1=enable, 0=disable) */ +#define CS_RESINT1 0x04 /* PLINT1 reset */ +#define CS_VPPSW 0x10 /* 12V power switch (0=off, 1=on) */ +#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ +#define CS_RESINT2 0x40 /* PLINT2 reset */ +/* read */ +#define CS_BUSY 0x04 /* master transfer activ (=1) */ +#define CS_SW_EPROM 0x08 /* 0=Application Soft. 1=BOOT-EPROM */ +#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ +#define CS_SAS 0x80 /* single attachement station (=1) */ + +/* + * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ. + */ +#define IS_MINTR1 0x01 /* FORMAC ST1U/L && ~IMSK1U/L*/ +#define IS_MINTR2 0x02 /* FORMAC ST2U/L && ~IMSK2U/L*/ +#define IS_PLINT1 0x04 /* PLC1 */ +#define IS_PLINT2 0x08 /* PLC2 */ +#define IS_TIMINT 0x10 /* Timer 82C54-2 */ + +#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT) + +#define FPROM_SW() (inpw(CSR_A)&CS_SW_EPROM) +#define DMA_BUSY() (inpw(CSR_A)&CS_BUSY) +#define CHECK_FIFO() +#define BUS_CHECK() + +/* + * set Host Request register (wr.) + */ +#define SET_HRQ(qup) outpw(RQA_A+((qup)<<1),0) + +#ifndef UNIX +#ifndef WINNT +#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW))) +#else +#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A) & \ + (CS_CRESET|CS_BYPASS|CS_VPPSW))) +#endif +#else +#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \ + (CS_CRESET|CS_BYPASS|CS_VPPSW))) +#endif + +#ifndef UNIX +#define STI_FBI() outpw(CSR_A,(inpw(CSR_A) & \ + (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) +#else +#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \ + (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) +#endif + +#define CHECK_DMA() {unsigned k = 10000 ;\ + while (k && (DMA_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } + +#define GET_ISR() ~inpw(ISR_A) + +#endif /* ISA */ + +/*--------------------------------------------------------------------------*/ +#ifdef PCI + +/* + * (DV) = only defined for Da Vinci + * (ML) = only defined for Monalisa + */ + +/* + * Configuration Space header + */ +#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 (ML) 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 0x40 /* 32 bit (DV) Our Register */ +#define PCI_OUR_REG_1 0x40 /* 32 bit (ML) Our Register 1 */ +#define PCI_OUR_REG_2 0x44 /* 32 bit (ML) Our Register 2 */ +/* Power Management Region */ +#define PCI_PM_CAP_ID 0x48 /* 8 bit (ML) Power Management Cap. ID */ +#define PCI_PM_NITEM 0x49 /* 8 bit (ML) Next Item Ptr */ +#define PCI_PM_CAP_REG 0x4a /* 16 bit (ML) Power Management Capabilities */ +#define PCI_PM_CTL_STS 0x4c /* 16 bit (ML) Power Manag. Control/Status */ +/* Byte 0x4e: Reserved */ +#define PCI_PM_DAT_REG 0x4f /* 8 bit (ML) Power Manag. Data Register */ +/* VPD Region */ +#define PCI_VPD_CAP_ID 0x50 /* 8 bit (ML) VPD Cap. ID */ +#define PCI_VPD_NITEM 0x51 /* 8 bit (ML) Next Item Ptr */ +#define PCI_VPD_ADR_REG 0x52 /* 16 bit (ML) VPD Address Register */ +#define PCI_VPD_DAT_REG 0x54 /* 32 bit (ML) 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 */ +#define PCI_FBTEN 0x0200 /* Bit 9: Fast Back-To-Back enable */ +#define PCI_SERREN 0x0100 /* Bit 8: SERR enable */ +#define PCI_ADSTEP 0x0080 /* Bit 7: Address Stepping */ +#define PCI_PERREN 0x0040 /* Bit 6: Parity Report Response enable */ +#define PCI_VGA_SNOOP 0x0020 /* Bit 5: VGA palette snoop */ +#define PCI_MWIEN 0x0010 /* Bit 4: Memory write an inv cycl ena */ +#define PCI_SCYCEN 0x0008 /* Bit 3: Special Cycle enable */ +#define PCI_BMEN 0x0004 /* Bit 2: Bus Master enable */ +#define PCI_MEMEN 0x0002 /* Bit 1: Memory Space Access enable */ +#define PCI_IOEN 0x0001 /* Bit 0: IO Space Access enable */ + +/* PCI_STATUS 16 bit Status */ +#define PCI_PERR 0x8000 /* Bit 15: Parity Error */ +#define PCI_SERR 0x4000 /* Bit 14: Signaled SERR */ +#define PCI_RMABORT 0x2000 /* Bit 13: Received Master Abort */ +#define PCI_RTABORT 0x1000 /* Bit 12: Received Target Abort */ +#define PCI_STABORT 0x0800 /* Bit 11: Sent Target Abort */ +#define PCI_DEVSEL 0x0600 /* 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 0x0100 /* Bit 8: DATA Parity error detected */ +#define PCI_FB2BCAP 0x0080 /* Bit 7: Fast Back-to-Back Capability */ +#define PCI_UDF 0x0040 /* Bit 6: User Defined Features */ +#define PCI_66MHZCAP 0x0020 /* Bit 5: 66 MHz PCI bus clock capable */ +#define PCI_NEWCAP 0x0010 /* Bit 4: New cap. list implemented */ + +#define PCI_ERRBITS (PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR) + +/* PCI_REV_ID 8 bit Revision ID */ +/* PCI_CLASS_CODE 24 bit Class Code */ +/* Byte 2: Base Class (02) */ +/* Byte 1: SubClass (02) */ +/* Byte 0: Programming Interface (00) */ + +/* PCI_CACHE_LSZ 8 bit Cache Line Size */ +/* Possible values: 0,2,4,8,16 */ + +/* PCI_LAT_TIM 8 bit Latency Timer */ + +/* PCI_HEADER_T 8 bit Header Type */ +#define PCI_HD_MF_DEV 0x80 /* 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 */ +#define PCI_BIST_CAP 0x80 /* Bit 7: BIST Capable */ +#define PCI_BIST_ST 0x40 /* Bit 6: Start BIST */ +#define PCI_BIST_RET 0x0f /* Bit 3..0: Completion Code */ + +/* PCI_BASE_1ST 32 bit 1st Base address */ +#define PCI_MEMSIZE 0x800L /* use 2 kB Memory Base */ +#define PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11: Memory Base Address */ +#define PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4: Memory Size Req. */ +#define PCI_PREFEN 0x00000008L /* Bit 3: Prefetchable */ +#define PCI_MEM_TYP 0x00000006L /* Bit 2..1: Memory Type */ +#define PCI_MEM32BIT (0<<1) /* Base addr anywhere in 32 Bit range */ +#define PCI_MEM1M (1<<1) /* Base addr below 1 MegaByte */ +#define PCI_MEM64BIT (2<<1) /* Base addr anywhere in 64 Bit range */ +#define PCI_MEMSPACE 0x00000001L /* 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 */ +#define PCI_IOSPACE 0x00000001L /* Bit 0: I/O Space Indicator */ + +/* PCI_SUB_VID 16 bit Subsystem Vendor ID */ +/* PCI_SUB_ID 16 bit Subsystem ID */ + +/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ +#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE addres (1st) */ +#define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */ +#define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */ +#define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */ + +/* PCI_CAP_PTR 8 bit New Capabilities Pointers */ +/* PCI_IRQ_LINE 8 bit Interrupt Line */ +/* PCI_IRQ_PIN 8 bit Interrupt Pin */ +/* PCI_MIN_GNT 8 bit Min_Gnt */ +/* PCI_MAX_LAT 8 bit Max_Lat */ +/* Device Dependent Region */ +/* PCI_OUR_REG (DV) 32 bit Our Register */ +/* PCI_OUR_REG_1 (ML) 32 bit Our Register 1 */ + /* Bit 31..29: reserved */ +#define PCI_PATCH_DIR (3L<<27) /*(DV) Bit 28..27: Ext Patchs direction */ +#define PCI_PATCH_DIR_0 (1L<<27) /*(DV) Type of the pins EXT_PATCHS<1..0> */ +#define PCI_PATCH_DIR_1 (1L<<28) /* 0 = input */ + /* 1 = output */ +#define PCI_EXT_PATCHS (3L<<25) /*(DV) Bit 26..25: Extended Patches */ +#define PCI_EXT_PATCH_0 (1L<<25) /*(DV) */ +#define PCI_EXT_PATCH_1 (1L<<26) /* CLK for MicroWire (ML) */ +#define PCI_VIO (1L<<25) /*(ML) */ +#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */ + /* 1 = Don't boot with 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 Memory */ + /* 0 = Disable all addr. decoding */ +#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 (ML) and (DV) */ +#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ + /* Bit 15: reserved */ +#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_BYTE_SWAP (1L<<8) /*(DV) Bit 8: Byte Swap in DATA */ +#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 (ML) 32 bit Our Register 2 (Monalisa only) */ +#define PCI_VPD_WR_TH (0xffL<<24) /* Bit 24..31 VPD Write Threshold */ +#define PCI_DEV_SEL (0x7fL<<17) /* Bit 17..23 EEPROM Device Select */ +#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 14..16 VPD ROM Size */ + /* Bit 12..13 reserved */ +#define PCI_PATCH_DIR2 (0xfL<<8) /* Bit 8..11 Ext Patchs dir 2..5 */ +#define PCI_PATCH_DIR_2 (1L<<8) /* Bit 8 CS for MicroWire */ +#define PCI_PATCH_DIR_3 (1L<<9) +#define PCI_PATCH_DIR_4 (1L<<10) +#define PCI_PATCH_DIR_5 (1L<<11) +#define PCI_EXT_PATCHS2 (0xfL<<4) /* Bit 4..7 Extended Patches */ +#define PCI_EXT_PATCH_2 (1L<<4) /* Bit 4 CS for MicroWire */ +#define PCI_EXT_PATCH_3 (1L<<5) +#define PCI_EXT_PATCH_4 (1L<<6) +#define PCI_EXT_PATCH_5 (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 */ +#define PCI_USEADDR64 (1L<<1) /* Bit 1 Use 64 Bit Addresse */ +#define PCI_USEDATA64 (1L<<0) /* Bit 0 Use 64 Bit Data bus ext*/ + +/* Power Management Region */ +/* PCI_PM_CAP_ID 8 bit (ML) Power Management Cap. ID */ +/* PCI_PM_NITEM 8 bit (ML) Next Item Ptr */ +/* PCI_PM_CAP_REG 16 bit (ML) Power Management Capabilities*/ +#define PCI_PME_SUP (0x1f<<11) /* Bit 11..15 PM Manag. Event Support*/ +#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 6..8 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 0..2 PM PCI Spec. version */ + +/* PCI_PM_CTL_STS 16 bit (ML) Power Manag. Control/Status */ +#define PCI_PME_STATUS (1<<15) /* Bit 15 PFA doesn't sup. PME#*/ +#define PCI_PM_DAT_SCL (3<<13) /* Bit 13..14 dat reg Scaling factor */ +#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 9..12 PM data selector field */ + /* Bit 7.. 2 reserved */ +#define PCI_PM_STATE (3<<0) /* Bit 0.. 1 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 */ + +/* PCI_PM_DAT_REG 8 bit (ML) Power Manag. Data Register */ +/* VPD Region */ +/* PCI_VPD_CAP_ID 8 bit (ML) VPD Cap. ID */ +/* PCI_VPD_NITEM 8 bit (ML) Next Item Ptr */ +/* PCI_VPD_ADR_REG 16 bit (ML) VPD Address Register */ +#define PCI_VPD_FLAG (1<<15) /* Bit 15 starts VPD rd/wd cycle*/ +#define PCI_VPD_ADDR (0x3fff<<0) /* Bit 0..14 VPD address */ + +/* PCI_VPD_DAT_REG 32 bit (ML) VPD Data Register */ + +/* + * Control Register File: + * Bank 0 + */ +#define B0_RAP 0x0000 /* 8 bit register address port */ + /* 0x0001 - 0x0003: reserved */ +#define B0_CTRL 0x0004 /* 8 bit control register */ +#define B0_DAS 0x0005 /* 8 Bit control register (DAS) */ +#define B0_LED 0x0006 /* 8 Bit LED register */ +#define B0_TST_CTRL 0x0007 /* 8 bit test control register */ +#define B0_ISRC 0x0008 /* 32 bit Interrupt source register */ +#define B0_IMSK 0x000c /* 32 bit Interrupt mask register */ + +/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ +#define B0_CMDREG1 0x0010 /* write command reg 1 instruction */ +#define B0_CMDREG2 0x0014 /* write command reg 2 instruction */ +#define B0_ST1U 0x0010 /* read upper 16-bit of status reg 1 */ +#define B0_ST1L 0x0014 /* read lower 16-bit of status reg 1 */ +#define B0_ST2U 0x0018 /* read upper 16-bit of status reg 2 */ +#define B0_ST2L 0x001c /* read lower 16-bit of status reg 2 */ + +#define B0_MARR 0x0020 /* r/w the memory read addr register */ +#define B0_MARW 0x0024 /* r/w the memory write addr register*/ +#define B0_MDRU 0x0028 /* r/w upper 16-bit of mem. data reg */ +#define B0_MDRL 0x002c /* r/w lower 16-bit of mem. data reg */ + +#define B0_MDREG3 0x0030 /* r/w Mode Register 3 */ +#define B0_ST3U 0x0034 /* read upper 16-bit of status reg 3 */ +#define B0_ST3L 0x0038 /* read lower 16-bit of status reg 3 */ +#define B0_IMSK3U 0x003c /* r/w upper 16-bit of IMSK reg 3 */ +#define B0_IMSK3L 0x0040 /* r/w lower 16-bit of IMSK reg 3 */ +#define B0_IVR 0x0044 /* read Interrupt Vector register */ +#define B0_IMR 0x0048 /* r/w Interrupt mask register */ +/* 0x4c Hidden */ + +#define B0_CNTRL_A 0x0050 /* control register A (r/w) */ +#define B0_CNTRL_B 0x0054 /* control register B (r/w) */ +#define B0_INTR_MASK 0x0058 /* interrupt mask (r/w) */ +#define B0_XMIT_VECTOR 0x005c /* transmit vector register (r/w) */ + +#define B0_STATUS_A 0x0060 /* status register A (read only) */ +#define B0_STATUS_B 0x0064 /* status register B (read only) */ +#define B0_CNTRL_C 0x0068 /* control register C (r/w) */ +#define B0_MDREG1 0x006c /* r/w Mode Register 1 */ + +#define B0_R1_CSR 0x0070 /* 32 bit BMU control/status reg (rec q 1) */ +#define B0_R2_CSR 0x0074 /* 32 bit BMU control/status reg (rec q 2)(DV)*/ +#define B0_XA_CSR 0x0078 /* 32 bit BMU control/status reg (a xmit q) */ +#define B0_XS_CSR 0x007c /* 32 bit BMU control/status reg (s xmit q) */ + +/* + * Bank 1 + * - completely empty (this is the RAP Block window) + * Note: if RAP = 1 this page is reserved + */ + +/* + * Bank 2 + */ +#define B2_MAC_0 0x0100 /* 8 bit MAC address Byte 0 */ +#define B2_MAC_1 0x0101 /* 8 bit MAC address Byte 1 */ +#define B2_MAC_2 0x0102 /* 8 bit MAC address Byte 2 */ +#define B2_MAC_3 0x0103 /* 8 bit MAC address Byte 3 */ +#define B2_MAC_4 0x0104 /* 8 bit MAC address Byte 4 */ +#define B2_MAC_5 0x0105 /* 8 bit MAC address Byte 5 */ +#define B2_MAC_6 0x0106 /* 8 bit MAC address Byte 6 (== 0) (DV) */ +#define B2_MAC_7 0x0107 /* 8 bit MAC address Byte 7 (== 0) (DV) */ + +#define B2_CONN_TYP 0x0108 /* 8 bit Connector type */ +#define B2_PMD_TYP 0x0109 /* 8 bit PMD type */ + /* 0x010a - 0x010b: reserved */ + /* Eprom registers are currently of no use */ +#define B2_E_0 0x010c /* 8 bit EPROM Byte 0 */ +#define B2_E_1 0x010d /* 8 bit EPROM Byte 1 */ +#define B2_E_2 0x010e /* 8 bit EPROM Byte 2 */ +#define B2_E_3 0x010f /* 8 bit EPROM Byte 3 */ +#define B2_FAR 0x0110 /* 32 bit Flash-Prom Address Register/Counter */ +#define B2_FDP 0x0114 /* 8 bit Flash-Prom Data Port */ + /* 0x0115 - 0x0117: reserved */ +#define B2_LD_CRTL 0x0118 /* 8 bit loader control */ +#define B2_LD_TEST 0x0119 /* 8 bit loader test */ + /* 0x011a - 0x011f: reserved */ +#define B2_TI_INI 0x0120 /* 32 bit Timer init value */ +#define B2_TI_VAL 0x0124 /* 32 bit Timer value */ +#define B2_TI_CRTL 0x0128 /* 8 bit Timer control */ +#define B2_TI_TEST 0x0129 /* 8 Bit Timer Test */ + /* 0x012a - 0x012f: reserved */ +#define B2_WDOG_INI 0x0130 /* 32 bit Watchdog init value */ +#define B2_WDOG_VAL 0x0134 /* 32 bit Watchdog value */ +#define B2_WDOG_CRTL 0x0138 /* 8 bit Watchdog control */ +#define B2_WDOG_TEST 0x0139 /* 8 Bit Watchdog Test */ + /* 0x013a - 0x013f: reserved */ +#define B2_RTM_INI 0x0140 /* 32 bit RTM init value */ +#define B2_RTM_VAL 0x0144 /* 32 bit RTM value */ +#define B2_RTM_CRTL 0x0148 /* 8 bit RTM control */ +#define B2_RTM_TEST 0x0149 /* 8 Bit RTM Test */ + +#define B2_TOK_COUNT 0x014c /* (ML) 32 bit Token Counter */ +#define B2_DESC_ADDR_H 0x0150 /* (ML) 32 bit Desciptor Base Addr Reg High */ +#define B2_CTRL_2 0x0154 /* (ML) 8 bit Control Register 2 */ +#define B2_IFACE_REG 0x0155 /* (ML) 8 bit Interface Register */ + /* 0x0156: reserved */ +#define B2_TST_CTRL_2 0x0157 /* (ML) 8 bit Test Control Register 2 */ +#define B2_I2C_CTRL 0x0158 /* (ML) 32 bit I2C Control Register */ +#define B2_I2C_DATA 0x015c /* (ML) 32 bit I2C Data Register */ + +#define B2_IRQ_MOD_INI 0x0160 /* (ML) 32 bit IRQ Moderation Timer Init Reg. */ +#define B2_IRQ_MOD_VAL 0x0164 /* (ML) 32 bit IRQ Moderation Timer Value */ +#define B2_IRQ_MOD_CTRL 0x0168 /* (ML) 8 bit IRQ Moderation Timer Control */ +#define B2_IRQ_MOD_TEST 0x0169 /* (ML) 8 bit IRQ Moderation Timer Test */ + /* 0x016a - 0x017f: reserved */ + +/* + * Bank 3 + */ +/* + * This is a copy of the Configuration register file (lower half) + */ +#define B3_CFG_SPC 0x180 + +/* + * Bank 4 + */ +#define B4_R1_D 0x0200 /* 4*32 bit current receive Descriptor */ +#define B4_R1_DA 0x0210 /* 32 bit current rec desc address */ +#define B4_R1_AC 0x0214 /* 32 bit current receive Address Count */ +#define B4_R1_BC 0x0218 /* 32 bit current receive Byte Counter */ +#define B4_R1_CSR 0x021c /* 32 bit BMU Control/Status Register */ +#define B4_R1_F 0x0220 /* 32 bit flag register */ +#define B4_R1_T1 0x0224 /* 32 bit Test Register 1 */ +#define B4_R1_T1_TR 0x0224 /* 8 bit Test Register 1 TR */ +#define B4_R1_T1_WR 0x0225 /* 8 bit Test Register 1 WR */ +#define B4_R1_T1_RD 0x0226 /* 8 bit Test Register 1 RD */ +#define B4_R1_T1_SV 0x0227 /* 8 bit Test Register 1 SV */ +#define B4_R1_T2 0x0228 /* 32 bit Test Register 2 */ +#define B4_R1_T3 0x022c /* 32 bit Test Register 3 */ +#define B4_R1_DA_H 0x0230 /* (ML) 32 bit Curr Rx Desc Address High */ +#define B4_R1_AC_H 0x0234 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x0238 - 0x023f: reserved */ + /* Receive queue 2 is removed on Monalisa */ +#define B4_R2_D 0x0240 /* 4*32 bit current receive Descriptor (q2) */ +#define B4_R2_DA 0x0250 /* 32 bit current rec desc address (q2) */ +#define B4_R2_AC 0x0254 /* 32 bit current receive Address Count (q2) */ +#define B4_R2_BC 0x0258 /* 32 bit current receive Byte Counter (q2) */ +#define B4_R2_CSR 0x025c /* 32 bit BMU Control/Status Register (q2) */ +#define B4_R2_F 0x0260 /* 32 bit flag register (q2) */ +#define B4_R2_T1 0x0264 /* 32 bit Test Register 1 (q2) */ +#define B4_R2_T1_TR 0x0264 /* 8 bit Test Register 1 TR (q2) */ +#define B4_R2_T1_WR 0x0265 /* 8 bit Test Register 1 WR (q2) */ +#define B4_R2_T1_RD 0x0266 /* 8 bit Test Register 1 RD (q2) */ +#define B4_R2_T1_SV 0x0267 /* 8 bit Test Register 1 SV (q2) */ +#define B4_R2_T2 0x0268 /* 32 bit Test Register 2 (q2) */ +#define B4_R2_T3 0x026c /* 32 bit Test Register 3 (q2) */ + /* 0x0270 - 0x027c: reserved */ + +/* + * Bank 5 + */ +#define B5_XA_D 0x0280 /* 4*32 bit current transmit Descriptor (xa) */ +#define B5_XA_DA 0x0290 /* 32 bit current tx desc address (xa) */ +#define B5_XA_AC 0x0294 /* 32 bit current tx Address Count (xa) */ +#define B5_XA_BC 0x0298 /* 32 bit current tx Byte Counter (xa) */ +#define B5_XA_CSR 0x029c /* 32 bit BMU Control/Status Register (xa) */ +#define B5_XA_F 0x02a0 /* 32 bit flag register (xa) */ +#define B5_XA_T1 0x02a4 /* 32 bit Test Register 1 (xa) */ +#define B5_XA_T1_TR 0x02a4 /* 8 bit Test Register 1 TR (xa) */ +#define B5_XA_T1_WR 0x02a5 /* 8 bit Test Register 1 WR (xa) */ +#define B5_XA_T1_RD 0x02a6 /* 8 bit Test Register 1 RD (xa) */ +#define B5_XA_T1_SV 0x02a7 /* 8 bit Test Register 1 SV (xa) */ +#define B5_XA_T2 0x02a8 /* 32 bit Test Register 2 (xa) */ +#define B5_XA_T3 0x02ac /* 32 bit Test Register 3 (xa) */ +#define B5_XA_DA_H 0x02b0 /* (ML) 32 bit Curr Tx Desc Address High */ +#define B5_XA_AC_H 0x02b4 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x02b8 - 0x02bc: reserved */ +#define B5_XS_D 0x02c0 /* 4*32 bit current transmit Descriptor (xs) */ +#define B5_XS_DA 0x02d0 /* 32 bit current tx desc address (xs) */ +#define B5_XS_AC 0x02d4 /* 32 bit current transmit Address Count(xs) */ +#define B5_XS_BC 0x02d8 /* 32 bit current transmit Byte Counter (xs) */ +#define B5_XS_CSR 0x02dc /* 32 bit BMU Control/Status Register (xs) */ +#define B5_XS_F 0x02e0 /* 32 bit flag register (xs) */ +#define B5_XS_T1 0x02e4 /* 32 bit Test Register 1 (xs) */ +#define B5_XS_T1_TR 0x02e4 /* 8 bit Test Register 1 TR (xs) */ +#define B5_XS_T1_WR 0x02e5 /* 8 bit Test Register 1 WR (xs) */ +#define B5_XS_T1_RD 0x02e6 /* 8 bit Test Register 1 RD (xs) */ +#define B5_XS_T1_SV 0x02e7 /* 8 bit Test Register 1 SV (xs) */ +#define B5_XS_T2 0x02e8 /* 32 bit Test Register 2 (xs) */ +#define B5_XS_T3 0x02ec /* 32 bit Test Register 3 (xs) */ +#define B5_XS_DA_H 0x02f0 /* (ML) 32 bit Curr Tx Desc Address High */ +#define B5_XS_AC_H 0x02f4 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x02f8 - 0x02fc: reserved */ + +/* + * Bank 6 + */ +/* External PLC-S registers (SN2 compatibility for DV) */ +/* External registers (ML) */ +#define B6_EXT_REG 0x300 + +/* + * Bank 7 + */ +/* DAS PLC-S Registers */ + +/* + * Bank 8 - 15 + */ +/* IFCP registers */ + +/*---------------------------------------------------------------------------*/ +/* Definitions of the Bits in the registers */ + +/* B0_RAP 16 bit register address port */ +#define RAP_RAP 0x0f /* Bit 3..0: 0 = block0, .., f = block15 */ + +/* B0_CTRL 8 bit control register */ +#define CTRL_FDDI_CLR (1<<7) /* Bit 7: (ML) Clear FDDI Reset */ +#define CTRL_FDDI_SET (1<<6) /* Bit 6: (ML) Set FDDI Reset */ +#define CTRL_HPI_CLR (1<<5) /* Bit 5: Clear HPI SM reset */ +#define CTRL_HPI_SET (1<<4) /* Bit 4: Set HPI SM reset */ +#define CTRL_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */ +#define CTRL_MRST_SET (1<<2) /* Bit 2: Set Master reset */ +#define CTRL_RST_CLR (1<<1) /* Bit 1: Clear Software reset */ +#define CTRL_RST_SET (1<<0) /* Bit 0: Set Software reset */ + +/* B0_DAS 8 Bit control register (DAS) */ +#define BUS_CLOCK (1<<7) /* Bit 7: (ML) Bus Clock 0/1 = 33/66MHz */ +#define BUS_SLOT_SZ (1<<6) /* Bit 6: (ML) Slot Size 0/1 = 32/64 bit slot*/ + /* Bit 5..4: reserved */ +#define DAS_AVAIL (1<<3) /* Bit 3: 1 = DAS, 0 = SAS */ +#define DAS_BYP_ST (1<<2) /* Bit 2: 1 = avail,SAS, 0 = not avail */ +#define DAS_BYP_INS (1<<1) /* Bit 1: 1 = insert Bypass */ +#define DAS_BYP_RMV (1<<0) /* Bit 0: 1 = remove Bypass */ + +/* B0_LED 8 Bit LED register */ + /* Bit 7..6: reserved */ +#define LED_2_ON (1<<5) /* Bit 5: 1 = switch LED_2 on (left,gn)*/ +#define LED_2_OFF (1<<4) /* Bit 4: 1 = switch LED_2 off */ +#define LED_1_ON (1<<3) /* Bit 3: 1 = switch LED_1 on (mid,yel)*/ +#define LED_1_OFF (1<<2) /* Bit 2: 1 = switch LED_1 off */ +#define LED_0_ON (1<<1) /* Bit 1: 1 = switch LED_0 on (rght,gn)*/ +#define LED_0_OFF (1<<0) /* Bit 0: 1 = switch LED_0 off */ +/* This hardware defines are very ugly therefore we define some others */ + +#define LED_GA_ON LED_2_ON /* S port = A port */ +#define LED_GA_OFF LED_2_OFF /* S port = A port */ +#define LED_MY_ON LED_1_ON +#define LED_MY_OFF LED_1_OFF +#define LED_GB_ON LED_0_ON +#define LED_GB_OFF LED_0_OFF + +/* B0_TST_CTRL 8 bit test control register */ +#define TST_FRC_DPERR_MR (1<<7) /* Bit 7: force DATAPERR on MST RE. */ +#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 RE. */ +#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: ena configuration reg. WR */ +#define TST_CFG_WRITE_OFF (1<<0) /* Bit 0: dis configuration reg. WR */ + +/* B0_ISRC 32 bit Interrupt source register */ + /* Bit 31..28: reserved */ +#define IS_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ +#define IS_IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ +#define IS_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ +#define IS_IRQ_STAT (1L<<24) /* Bit 24: IRQ status execption */ + /* PERR, RMABORT, RTABORT DATAPERR */ +#define IS_IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ + /* RMABORT, RTABORT, DATAPERR */ +#define IS_TIMINT (1L<<22) /* Bit 22: IRQ_TIMER */ +#define IS_TOKEN (1L<<21) /* Bit 21: IRQ_RTM */ +/* + * Note: The DAS is our First Port (!=PA) + */ +#define IS_PLINT1 (1L<<20) /* Bit 20: IRQ_PHY_DAS */ +#define IS_PLINT2 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ +#define IS_MINTR3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ +#define IS_MINTR2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ +#define IS_MINTR1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ +/* Receive Queue 1 */ +#define IS_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ +#define IS_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ +#define IS_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ +#define IS_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ +/* Receive Queue 2 */ +#define IS_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ +#define IS_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ +#define IS_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ +#define IS_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ +/* Asynchronous Transmit queue */ + /* Bit 7: reserved */ +#define IS_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ +#define IS_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ +#define IS_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ +/* Synchronous Transmit queue */ + /* Bit 3: reserved */ +#define IS_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ +#define IS_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ +#define IS_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ + +/* + * Define all valid interrupt source Bits from GET_ISR () + */ +#define ALL_IRSR 0x01ffff77L /* (DV) */ +#define ALL_IRSR_ML 0x0ffff077L /* (ML) */ + + +/* B0_IMSK 32 bit Interrupt mask register */ +/* + * The Bit definnition of this register are the same as of the interrupt + * source register. These definition are directly derived from the Hardware + * spec. + */ + /* Bit 31..28: reserved */ +#define IRQ_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ +#define IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ +#define IRQ_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ +#define IRQ_STAT (1L<<24) /* Bit 24: IRQ status execption */ + /* PERR, RMABORT, RTABORT DATAPERR */ +#define IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ + /* RMABORT, RTABORT, DATAPERR */ +#define IRQ_TIMER (1L<<22) /* Bit 22: IRQ_TIMER */ +#define IRQ_RTM (1L<<21) /* Bit 21: IRQ_RTM */ +#define IRQ_DAS (1L<<20) /* Bit 20: IRQ_PHY_DAS */ +#define IRQ_IFCP_4 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ +#define IRQ_IFCP_3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ +#define IRQ_IFCP_2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ +#define IRQ_IFCP_1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ +/* Receive Queue 1 */ +#define IRQ_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ +#define IRQ_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ +#define IRQ_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ +#define IRQ_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ +/* Receive Queue 2 */ +#define IRQ_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ +#define IRQ_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ +#define IRQ_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ +#define IRQ_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ +/* Asynchronous Transmit queue */ + /* Bit 7: reserved */ +#define IRQ_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ +#define IRQ_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ +#define IRQ_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ +/* Synchronous Transmit queue */ + /* Bit 3: reserved */ +#define IRQ_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ +#define IRQ_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ +#define IRQ_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ + +/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ +/* B0_R1_CSR 32 bit BMU control/status reg (rec q 1 ) */ +/* B0_R2_CSR 32 bit BMU control/status reg (rec q 2 ) */ +/* B0_XA_CSR 32 bit BMU control/status reg (a xmit q ) */ +/* B0_XS_CSR 32 bit BMU control/status reg (s xmit q ) */ +/* The registers are the same as B4_R1_CSR, B4_R2_CSR, B5_Xa_CSR, B5_XS_CSR */ + +/* B2_MAC_0 8 bit MAC address Byte 0 */ +/* B2_MAC_1 8 bit MAC address Byte 1 */ +/* B2_MAC_2 8 bit MAC address Byte 2 */ +/* B2_MAC_3 8 bit MAC address Byte 3 */ +/* B2_MAC_4 8 bit MAC address Byte 4 */ +/* B2_MAC_5 8 bit MAC address Byte 5 */ +/* B2_MAC_6 8 bit MAC address Byte 6 (== 0) (DV) */ +/* B2_MAC_7 8 bit MAC address Byte 7 (== 0) (DV) */ + +/* 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 */ + +/* The EPROM register are currently of no use */ +/* B2_E_0 8 bit EPROM Byte 0 */ +/* B2_E_1 8 bit EPROM Byte 1 */ +/* B2_E_2 8 bit EPROM Byte 2 */ +/* B2_E_3 8 bit EPROM Byte 3 */ + +/* B2_FAR 32 bit Flash-Prom Address Register/Counter */ +#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */ + +/* B2_FDP 8 bit Flash-Prom Data Port */ + +/* B2_LD_CRTL 8 bit loader control */ +/* Bits are currently reserved */ + +/* B2_LD_TEST 8 bit loader test */ +#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 */ + +/* B2_TI_INI 32 bit Timer init value */ +/* B2_TI_VAL 32 bit Timer value */ +/* B2_TI_CRTL 8 bit Timer control */ +/* B2_TI_TEST 8 Bit Timer Test */ +/* B2_WDOG_INI 32 bit Watchdog init value */ +/* B2_WDOG_VAL 32 bit Watchdog value */ +/* B2_WDOG_CRTL 8 bit Watchdog control */ +/* B2_WDOG_TEST 8 Bit Watchdog Test */ +/* B2_RTM_INI 32 bit RTM init value */ +/* B2_RTM_VAL 32 bit RTM value */ +/* B2_RTM_CRTL 8 bit RTM control */ +/* B2_RTM_TEST 8 Bit RTM Test */ +/* B2__CRTL 8 bit control */ +/* B2_IRQ_MOD_INI 32 bit IRQ Moderation Timer Init Reg. (ML) */ +/* B2_IRQ_MOD_VAL 32 bit IRQ Moderation Timer Value (ML) */ +/* B2_IRQ_MOD_CTRL 8 bit IRQ Moderation Timer Control (ML) */ +/* B2_IRQ_MOD_TEST 8 bit IRQ Moderation Timer Test (ML) */ +#define GET_TOK_CT (1<<4) /* Bit 4: Get the Token Counter (RTM) */ +#define TIM_RES_TOK (1<<3) /* Bit 3: RTM Status: 1 == restricted */ +#define TIM_ALARM (1<<3) /* Bit 3: Timer Alarm (WDOG) */ +#define TIM_START (1<<2) /* Bit 2: Start Timer (TI,WDOG,RTM,IRQ_MOD)*/ +#define TIM_STOP (1<<1) /* Bit 1: Stop Timer (TI,WDOG,RTM,IRQ_MOD) */ +#define TIM_CL_IRQ (1<<0) /* Bit 0: Clear Timer IRQ (TI,WDOG,RTM) */ +/* B2__TEST 8 Bit Test */ +#define TIM_T_ON (1<<2) /* Bit 2: Test mode on (TI,WDOG,RTM,IRQ_MOD) */ +#define TIM_T_OFF (1<<1) /* Bit 1: Test mode off (TI,WDOG,RTM,IRQ_MOD) */ +#define TIM_T_STEP (1<<0) /* Bit 0: Test step (TI,WDOG,RTM,IRQ_MOD) */ + +/* B2_TOK_COUNT 0x014c (ML) 32 bit Token Counter */ +/* B2_DESC_ADDR_H 0x0150 (ML) 32 bit Desciptor Base Addr Reg High */ +/* B2_CTRL_2 0x0154 (ML) 8 bit Control Register 2 */ + /* Bit 7..5: reserved */ +#define CTRL_CL_I2C_IRQ (1<<4) /* Bit 4: Clear I2C IRQ */ +#define CTRL_ST_SW_IRQ (1<<3) /* Bit 3: Set IRQ SW Request */ +#define CTRL_CL_SW_IRQ (1<<2) /* Bit 2: Clear IRQ SW Request */ +#define CTRL_STOP_DONE (1<<1) /* Bit 1: Stop Master is finished */ +#define CTRL_STOP_MAST (1<<0) /* Bit 0: Command Bit to stop the master*/ + +/* B2_IFACE_REG 0x0155 (ML) 8 bit Interface Register */ + /* Bit 7..3: reserved */ +#define IF_I2C_DATA_DIR (1<<2) /* Bit 2: direction of IF_I2C_DATA*/ +#define IF_I2C_DATA (1<<1) /* Bit 1: I2C Data Port */ +#define IF_I2C_CLK (1<<0) /* Bit 0: I2C Clock Port */ + + /* 0x0156: reserved */ +/* B2_TST_CTRL_2 0x0157 (ML) 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_I2C_CTRL 0x0158 (ML) 32 bit I2C Control Register */ +#define I2C_FLAG (1L<<31) /* Bit 31: Start read/write if WR */ +#define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be read/written*/ +#define I2C_DEV_SEL (0x7fL<<9) /* Bit 9..15: I2C Device Select */ + /* Bit 5.. 8: reserved */ +#define I2C_BURST_LEN (1L<<4) /* Bit 4 Burst Len, 1/4 bytes */ +#define I2C_DEV_SIZE (7L<<1) /* Bit 1.. 3: I2C Device Size */ +#define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smaller*/ +#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_BIT (1<<0) /* Bit 0: Interrupt I2C transfer */ + +/* + * I2C Addresses + * + * The temperature sensor and the voltage sensor are on the same I2C bus. + * Note: The voltage sensor (Micorwire) will be selected by PCI_EXT_PATCH_1 + * in PCI_OUR_REG 1. + */ +#define I2C_ADDR_TEMP 0x90 /* I2C Address Temperature Sensor */ + +/* B2_I2C_DATA 0x015c (ML) 32 bit I2C Data Register */ + +/* B4_R1_D 4*32 bit current receive Descriptor (q1) */ +/* B4_R1_DA 32 bit current rec desc address (q1) */ +/* B4_R1_AC 32 bit current receive Address Count (q1) */ +/* B4_R1_BC 32 bit current receive Byte Counter (q1) */ +/* B4_R1_CSR 32 bit BMU Control/Status Register (q1) */ +/* B4_R1_F 32 bit flag register (q1) */ +/* B4_R1_T1 32 bit Test Register 1 (q1) */ +/* B4_R1_T2 32 bit Test Register 2 (q1) */ +/* B4_R1_T3 32 bit Test Register 3 (q1) */ +/* B4_R2_D 4*32 bit current receive Descriptor (q2) */ +/* B4_R2_DA 32 bit current rec desc address (q2) */ +/* B4_R2_AC 32 bit current receive Address Count (q2) */ +/* B4_R2_BC 32 bit current receive Byte Counter (q2) */ +/* B4_R2_CSR 32 bit BMU Control/Status Register (q2) */ +/* B4_R2_F 32 bit flag register (q2) */ +/* B4_R2_T1 32 bit Test Register 1 (q2) */ +/* B4_R2_T2 32 bit Test Register 2 (q2) */ +/* B4_R2_T3 32 bit Test Register 3 (q2) */ +/* B5_XA_D 4*32 bit current receive Descriptor (xa) */ +/* B5_XA_DA 32 bit current rec desc address (xa) */ +/* B5_XA_AC 32 bit current receive Address Count (xa) */ +/* B5_XA_BC 32 bit current receive Byte Counter (xa) */ +/* B5_XA_CSR 32 bit BMU Control/Status Register (xa) */ +/* B5_XA_F 32 bit flag register (xa) */ +/* B5_XA_T1 32 bit Test Register 1 (xa) */ +/* B5_XA_T2 32 bit Test Register 2 (xa) */ +/* B5_XA_T3 32 bit Test Register 3 (xa) */ +/* B5_XS_D 4*32 bit current receive Descriptor (xs) */ +/* B5_XS_DA 32 bit current rec desc address (xs) */ +/* B5_XS_AC 32 bit current receive Address Count (xs) */ +/* B5_XS_BC 32 bit current receive Byte Counter (xs) */ +/* B5_XS_CSR 32 bit BMU Control/Status Register (xs) */ +/* B5_XS_F 32 bit flag register (xs) */ +/* B5_XS_T1 32 bit Test Register 1 (xs) */ +/* B5_XS_T2 32 bit Test Register 2 (xs) */ +/* B5_XS_T3 32 bit Test Register 3 (xs) */ +/* B5__CSR 32 bit BMU Control/Status Register (xx) */ +#define CSR_DESC_CLEAR (1L<<21) /* Bit 21: Clear Reset for Descr */ +#define CSR_DESC_SET (1L<<20) /* Bit 20: Set Reset for Descr */ +#define CSR_FIFO_CLEAR (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 */ + /* Bit 7..5: reserved */ +#define CSR_START (1L<<4) /* Bit 4: Start Rec/Xmit Queue */ +#define CSR_IRQ_CL_P (1L<<3) /* Bit 3: Clear Parity IRQ, Rcv */ +#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_CLEAR|CSR_FIFO_CLEAR|CSR_HPI_RUN|CSR_SV_RUN|\ + CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN) + + +/* B5__F 32 bit flag register (xx) */ + /* Bit 28..31: reserved */ +#define F_ALM_FULL (1L<<27) /* Bit 27: (ML) FIFO almost full */ +#define F_FIFO_EOF (1L<<26) /* Bit 26: (ML) Fag bit in FIFO */ +#define F_WM_REACHED (1L<<25) /* Bit 25: (ML) Watermark reached */ +#define F_UP_DW_USED (1L<<24) /* Bit 24: (ML) Upper Dword used (bug)*/ + /* Bit 23: reserved */ +#define F_FIFO_LEVEL (0x1fL<<16) /* Bit 16..22:(ML) # of Qwords in FIFO*/ + /* Bit 8..15: reserved */ +#define F_ML_WATER_M 0x0000ffL /* Bit 0.. 7:(ML) Watermark */ +#define FLAG_WATER 0x00001fL /* Bit 4..0:(DV) Level of req data tr.*/ + +/* B5__T1 32 bit Test Register 1 (xx) */ +/* 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 */ + +/* B4__T1_TR 8 bit Test Register 1 TR (xx) */ +/* B4__T1_WR 8 bit Test Register 1 WR (xx) */ +/* B4__T1_RD 8 bit Test Register 1 RD (xx) */ +/* B4__T1_SV 8 bit Test Register 1 SV (xx) */ +/* The control status byte of each machine looks like ... */ +#define SM_STATE 0xf0 /* Bit 7..4: State which shall be loaded */ +#define SM_LOAD 0x08 /* Bit 3: Load the SM with SM_STATE */ +#define SM_TEST_ON 0x04 /* Bit 2: Switch on SM Test Mode */ +#define SM_TEST_OFF 0x02 /* Bit 1: Go off the Test Mode */ +#define SM_STEP 0x01 /* Bit 0: Step the State Machine */ + +/* The coding of the states */ +#define SM_SV_IDLE 0x0 /* Supervisor Idle Tr/Re */ +#define SM_SV_RES_START 0x1 /* Supervisor Res_Start Tr/Re */ +#define SM_SV_GET_DESC 0x3 /* Supervisor Get_Desc Tr/Re */ +#define SM_SV_CHECK 0x2 /* Supervisor Check Tr/Re */ +#define SM_SV_MOV_DATA 0x6 /* Supervisor Move_Data Tr/Re */ +#define SM_SV_PUT_DESC 0x7 /* Supervisor Put_Desc Tr/Re */ +#define SM_SV_SET_IRQ 0x5 /* Supervisor Set_Irq Tr/Re */ + +#define SM_RD_IDLE 0x0 /* Read Desc. Idle Tr/Re */ +#define SM_RD_LOAD 0x1 /* Read Desc. Load Tr/Re */ +#define SM_RD_WAIT_TC 0x3 /* Read Desc. Wait_TC Tr/Re */ +#define SM_RD_RST_EOF 0x6 /* Read Desc. Reset_EOF Re */ +#define SM_RD_WDONE_R 0x2 /* Read Desc. Wait_Done Re */ +#define SM_RD_WDONE_T 0x4 /* Read Desc. Wait_Done Tr */ + +#define SM_TR_IDLE 0x0 /* Trans. Data Idle Tr/Re */ +#define SM_TR_LOAD 0x3 /* Trans. Data Load Tr/Re */ +#define SM_TR_LOAD_R_ML 0x1 /* Trans. Data Load /Re (ML) */ +#define SM_TR_WAIT_TC 0x2 /* Trans. Data Wait_TC Tr/Re */ +#define SM_TR_WDONE 0x4 /* Trans. Data Wait_Done Tr/Re */ + +#define SM_WR_IDLE 0x0 /* Write Desc. Idle Tr/Re */ +#define SM_WR_ABLEN 0x1 /* Write Desc. Act_Buf_Length Tr/Re */ +#define SM_WR_LD_A4 0x2 /* Write Desc. Load_A4 Re */ +#define SM_WR_RES_OWN 0x2 /* Write Desc. Res_OWN Tr */ +#define SM_WR_WAIT_EOF 0x3 /* Write Desc. Wait_EOF Re */ +#define SM_WR_LD_N2C_R 0x4 /* Write Desc. Load_N2C Re */ +#define SM_WR_WAIT_TC_R 0x5 /* Write Desc. Wait_TC Re */ +#define SM_WR_WAIT_TC4 0x6 /* Write Desc. Wait_TC4 Re */ +#define SM_WR_LD_A_T 0x6 /* Write Desc. Load_A Tr */ +#define SM_WR_LD_A_R 0x7 /* Write Desc. Load_A Re */ +#define SM_WR_WAIT_TC_T 0x7 /* Write Desc. Wait_TC Tr */ +#define SM_WR_LD_N2C_T 0xc /* Write Desc. Load_N2C Tr */ +#define SM_WR_WDONE_T 0x9 /* Write Desc. Wait_Done Tr */ +#define SM_WR_WDONE_R 0xc /* Write Desc. Wait_Done Re */ +#define SM_WR_LD_D_AD 0xe /* Write Desc. Load_Dumr_A Re (ML) */ +#define SM_WR_WAIT_D_TC 0xf /* Write Desc. Wait_Dumr_TC Re (ML) */ + +/* B5__T2 32 bit Test Register 2 (xx) */ +/* Note: This register is only defined for the transmit queues */ + /* Bit 31..8: reserved */ +#define AC_TEST_ON (1<<7) /* Bit 7: Address Counter Test Mode on */ +#define AC_TEST_OFF (1<<6) /* Bit 6: Address Counter Test Mode off*/ +#define BC_TEST_ON (1<<5) /* Bit 5: Byte Counter Test Mode on */ +#define BC_TEST_OFF (1<<4) /* Bit 4: Byte Counter Test Mode off */ +#define TEST_STEP04 (1<<3) /* Bit 3: Inc AC/Dec BC by 4 */ +#define TEST_STEP03 (1<<2) /* Bit 2: Inc AC/Dec BC by 3 */ +#define TEST_STEP02 (1<<1) /* Bit 1: Inc AC/Dec BC by 2 */ +#define TEST_STEP01 (1<<0) /* Bit 0: Inc AC/Dec BC by 1 */ + +/* B5__T3 32 bit Test Register 3 (xx) */ +/* Note: This register is only defined for the transmit queues */ + /* Bit 31..8: reserved */ +#define T3_MUX_2 (1<<7) /* Bit 7: (ML) Mux position MSB */ +#define T3_VRAM_2 (1<<6) /* Bit 6: (ML) Virtual RAM buffer addr MSB */ +#define T3_LOOP (1<<5) /* Bit 5: Set Loopback (Xmit) */ +#define T3_UNLOOP (1<<4) /* Bit 4: Unset Loopback (Xmit) */ +#define T3_MUX (3<<2) /* Bit 3..2: Mux position */ +#define T3_VRAM (3<<0) /* Bit 1..0: Virtual RAM buffer Address */ + +/* PCI card IDs */ +/* + * Note: The following 4 byte definitions shall not be used! Use OEM Concept! + */ +#define PCI_VEND_ID0 0x48 /* PCI vendor ID (SysKonnect) */ +#define PCI_VEND_ID1 0x11 /* PCI vendor ID (SysKonnect) */ + /* (High byte) */ +#define PCI_DEV_ID0 0x00 /* PCI device ID */ +#define PCI_DEV_ID1 0x40 /* PCI device ID (High byte) */ + +/*#define PCI_CLASS 0x02*/ /* PCI class code: network device */ +#define PCI_NW_CLASS 0x02 /* PCI class code: network device */ +#define PCI_SUB_CLASS 0x02 /* PCI subclass ID: FDDI device */ +#define PCI_PROG_INTFC 0x00 /* PCI programming Interface (=0) */ + +/* + * address transmision from logical to physical offset address on board + */ +#define FMA(a) (0x0400|((a)<<2)) /* FORMAC+ (r/w) (SN3) */ +#define P1(a) (0x0380|((a)<<2)) /* PLC1 (r/w) (DAS) */ +#define P2(a) (0x0600|((a)<<2)) /* PLC2 (r/w) (covered by the SN3) */ +#define PRA(a) (B2_MAC_0 + (a)) /* configuration PROM (MAC address) */ + +/* + * FlashProm specification + */ +#define MAX_PAGES 0x20000L /* Every byte has a single page */ +#define MAX_FADDR 1 /* 1 byte per page */ + +/* + * Receive / Transmit Buffer Control word + */ +#define BMU_OWN (1UL<<31) /* OWN bit: 0 == host, 1 == adapter */ +#define BMU_STF (1L<<30) /* Start of Frame ? */ +#define BMU_EOF (1L<<29) /* End of Frame ? */ +#define BMU_EN_IRQ_EOB (1L<<28) /* Enable "End of Buffer" IRQ */ +#define BMU_EN_IRQ_EOF (1L<<27) /* Enable "End of Frame" IRQ */ +#define BMU_DEV_0 (1L<<26) /* RX: don't transfer to system mem */ +#define BMU_SMT_TX (1L<<25) /* TX: if set, buffer type SMT_MBuf */ +#define BMU_ST_BUF (1L<<25) /* RX: copy of start of frame */ +#define BMU_UNUSED (1L<<24) /* Set if the Descr is curr unused */ +#define BMU_SW (3L<<24) /* 2 Bits reserved for SW usage */ +#define BMU_CHECK 0x00550000L /* To identify the control word */ +#define BMU_BBC 0x0000FFFFL /* R/T Buffer Byte Count */ + +/* + * physical address offset + IO-Port base address + */ +#ifdef MEM_MAPPED_IO +#define ADDR(a) (char far *) smc->hw.iop+(a) +#define ADDRS(smc,a) (char far *) (smc)->hw.iop+(a) +#else +#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), \ + (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \ + (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) +#define ADDRS(smc,a) (((a)>>7) ? (outp((smc)->hw.iop+B0_RAP,(a)>>7), \ + ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \ + ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) +#endif + +/* + * Define a macro to access the configuration space + */ +#define PCI_C(a) ADDR(B3_CFG_SPC + (a)) /* PCI Config Space */ + +#define EXT_R(a) ADDR(B6_EXT_REG + (a)) /* External Registers */ + +/* + * Define some values needed for the MAC address (PROM) + */ +#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (0) /* offset correction when 4th byte reading */ + +#define SKFDDI_PSZ 8 /* address PROM size */ + +#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */ +#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */ +#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */ +#define PR_A(a) ADDR(PRA(a)) /* config. PROM (MAC address) */ + +/* + * Macro to read the PROM + */ +#define READ_PROM(a) ((u_char)inp(a)) + +#define GET_PAGE(bank) outpd(ADDR(B2_FAR),bank) +#define VPP_ON() +#define VPP_OFF() + +/* + * Note: Values of the Interrupt Source Register are defined above + */ +#define ISR_A ADDR(B0_ISRC) +#define GET_ISR() inpd(ISR_A) +#define GET_ISR_SMP(iop) inpd((iop)+B0_ISRC) +#define CHECK_ISR() (inpd(ISR_A) & inpd(ADDR(B0_IMSK))) +#define CHECK_ISR_SMP(iop) (inpd((iop)+B0_ISRC) & inpd((iop)+B0_IMSK)) + +#define BUS_CHECK() + +/* + * CLI_FBI: Disable Board Interrupts + * STI_FBI: Enable Board Interrupts + */ +#ifndef UNIX +#define CLI_FBI() outpd(ADDR(B0_IMSK),0) +#else +#define CLI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),0) +#endif + +#ifndef UNIX +#define STI_FBI() outpd(ADDR(B0_IMSK),smc->hw.is_imask) +#else +#define STI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),(smc)->hw.is_imask) +#endif + +#define CLI_FBI_SMP(iop) outpd((iop)+B0_IMSK,0) +#define STI_FBI_SMP(smc,iop) outpd((iop)+B0_IMSK,(smc)->hw.is_imask) + +#endif /* PCI */ +/*--------------------------------------------------------------------------*/ + +/* + * 12 bit transfer (dword) counter: + * (ISA: 2*trc = number of byte) + * (EISA: 4*trc = number of byte) + * (MCA: 4*trc = number of byte) + */ +#define MAX_TRANS (0x0fff) + +/* + * PC PIC + */ +#define MST_8259 (0x20) +#define SLV_8259 (0xA0) + +#define TPS (18) /* ticks per second */ + +/* + * error timer defs + */ +#define TN (4) /* number of supported timer = TN+1 */ +#define SNPPND_TIME (5) /* buffer memory access over mem. data reg. */ + +#define MAC_AD 0x405a0000 + +#define MODR1 FM_A(FM_MDREG1) /* mode register 1 */ +#define MODR2 FM_A(FM_MDREG2) /* mode register 2 */ + +#define CMDR1 FM_A(FM_CMDREG1) /* command register 1 */ +#define CMDR2 FM_A(FM_CMDREG2) /* command register 2 */ + + +/* + * function defines + */ +#define CLEAR(io,mask) outpw((io),inpw(io)&(~(mask))) +#define SET(io,mask) outpw((io),inpw(io)|(mask)) +#define GET(io,mask) (inpw(io)&(mask)) +#define SETMASK(io,val,mask) outpw((io),(inpw(io) & ~(mask)) | (val)) + +/* + * PHY Port A (PA) = PLC 1 + * With SuperNet 3 PHY-A and PHY S are identical. + */ +#define PLC(np,reg) (((np) == PA) ? P2_A(reg) : P1_A(reg)) + +/* + * set memory address register for write and read + */ +#define MARW(ma) outpw(FM_A(FM_MARW),(unsigned int)(ma)) +#define MARR(ma) outpw(FM_A(FM_MARR),(unsigned int)(ma)) + +/* + * read/write from/to memory data register + */ +/* write double word */ +#define MDRW(dd) outpw(FM_A(FM_MDRU),(unsigned int)((dd)>>16)) ;\ + outpw(FM_A(FM_MDRL),(unsigned int)(dd)) + +#ifndef WINNT +/* read double word */ +#define MDRR() (((long)inpw(FM_A(FM_MDRU))<<16) + inpw(FM_A(FM_MDRL))) + +/* read FORMAC+ 32-bit status register */ +#define GET_ST1() (((long)inpw(FM_A(FM_ST1U))<<16) + inpw(FM_A(FM_ST1L))) +#define GET_ST2() (((long)inpw(FM_A(FM_ST2U))<<16) + inpw(FM_A(FM_ST2L))) +#ifdef SUPERNET_3 +#define GET_ST3() (((long)inpw(FM_A(FM_ST3U))<<16) + inpw(FM_A(FM_ST3L))) +#endif +#else +/* read double word */ +#define MDRR() inp2w((FM_A(FM_MDRU)),(FM_A(FM_MDRL))) + +/* read FORMAC+ 32-bit status register */ +#define GET_ST1() inp2w((FM_A(FM_ST1U)),(FM_A(FM_ST1L))) +#define GET_ST2() inp2w((FM_A(FM_ST2U)),(FM_A(FM_ST2L))) +#ifdef SUPERNET_3 +#define GET_ST3() inp2w((FM_A(FM_ST3U)),(FM_A(FM_ST3L))) +#endif +#endif + +/* Special timer macro for 82c54 */ + /* timer access over data bus bit 8..15 */ +#define OUT_82c54_TIMER(port,val) outpw(TI_A(port),(val)<<8) +#define IN_82c54_TIMER(port) ((inpw(TI_A(port))>>8) & 0xff) + + +#ifdef DEBUG +#define DB_MAC(mac,st) {if (debug_mac & 0x1)\ + printf("M") ;\ + if (debug_mac & 0x2)\ + printf("\tMAC %d status 0x%08lx\n",mac,st) ;\ + if (debug_mac & 0x4)\ + dp_mac(mac,st) ;\ +} + +#define DB_PLC(p,iev) { if (debug_plc & 0x1)\ + printf("P") ;\ + if (debug_plc & 0x2)\ + printf("\tPLC %s Int 0x%04x\n", \ + (p == PA) ? "A" : "B", iev) ;\ + if (debug_plc & 0x4)\ + dp_plc(p,iev) ;\ +} + +#define DB_TIMER() { if (debug_timer & 0x1)\ + printf("T") ;\ + if (debug_timer & 0x2)\ + printf("\tTimer ISR\n") ;\ +} + +#else /* no DEBUG */ + +#define DB_MAC(mac,st) +#define DB_PLC(p,iev) +#define DB_TIMER() + +#endif /* no DEBUG */ + +#define INC_PTR(sp,cp,ep) if (++cp == ep) cp = sp +/* + * timer defs + */ +#define COUNT(t) ((t)<<6) /* counter */ +#define RW_OP(o) ((o)<<4) /* read/write operation */ +#define TMODE(m) ((m)<<1) /* timer mode */ + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/skfbiinc.h linux/drivers/net/skfp/h/skfbiinc.h --- v2.2.17/drivers/net/skfp/h/skfbiinc.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/skfbiinc.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,123 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _SKFBIINC_ +#define _SKFBIINC_ + +#include "h/supern_2.h" + +/* + * special defines for use into .asm files + */ +#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1) + +#ifdef ISA +#define DMA_BUSY_CHECK CSRA +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT) +#define HRQR (RQAA+(RQ_RRQ<<1)) +#define HRQW (RQAA+(RQ_WA2<<1)) +#define HRQA0 (RQAA+(RQ_WA0<<1)) +#define HRQSQ (RQAA+(RQ_WSQ<<1)) +#endif + +#ifdef EISA +#define DMA_BUSY_CHECK CSRA +#define DMA_HIGH_WORD 0x0400 +#define DMA_MASK_M 0x0a +#define DMA_MODE_M 0x0b +#define DMA_BYTE_PTR_M 0x0c +#define DMA_MASK_S 0x0d4 +#define DMA_MODE_S 0x0d6 +#define DMA_BYTE_PTR_S 0x0d8 +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC) +#endif /* EISA */ + +#ifdef MCA +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_CHCK_L | IS_BUSERR) +#endif + +#ifdef PCI +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ + IS_R1_C | IS_XA_C | IS_XS_C) +#endif + +#ifdef PCI +#define ISR_MASK (IS_MINTR1 | IS_R1_F | IS_XS_F| IS_XA_F | IMASK_FAST) +#else +#define ISR_MASK (IS_MINTR1 | IS_MINTR2 | IMASK_FAST) +#endif + +#define FMA_FM_CMDREG1 FMA(FM_CMDREG1) +#define FMA_FM_CMDREG2 FMA(FM_CMDREG2) +#define FMA_FM_STMCHN FMA(FM_STMCHN) +#define FMA_FM_RPR FMA(FM_RPR) +#define FMA_FM_WPXA0 FMA(FM_WPXA0) +#define FMA_FM_WPXA2 FMA(FM_WPXA2) +#define FMA_FM_MARR FMA(FM_MARR) +#define FMA_FM_MARW FMA(FM_MARW) +#define FMA_FM_MDRU FMA(FM_MDRU) +#define FMA_FM_MDRL FMA(FM_MDRL) +#define FMA_ST1L FMA(FM_ST1L) +#define FMA_ST1U FMA(FM_ST1U) +#define FMA_ST2L FMA(FM_ST2L) +#define FMA_ST2U FMA(FM_ST2U) +#ifdef SUPERNET_3 +#define FMA_ST3L FMA(FM_ST3L) +#define FMA_ST3U FMA(FM_ST3U) +#endif + +#define TMODE_RRQ RQ_RRQ +#define TMODE_WAQ2 RQ_WA2 +#define HSRA HSR(0) + + +#define FMA_FM_ST1L FMA_ST1L +#define FMA_FM_ST1U FMA_ST1U +#define FMA_FM_ST2L FMA_ST2L +#define FMA_FM_ST2U FMA_ST2U +#ifdef SUPERNET_3 +#define FMA_FM_ST3L FMA_ST3L +#define FMA_FM_ST3U FMA_ST3U +#endif + +#define FMA_FM_SWPR FMA(FM_SWPR) + +#define FMA_FM_RPXA0 FMA(FM_RPXA0) + +#define FMA_FM_RPXS FMA(FM_RPXS) +#define FMA_FM_WPXS FMA(FM_WPXS) + +#define FMA_FM_IMSK1U FMA(FM_IMSK1U) +#define FMA_FM_IMSK1L FMA(FM_IMSK1L) + +#define FMA_FM_EAS FMA(FM_EAS) +#define FMA_FM_EAA0 FMA(FM_EAA0) + +#define TMODE_WAQ0 RQ_WA0 +#define TMODE_WSQ RQ_WSQ + +/* Define default for DRV_PCM_STATE_CHANGE */ +#ifndef DRV_PCM_STATE_CHANGE +#define DRV_PCM_STATE_CHANGE(smc,plc,p_state) /* nothing */ +#endif + +/* Define default for DRV_RMT_INDICATION */ +#ifndef DRV_RMT_INDICATION +#define DRV_RMT_INDICATION(smc,i) /* nothing */ +#endif + +#endif /* n_SKFBIINC_ */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/smc.h linux/drivers/net/skfp/h/smc.h --- v2.2.17/drivers/net/skfp/h/smc.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/smc.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,471 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _SCMECM_ +#define _SCMECM_ + +#if defined(PCI) && !defined(OSDEF) +/* + * In the case of the PCI bus the file osdef1st.h must be present + */ +#define OSDEF +#endif + +#ifdef PCI +#ifndef SUPERNET_3 +#define SUPERNET_3 +#endif +#ifndef TAG_MODE +#define TAG_MODE +#endif +#endif + +/* + * include all other files in required order + * the following files must have been included before: + * types.h + * fddi.h + */ +#ifdef OSDEF +#include "h/osdef1st.h" +#endif /* OSDEF */ +#ifdef OEM_CONCEPT +#include "oemdef.h" +#endif /* OEM_CONCEPT */ +#include "h/smt.h" +#include "h/cmtdef.h" +#include "h/fddimib.h" +#include "h/targethw.h" /* all target hw dependencies */ +#include "h/targetos.h" /* all target os dependencies */ +#ifdef ESS +#include "h/sba.h" +#endif + +/* + * Event Queue + * queue.c + * events are class/value pairs + * class is addressee, e.g. RMT, PCM etc. + * value is command, e.g. line state change, ring op change etc. + */ +struct event_queue { + u_short class ; /* event class */ + u_short event ; /* event value */ +} ; + +/* + * define event queue as circular buffer + */ +#ifdef CONCENTRATOR +#define MAX_EVENT 128 +#else /* nCONCENTRATOR */ +#define MAX_EVENT 64 +#endif /* nCONCENTRATOR */ + +struct s_queue { + + struct event_queue ev_queue[MAX_EVENT]; + struct event_queue *ev_put ; + struct event_queue *ev_get ; +} ; + +/* + * ECM - Entity Coordination Management + * ecm.c + */ +struct s_ecm { + u_char path_test ; /* ECM path test variable */ + u_char sb_flag ; /* ECM stuck bypass */ + u_char DisconnectFlag ; /* jd 05-Aug-1999 Bug #10419 + * ECM disconnected */ + u_char ecm_line_state ; /* flag to dispatcher : line states */ + u_long trace_prop ; /* ECM Trace_Prop flag >= 16 bits !! */ + /* NUMPHYS note: + * this variable must have enough bits to hold all entiies in + * the station. So NUMPHYS may not be greater than 31. + */ + char ec_pad[2] ; + struct smt_timer ecm_timer ; /* timer */ +} ; + + +/* + * RMT - Ring Management + * rmt.c + */ +struct s_rmt { + u_char dup_addr_test ; /* state of dupl. addr. test */ + u_char da_flag ; /* flag : duplicate address det. */ + u_char loop_avail ; /* flag : MAC available for loopback */ + u_char sm_ma_avail ; /* flag : MAC available for SMT */ + u_char no_flag ; /* flag : ring not operational */ + u_char bn_flag ; /* flag : MAC reached beacon state */ + u_char jm_flag ; /* flag : jamming in NON_OP_DUP */ + u_char rm_join ; /* CFM flag RM_Join */ + u_char rm_loop ; /* CFM flag RM_Loop */ + + long fast_rm_join ; /* bit mask of active ports */ + /* + * timer and flags + */ + struct smt_timer rmt_timer0 ; /* timer 0 */ + struct smt_timer rmt_timer1 ; /* timer 1 */ + struct smt_timer rmt_timer2 ; /* timer 2 */ + u_char timer0_exp ; /* flag : timer 0 expired */ + u_char timer1_exp ; /* flag : timer 1 expired */ + u_char timer2_exp ; /* flag : timer 2 expired */ + + u_char rm_pad1[1] ; +} ; + +/* + * CFM - Configuration Management + * cfm.c + * used for SAS and DAS + */ +struct s_cfm { + u_char cf_state; /* CFM state machine current state */ + u_char cf_pad[3] ; +} ; + +/* + * CEM - Configuration Element Management + * cem.c + * used for Concentrator + */ +#ifdef CONCENTRATOR +struct s_cem { + int ce_state ; /* CEM state */ + int ce_port ; /* PA PB PM PM+1 .. */ + int ce_type ; /* TA TB TS TM */ +} ; + +/* + * linked list of CCEs in current token path + */ +struct s_c_ring { + struct s_c_ring *c_next ; + char c_entity ; +} ; + +struct mib_path_config { + u_long fddimibPATHConfigSMTIndex; + u_long fddimibPATHConfigPATHIndex; + u_long fddimibPATHConfigTokenOrder; + u_long fddimibPATHConfigResourceType; +#define SNMP_RES_TYPE_MAC 2 /* Resource is a MAC */ +#define SNMP_RES_TYPE_PORT 4 /* Resource is a PORT */ + u_long fddimibPATHConfigResourceIndex; + u_long fddimibPATHConfigCurrentPath; +#define SNMP_PATH_ISOLATED 1 /* Current path is isolated */ +#define SNMP_PATH_LOCAL 2 /* Current path is local */ +#define SNMP_PATH_SECONDARY 3 /* Current path is secondary */ +#define SNMP_PATH_PRIMARY 4 /* Current path is primary */ +#define SNMP_PATH_CONCATENATED 5 /* Current path is concatenated */ +#define SNMP_PATH_THRU 6 /* Current path is thru */ +}; + + +#endif + +/* + * PCM connect states + */ +#define PCM_DISABLED 0 +#define PCM_CONNECTING 1 +#define PCM_STANDBY 2 +#define PCM_ACTIVE 3 + +struct s_pcm { + u_char pcm_pad[3] ; +} ; + +/* + * PHY struct + * one per physical port + */ +struct s_phy { + /* Inter Module Globals */ + struct fddi_mib_p *mib ; + + u_char np ; /* index 0 .. NUMPHYS */ + u_char cf_join ; + u_char cf_loop ; + u_char wc_flag ; /* withhold connection flag */ + u_char pc_mode ; /* Holds the negotiated mode of the PCM */ + u_char pc_lem_fail ; /* flag : LCT failed */ + u_char lc_test ; + u_char scrub ; /* CFM flag Scrub -> PCM */ + char phy_name ; + u_char pmd_type[2] ; /* SK connector/transceiver type codes */ +#define PMD_SK_CONN 0 /* pmd_type[PMD_SK_CONN] = Connector */ +#define PMD_SK_PMD 1 /* pmd_type[PMD_SK_PMD] = Xver */ + u_char pmd_scramble ; /* scrambler on/off */ + + /* inner Module Globals */ + u_char curr_ls ; /* current line state */ + u_char ls_flag ; + u_char rc_flag ; + u_char tc_flag ; + u_char td_flag ; + u_char bitn ; + u_char tr_flag ; /* trace recvd while in active */ + u_char twisted ; /* flag to indicate an A-A or B-B connection */ + u_char t_val[NUMBITS] ; /* transmit bits for signaling */ + u_char r_val[NUMBITS] ; /* receive bits for signaling */ + u_long t_next[NUMBITS] ; + struct smt_timer pcm_timer0 ; + struct smt_timer pcm_timer1 ; + struct smt_timer pcm_timer2 ; + u_char timer0_exp ; + u_char timer1_exp ; + u_char timer2_exp ; + u_char pcm_pad1[1] ; + int cem_pst ; /* CEM privae state; used for dual homing */ + struct lem_counter lem ; +#ifdef AMDPLC + struct s_plc plc ; +#endif +} ; + +/* + * timer package + * smttimer.c + */ +struct s_timer { + struct smt_timer *st_queue ; + struct smt_timer st_fast ; +} ; + +/* + * SRF types and data + */ +#define SMT_EVENT_BASE 1 +#define SMT_EVENT_MAC_PATH_CHANGE (SMT_EVENT_BASE+0) +#define SMT_EVENT_MAC_NEIGHBOR_CHANGE (SMT_EVENT_BASE+1) +#define SMT_EVENT_PORT_PATH_CHANGE (SMT_EVENT_BASE+2) +#define SMT_EVENT_PORT_CONNECTION (SMT_EVENT_BASE+3) + +#define SMT_IS_CONDITION(x) ((x)>=SMT_COND_BASE) + +#define SMT_COND_BASE (SMT_EVENT_PORT_CONNECTION+1) +#define SMT_COND_SMT_PEER_WRAP (SMT_COND_BASE+0) +#define SMT_COND_SMT_HOLD (SMT_COND_BASE+1) +#define SMT_COND_MAC_FRAME_ERROR (SMT_COND_BASE+2) +#define SMT_COND_MAC_DUP_ADDR (SMT_COND_BASE+3) +#define SMT_COND_MAC_NOT_COPIED (SMT_COND_BASE+4) +#define SMT_COND_PORT_EB_ERROR (SMT_COND_BASE+5) +#define SMT_COND_PORT_LER (SMT_COND_BASE+6) + +#define SR0_WAIT 0 +#define SR1_HOLDOFF 1 +#define SR2_DISABLED 2 + +struct s_srf { + u_long SRThreshold ; /* threshold value */ + u_char RT_Flag ; /* report transmitted flag */ + u_char sr_state ; /* state-machine */ + u_char any_report ; /* any report required */ + u_long TSR ; /* timer */ + u_short ring_status ; /* IBM ring status */ +} ; + +/* + * IBM token ring status + */ +#define RS_RES15 (1<<15) /* reserved */ +#define RS_HARDERROR (1<<14) /* ring down */ +#define RS_SOFTERROR (1<<13) /* sent SRF */ +#define RS_BEACON (1<<12) /* transmitted beacon */ +#define RS_PATHTEST (1<<11) /* path test failed */ +#define RS_SELFTEST (1<<10) /* selftest required */ +#define RS_RES9 (1<< 9) /* reserved */ +#define RS_DISCONNECT (1<< 8) /* remote disconnect */ +#define RS_RES7 (1<< 7) /* reserved */ +#define RS_DUPADDR (1<< 6) /* duplicate address */ +#define RS_NORINGOP (1<< 5) /* no ring op */ +#define RS_VERSION (1<< 4) /* SMT version mismatch */ +#define RS_STUCKBYPASSS (1<< 3) /* stuck bypass */ +#define RS_EVENT (1<< 2) /* FDDI event occured */ +#define RS_RINGOPCHANGE (1<< 1) /* ring op changed */ +#define RS_RES0 (1<< 0) /* reserved */ + +#define RS_SET(smc,bit) \ + ring_status_indication(smc,smc->srf.ring_status |= bit) +#define RS_CLEAR(smc,bit) \ + ring_status_indication(smc,smc->srf.ring_status &= ~bit) + +#define RS_CLEAR_EVENT (0xffff & ~(RS_NORINGOP)) + +/* Define the AIX-event-Notification as null function if it isn't defined */ +/* in the targetos.h file */ +#ifndef AIX_EVENT +#define AIX_EVENT(smc,opt0,opt1,opt2,opt3) /* nothing */ +#endif + +struct s_srf_evc { + u_char evc_code ; /* event code type */ + u_char evc_index ; /* index for mult. instances */ + u_char evc_rep_required ; /* report required */ + u_short evc_para ; /* SMT Para Number */ + u_char *evc_cond_state ; /* condition state */ + u_char *evc_multiple ; /* multiple occurence */ +} ; + +/* + * Values used by frame based services + * smt.c + */ +#define SMT_MAX_TEST 5 +#define SMT_TID_NIF 0 /* pending NIF request */ +#define SMT_TID_NIF_TEST 1 /* pending NIF test */ +#define SMT_TID_ECF_UNA 2 /* pending ECF UNA test */ +#define SMT_TID_ECF_DNA 3 /* pending ECF DNA test */ +#define SMT_TID_ECF 4 /* pending ECF test */ + +struct smt_values { + u_long smt_tvu ; /* timer valid una */ + u_long smt_tvd ; /* timer valid dna */ + u_long smt_tid ; /* transaction id */ + u_long pend[SMT_MAX_TEST] ; /* TID of requests */ + u_long uniq_time ; /* unique time stamp */ + u_short uniq_ticks ; /* unique time stamp */ + u_short please_reconnect ; /* flag : reconnect */ + u_long smt_last_lem ; + u_long smt_last_notify ; + struct smt_timer smt_timer ; /* SMT NIF timer */ + u_long last_tok_time[NUMMACS]; /* token cnt emulation */ +} ; + +/* + * SMT/CMT configurable parameters + */ +#define SMT_DAS 0 /* dual attach */ +#define SMT_SAS 1 /* single attach */ +#define SMT_NAC 2 /* null attach concentrator */ + +struct smt_config { + u_char attach_s ; /* CFM attach to secondary path */ + u_char sas ; /* SMT_DAS/SAS/NAC */ + u_char build_ring_map ; /* build ringmap if TRUE */ + u_char numphys ; /* number of active phys */ + u_char sc_pad[1] ; + + u_long pcm_tb_min ; /* PCM : TB_Min timer value */ + u_long pcm_tb_max ; /* PCM : TB_Max timer value */ + u_long pcm_c_min ; /* PCM : C_Min timer value */ + u_long pcm_t_out ; /* PCM : T_Out timer value */ + u_long pcm_tl_min ; /* PCM : TL_min timer value */ + u_long pcm_lc_short ; /* PCM : LC_Short timer value */ + u_long pcm_lc_medium ; /* PCM : LC_Medium timer value */ + u_long pcm_lc_long ; /* PCM : LC_Long timer value */ + u_long pcm_lc_extended ; /* PCM : LC_Extended timer value */ + u_long pcm_t_next_9 ; /* PCM : T_Next[9] timer value */ + u_long pcm_ns_max ; /* PCM : NS_Max timer value */ + + u_long ecm_i_max ; /* ECM : I_Max timer value */ + u_long ecm_in_max ; /* ECM : IN_Max timer value */ + u_long ecm_td_min ; /* ECM : TD_Min timer */ + u_long ecm_test_done ; /* ECM : path test done timer */ + u_long ecm_check_poll ; /* ECM : check bypass poller */ + + u_long rmt_t_non_op ; /* RMT : T_Non_OP timer value */ + u_long rmt_t_stuck ; /* RMT : T_Stuck timer value */ + u_long rmt_t_direct ; /* RMT : T_Direct timer value */ + u_long rmt_t_jam ; /* RMT : T_Jam timer value */ + u_long rmt_t_announce ; /* RMT : T_Announce timer value */ + u_long rmt_t_poll ; /* RMT : claim/beacon poller */ + u_long rmt_dup_mac_behavior ; /* Flag for the beavior of SMT if + * a Duplicate MAC Address was detected. + * FALSE: SMT will leave finaly the ring + * TRUE: SMT will reinstert into the ring + */ + u_long mac_d_max ; /* MAC : D_Max timer value */ + + u_long lct_short ; /* LCT : error threshhold */ + u_long lct_medium ; /* LCT : error threshhold */ + u_long lct_long ; /* LCT : error threshhold */ + u_long lct_extended ; /* LCT : error threshhold */ +} ; + +#ifdef DEBUG +/* + * Debugging struct sometimes used in smc + */ +struct smt_debug { + int d_smtf ; + int d_smt ; + int d_ecm ; + int d_rmt ; + int d_cfm ; + int d_pcm ; + int d_plc ; +#ifdef ESS + int d_ess ; +#endif +#ifdef SBA + int d_sba ; +#endif + struct os_debug d_os; /* Include specific OS DEBUG struct */ +} ; + +#ifndef DEBUG_BRD +/* all boards shall be debugged with one debug struct */ +extern struct smt_debug debug; /* Declaration of debug struct */ +#endif /* DEBUG_BRD */ + +#endif /* DEBUG */ + +/* + * the SMT Context Struct SMC + * this struct contains ALL global variables of SMT + */ +struct s_smc { + struct s_smt_os os ; /* os specific */ + struct s_smt_hw hw ; /* hardware */ + +/* + * NOTE: os and hw MUST BE the first two structs + * anything beyond hw WILL BE SET TO ZERO in smt_set_defaults() + */ + struct smt_config s ; /* smt constants */ + struct smt_values sm ; /* smt variables */ + struct s_ecm e ; /* ecm */ + struct s_rmt r ; /* rmt */ + struct s_cfm cf ; /* cfm/cem */ +#ifdef CONCENTRATOR + struct s_cem ce[NUMPHYS] ; /* cem */ + struct s_c_ring cr[NUMPHYS+NUMMACS] ; +#endif + struct s_pcm p ; /* pcm */ + struct s_phy y[NUMPHYS] ; /* phy */ + struct s_queue q ; /* queue */ + struct s_timer t ; /* timer */ + struct s_srf srf ; /* SRF */ + struct s_srf_evc evcs[6+NUMPHYS*4] ; + struct fddi_mib mib ; /* __THE_MIB__ */ +#ifdef SBA + struct s_sba sba ; /* SBA variables */ +#endif +#ifdef ESS + struct s_ess ess ; /* Ess variables */ +#endif +#if defined(DEBUG) && defined(DEBUG_BRD) + /* If you want all single board to be debugged separately */ + struct smt_debug debug; /* Declaration of debug struct */ +#endif /* DEBUG_BRD && DEBUG */ +} ; + +#endif /* _SCMECM_ */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/smt.h linux/drivers/net/skfp/h/smt.h --- v2.2.17/drivers/net/skfp/h/smt.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/smt.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,882 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * SMT 7.2 frame definitions + */ + +#ifndef _SMT_ +#define _SMT_ + +/* #define SMT5_10 */ +#define SMT6_10 +#define SMT7_20 + +#define OPT_PMF /* if parameter management is supported */ +#define OPT_SRF /* if status report is supported */ + +/* + * SMT frame version 5.1 + */ + +#define SMT_VID 0x0001 /* V 5.1 .. 6.1 */ +#define SMT_VID_2 0x0002 /* V 7.2 */ + +struct smt_sid { + u_char sid_oem[2] ; /* implementation spec. */ + struct fddi_addr sid_node ; /* node address */ +} ; + +typedef u_char t_station_id[8] ; + +/* + * note on alignment : + * sizeof(struct smt_header) = 32 + * all parameters are long aligned + * if struct smt_header starts at offset 0, all longs are aligned correctly + * (FC starts at offset 3) + */ +_packed struct smt_header { + struct fddi_addr smt_dest ; /* destination address */ + struct fddi_addr smt_source ; /* source address */ + u_char smt_class ; /* NIF, SIF ... */ + u_char smt_type ; /* req., response .. */ + u_short smt_version ; /* version id */ + u_int smt_tid ; /* transaction ID */ + struct smt_sid smt_sid ; /* station ID */ + u_short smt_pad ; /* pad with 0 */ + u_short smt_len ; /* length of info field */ +} ; +#define SWAP_SMTHEADER "662sl8ss" + +#if 0 +/* + * MAC FC values + */ +#define FC_SMT_INFO 0x41 /* SMT info */ +#define FC_SMT_NSA 0x4f /* SMT Next Station Addressing */ +#endif + + +/* + * type codes + */ +#define SMT_ANNOUNCE 0x01 /* announcement */ +#define SMT_REQUEST 0x02 /* request */ +#define SMT_REPLY 0x03 /* reply */ + +/* + * class codes + */ +#define SMT_NIF 0x01 /* neighbor information frames */ +#define SMT_SIF_CONFIG 0x02 /* station information configuration */ +#define SMT_SIF_OPER 0x03 /* station information operation */ +#define SMT_ECF 0x04 /* echo frames */ +#define SMT_RAF 0x05 /* resource allocation */ +#define SMT_RDF 0x06 /* request denied */ +#define SMT_SRF 0x07 /* status report */ +#define SMT_PMF_GET 0x08 /* parameter management get */ +#define SMT_PMF_SET 0x09 /* parameter management set */ +#define SMT_ESF 0xff /* extended service */ + +#define SMT_MAX_ECHO_LEN 4458 /* max length of SMT Echo */ +#if defined(CONC) || defined(CONC_II) +#define SMT_TEST_ECHO_LEN 50 /* test length of SMT Echo */ +#else +#define SMT_TEST_ECHO_LEN SMT_MAX_ECHO_LEN /* test length */ +#endif + +#define SMT_MAX_INFO_LEN (4352-20) /* max length for SMT info */ + + +/* + * parameter types + */ + +struct smt_para { + u_short p_type ; /* type */ + u_short p_len ; /* length of parameter */ +} ; + +#define PARA_LEN (sizeof(struct smt_para)) + +#define SMTSETPARA(p,t) (p)->para.p_type = (t),\ + (p)->para.p_len = sizeof(*(p)) - PARA_LEN + +/* + * P01 : Upstream Neighbor Address, UNA + */ +#define SMT_P_UNA 0x0001 /* upstream neighbor address */ +#define SWAP_SMT_P_UNA "s6" + +struct smt_p_una { + struct smt_para para ; /* generic parameter header */ + u_short una_pad ; + struct fddi_addr una_node ; /* node address, zero if unknown */ +} ; + +/* + * P02 : Station Descriptor + */ +#define SMT_P_SDE 0x0002 /* station descriptor */ +#define SWAP_SMT_P_SDE "1111" + +#define SMT_SDE_STATION 0 /* end node */ +#define SMT_SDE_CONCENTRATOR 1 /* concentrator */ + +struct smt_p_sde { + struct smt_para para ; /* generic parameter header */ + u_char sde_type ; /* station type */ + u_char sde_mac_count ; /* number of MACs */ + u_char sde_non_master ; /* number of A,B or S ports */ + u_char sde_master ; /* number of S ports on conc. */ +} ; + +/* + * P03 : Station State + */ +#define SMT_P_STATE 0x0003 /* station state */ +#define SWAP_SMT_P_STATE "scc" + +struct smt_p_state { + struct smt_para para ; /* generic parameter header */ + u_short st_pad ; + u_char st_topology ; /* topology */ + u_char st_dupl_addr ; /* duplicate address detected */ +} ; +#define SMT_ST_WRAPPED (1<<0) /* station wrapped */ +#define SMT_ST_UNATTACHED (1<<1) /* unattached concentrator */ +#define SMT_ST_TWISTED_A (1<<2) /* A-A connection, twisted ring */ +#define SMT_ST_TWISTED_B (1<<3) /* B-B connection, twisted ring */ +#define SMT_ST_ROOTED_S (1<<4) /* rooted station */ +#define SMT_ST_SRF (1<<5) /* SRF protocol supported */ +#define SMT_ST_SYNC_SERVICE (1<<6) /* use synchronous bandwidth */ + +#define SMT_ST_MY_DUPA (1<<0) /* my station detected dupl. */ +#define SMT_ST_UNA_DUPA (1<<1) /* my UNA detected duplicate */ + +/* + * P04 : timestamp + */ +#define SMT_P_TIMESTAMP 0x0004 /* time stamp */ +#define SWAP_SMT_P_TIMESTAMP "8" +struct smt_p_timestamp { + struct smt_para para ; /* generic parameter header */ + u_char ts_time[8] ; /* time, resolution 80nS, unique */ +} ; + +/* + * P05 : station policies + */ +#define SMT_P_POLICY 0x0005 /* station policies */ +#define SWAP_SMT_P_POLICY "ss" + +struct smt_p_policy { + struct smt_para para ; /* generic parameter header */ + u_short pl_config ; + u_short pl_connect ; /* bit string POLICY_AA ... */ +} ; +#define SMT_PL_HOLD 1 /* hold policy supported (Dual MAC) */ + +/* + * P06 : latency equivalent + */ +#define SMT_P_LATENCY 0x0006 /* latency */ +#define SWAP_SMT_P_LATENCY "ssss" + +/* + * note: latency has two phy entries by definition + * for a SAS, the 2nd one is null + */ +struct smt_p_latency { + struct smt_para para ; /* generic parameter header */ + u_short lt_phyout_idx1 ; /* index */ + u_short lt_latency1 ; /* latency , unit : byte clock */ + u_short lt_phyout_idx2 ; /* 0 if SAS */ + u_short lt_latency2 ; /* 0 if SAS */ +} ; + +/* + * P07 : MAC neighbors + */ +#define SMT_P_NEIGHBORS 0x0007 /* MAC neighbor description */ +#define SWAP_SMT_P_NEIGHBORS "ss66" + +struct smt_p_neighbor { + struct smt_para para ; /* generic parameter header */ + u_short nb_mib_index ; /* MIB index */ + u_short nb_mac_index ; /* n+1 .. n+m, m = #MACs, n = #PHYs */ + struct fddi_addr nb_una ; /* UNA , 0 for unknown */ + struct fddi_addr nb_dna ; /* DNA , 0 for unknown */ +} ; + +/* + * PHY record + */ +#define SMT_PHY_A 0 /* A port */ +#define SMT_PHY_B 1 /* B port */ +#define SMT_PHY_S 2 /* slave port */ +#define SMT_PHY_M 3 /* master port */ + +#define SMT_CS_DISABLED 0 /* connect state : disabled */ +#define SMT_CS_CONNECTING 1 /* connect state : connecting */ +#define SMT_CS_STANDBY 2 /* connect state : stand by */ +#define SMT_CS_ACTIVE 3 /* connect state : active */ + +#define SMT_RM_NONE 0 +#define SMT_RM_MAC 1 + +struct smt_phy_rec { + u_short phy_mib_index ; /* MIB index */ + u_char phy_type ; /* A/B/S/M */ + u_char phy_connect_state ; /* disabled/connecting/active */ + u_char phy_remote_type ; /* A/B/S/M */ + u_char phy_remote_mac ; /* none/remote */ + u_short phy_resource_idx ; /* 1 .. n */ +} ; + +/* + * MAC record + */ +struct smt_mac_rec { + struct fddi_addr mac_addr ; /* MAC address */ + u_short mac_resource_idx ; /* n+1 .. n+m */ +} ; + +/* + * P08 : path descriptors + * should be really an array ; however our environment has a fixed number of + * PHYs and MACs + */ +#define SMT_P_PATH 0x0008 /* path descriptor */ +#define SWAP_SMT_P_PATH "[6s]" + +struct smt_p_path { + struct smt_para para ; /* generic parameter header */ + struct smt_phy_rec pd_phy[2] ; /* PHY A */ + struct smt_mac_rec pd_mac ; /* MAC record */ +} ; + +/* + * P09 : MAC status + */ +#define SMT_P_MAC_STATUS 0x0009 /* MAC status */ +#define SWAP_SMT_P_MAC_STATUS "sslllllllll" + +struct smt_p_mac_status { + struct smt_para para ; /* generic parameter header */ + u_short st_mib_index ; /* MIB index */ + u_short st_mac_index ; /* n+1 .. n+m */ + u_int st_t_req ; /* T_Req */ + u_int st_t_neg ; /* T_Neg */ + u_int st_t_max ; /* T_Max */ + u_int st_tvx_value ; /* TVX_Value */ + u_int st_t_min ; /* T_Min */ + u_int st_sba ; /* synchr. bandwidth alloc */ + u_int st_frame_ct ; /* frame counter */ + u_int st_error_ct ; /* error counter */ + u_int st_lost_ct ; /* lost frames counter */ +} ; + +/* + * P0A : PHY link error rate monitoring + */ +#define SMT_P_LEM 0x000a /* link error monitor */ +#define SWAP_SMT_P_LEM "ssccccll" +/* + * units of lem_cutoff,lem_alarm,lem_estimate : 10**-x + */ +struct smt_p_lem { + struct smt_para para ; /* generic parameter header */ + u_short lem_mib_index ; /* MIB index */ + u_short lem_phy_index ; /* 1 .. n */ + u_char lem_pad2 ; /* be nice and make it even . */ + u_char lem_cutoff ; /* 0x4 .. 0xf, default 0x7 */ + u_char lem_alarm ; /* 0x4 .. 0xf, default 0x8 */ + u_char lem_estimate ; /* 0x0 .. 0xff */ + u_int lem_reject_ct ; /* 0x00000000 .. 0xffffffff */ + u_int lem_ct ; /* 0x00000000 .. 0xffffffff */ +} ; + +/* + * P0B : MAC frame counters + */ +#define SMT_P_MAC_COUNTER 0x000b /* MAC frame counters */ +#define SWAP_SMT_P_MAC_COUNTER "ssll" + +struct smt_p_mac_counter { + struct smt_para para ; /* generic parameter header */ + u_short mc_mib_index ; /* MIB index */ + u_short mc_index ; /* mac index */ + u_int mc_receive_ct ; /* receive counter */ + u_int mc_transmit_ct ; /* transmit counter */ +} ; + +/* + * P0C : MAC frame not copied counter + */ +#define SMT_P_MAC_FNC 0x000c /* MAC frame not copied counter */ +#define SWAP_SMT_P_MAC_FNC "ssl" + +struct smt_p_mac_fnc { + struct smt_para para ; /* generic parameter header */ + u_short nc_mib_index ; /* MIB index */ + u_short nc_index ; /* mac index */ + u_int nc_counter ; /* not copied counter */ +} ; + + +/* + * P0D : MAC priority values + */ +#define SMT_P_PRIORITY 0x000d /* MAC priority values */ +#define SWAP_SMT_P_PRIORITY "ssl" + +struct smt_p_priority { + struct smt_para para ; /* generic parameter header */ + u_short pr_mib_index ; /* MIB index */ + u_short pr_index ; /* mac index */ + u_int pr_priority[7] ; /* priority values */ +} ; + +/* + * P0E : PHY elasticity buffer status + */ +#define SMT_P_EB 0x000e /* PHY EB status */ +#define SWAP_SMT_P_EB "ssl" + +struct smt_p_eb { + struct smt_para para ; /* generic parameter header */ + u_short eb_mib_index ; /* MIB index */ + u_short eb_index ; /* phy index */ + u_int eb_error_ct ; /* # of eb overflows */ +} ; + +/* + * P0F : manufacturer field + */ +#define SMT_P_MANUFACTURER 0x000f /* manufacturer field */ +#define SWAP_SMT_P_MANUFACTURER "" + +struct smp_p_manufacturer { + struct smt_para para ; /* generic parameter header */ + u_char mf_data[32] ; /* OUI + arbitrary data */ +} ; + +/* + * P10 : user field + */ +#define SMT_P_USER 0x0010 /* manufacturer field */ +#define SWAP_SMT_P_USER "" + +struct smp_p_user { + struct smt_para para ; /* generic parameter header */ + u_char us_data[32] ; /* arbitrary data */ +} ; + + + +/* + * P11 : echo data + */ +#define SMT_P_ECHODATA 0x0011 /* echo data */ +#define SWAP_SMT_P_ECHODATA "" + +struct smt_p_echo { + struct smt_para para ; /* generic parameter header */ + u_char ec_data[SMT_MAX_ECHO_LEN-4] ; /* echo data */ +} ; + +/* + * P12 : reason code + */ +#define SMT_P_REASON 0x0012 /* reason code */ +#define SWAP_SMT_P_REASON "l" + +struct smt_p_reason { + struct smt_para para ; /* generic parameter header */ + u_int rdf_reason ; /* CLASS/VERSION */ +} ; +#define SMT_RDF_CLASS 0x00000001 /* class not supported */ +#define SMT_RDF_VERSION 0x00000002 /* version not supported */ +#define SMT_RDF_SUCCESS 0x00000003 /* success (PMF) */ +#define SMT_RDF_BADSET 0x00000004 /* bad set count (PMF) */ +#define SMT_RDF_ILLEGAL 0x00000005 /* read only (PMF) */ +#define SMT_RDF_NOPARAM 0x6 /* paramter not supported (PMF) */ +#define SMT_RDF_RANGE 0x8 /* out of range */ +#define SMT_RDF_AUTHOR 0x9 /* not autohorized */ +#define SMT_RDF_LENGTH 0x0a /* length error */ +#define SMT_RDF_TOOLONG 0x0b /* length error */ +#define SMT_RDF_SBA 0x0d /* SBA denied */ + +/* + * P13 : refused frame beginning + */ +#define SMT_P_REFUSED 0x0013 /* refused frame beginning */ +#define SWAP_SMT_P_REFUSED "l" + +struct smt_p_refused { + struct smt_para para ; /* generic parameter header */ + u_int ref_fc ; /* 3 bytes 0 + FC */ + struct smt_header ref_header ; /* refused header */ +} ; + +/* + * P14 : supported SMT versions + */ +#define SMT_P_VERSION 0x0014 /* SMT supported versions */ +#define SWAP_SMT_P_VERSION "sccss" + +struct smt_p_version { + struct smt_para para ; /* generic parameter header */ + u_short v_pad ; + u_char v_n ; /* 1 .. 0xff, #versions */ + u_char v_index ; /* 1 .. 0xff, index of op. v. */ + u_short v_version[1] ; /* list of min. 1 version */ + u_short v_pad2 ; /* pad if necessary */ +} ; + +/* + * P15 : Resource Type + */ +#define SWAP_SMT_P0015 "l" + +struct smt_p_0015 { + struct smt_para para ; /* generic parameter header */ + u_int res_type ; /* recsource type */ +} ; + +#define SYNC_BW 0x00000001L /* Synchronous Bandwidth */ + +/* + * P16 : SBA Command + */ +#define SWAP_SMT_P0016 "l" + +struct smt_p_0016 { + struct smt_para para ; /* generic parameter header */ + u_int sba_cmd ; /* command for the SBA */ +} ; + +#define REQUEST_ALLOCATION 0x1 /* req allocation of sync bandwidth */ +#define REPORT_ALLOCATION 0x2 /* rep of sync bandwidth allocation */ +#define CHANGE_ALLOCATION 0x3 /* forces a station using sync band-*/ + /* width to change its current allo-*/ + /* cation */ + +/* + * P17 : SBA Payload Request + */ +#define SWAP_SMT_P0017 "l" + +struct smt_p_0017 { + struct smt_para para ; /* generic parameter header */ + int sba_pl_req ; /* total sync bandwidth measured in */ +} ; /* bytes per 125 us */ + +/* + * P18 : SBA Overhead Request + */ +#define SWAP_SMT_P0018 "l" + +struct smt_p_0018 { + struct smt_para para ; /* generic parameter header */ + int sba_ov_req ; /* total sync bandwidth req for overhead*/ +} ; /* measuered in bytes per T_Neg */ + +/* + * P19 : SBA Allocation Address + */ +#define SWAP_SMT_P0019 "s6" + +struct smt_p_0019 { + struct smt_para para ; /* generic parameter header */ + u_short sba_pad ; + struct fddi_addr alloc_addr ; /* Allocation Address */ +} ; + +/* + * P1A : SBA Category + */ +#define SWAP_SMT_P001A "l" + +struct smt_p_001a { + struct smt_para para ; /* generic parameter header */ + u_int category ; /* Allocator defined classification */ +} ; + +/* + * P1B : Maximum T_Neg + */ +#define SWAP_SMT_P001B "l" + +struct smt_p_001b { + struct smt_para para ; /* generic parameter header */ + u_int max_t_neg ; /* longest T_NEG for the sync service*/ +} ; + +/* + * P1C : Minimum SBA Segment Size + */ +#define SWAP_SMT_P001C "l" + +struct smt_p_001c { + struct smt_para para ; /* generic parameter header */ + u_int min_seg_siz ; /* smallest number of bytes per frame*/ +} ; + +/* + * P1D : SBA Allocatable + */ +#define SWAP_SMT_P001D "l" + +struct smt_p_001d { + struct smt_para para ; /* generic parameter header */ + u_int allocatable ; /* total sync bw availabel for alloc */ +} ; + +/* + * P20 0B : frame status capabilities + * NOTE: not in swap table, is used by smt.c AND PMF table + */ +#define SMT_P_FSC 0x200b +/* #define SWAP_SMT_P_FSC "ssss" */ + +struct smt_p_fsc { + struct smt_para para ; /* generic parameter header */ + u_short fsc_pad0 ; + u_short fsc_mac_index ; /* mac index 1 .. ff */ + u_short fsc_pad1 ; + u_short fsc_value ; /* FSC_TYPE[0-2] */ +} ; + +#define FSC_TYPE0 0 /* "normal" node (A/C handling) */ +#define FSC_TYPE1 1 /* Special A/C indicator forwarding */ +#define FSC_TYPE2 2 /* Special A/C indicator forwarding */ + +/* + * P00 21 : user defined authoriziation (see pmf.c) + */ +#define SMT_P_AUTHOR 0x0021 + +/* + * notification parameters + */ +#define SWAP_SMT_P1048 "ll" +struct smt_p_1048 { + u_int p1048_flag ; + u_int p1048_cf_state ; +} ; + +/* + * NOTE: all 2xxx 3xxx and 4xxx must include the INDEX in the swap string, + * even so the INDEX is NOT part of the struct. + * INDEX is already swapped in pmf.c, format in string is '4' + */ +#define SWAP_SMT_P208C "4lss66" +struct smt_p_208c { + u_int p208c_flag ; + u_short p208c_pad ; + u_short p208c_dupcondition ; + struct fddi_addr p208c_fddilong ; + struct fddi_addr p208c_fddiunalong ; +} ; + +#define SWAP_SMT_P208D "4lllll" +struct smt_p_208d { + u_int p208d_flag ; + u_int p208d_frame_ct ; + u_int p208d_error_ct ; + u_int p208d_lost_ct ; + u_int p208d_ratio ; +} ; + +#define SWAP_SMT_P208E "4llll" +struct smt_p_208e { + u_int p208e_flag ; + u_int p208e_not_copied ; + u_int p208e_copied ; + u_int p208e_not_copied_ratio ; +} ; + +#define SWAP_SMT_P208F "4ll6666s6" + +struct smt_p_208f { + u_int p208f_multiple ; + u_int p208f_nacondition ; + struct fddi_addr p208f_old_una ; + struct fddi_addr p208f_new_una ; + struct fddi_addr p208f_old_dna ; + struct fddi_addr p208f_new_dna ; + u_short p208f_curren_path ; + struct fddi_addr p208f_smt_address ; +} ; + +#define SWAP_SMT_P2090 "4lssl" + +struct smt_p_2090 { + u_int p2090_multiple ; + u_short p2090_availablepaths ; + u_short p2090_currentpath ; + u_int p2090_requestedpaths ; +} ; + +/* + * NOTE: + * special kludge for parameters 320b,320f,3210 + * these parameters are part of RAF frames + * RAF frames are parsed in SBA.C and must be swapped + * PMF.C has special code to avoid double swapping + */ +#ifdef LITTLE_ENDIAN +#define SBAPATHINDEX (0x01000000L) +#else +#define SBAPATHINDEX (0x01L) +#endif + +#define SWAP_SMT_P320B "42s" + +struct smt_p_320b { + struct smt_para para ; /* generic parameter header */ + u_int mib_index ; + u_short path_pad ; + u_short path_index ; +} ; + +#define SWAP_SMT_P320F "4l" + +struct smt_p_320f { + struct smt_para para ; /* generic parameter header */ + u_int mib_index ; + u_int mib_payload ; +} ; + +#define SWAP_SMT_P3210 "4l" + +struct smt_p_3210 { + struct smt_para para ; /* generic parameter header */ + u_int mib_index ; + u_int mib_overhead ; +} ; + +#define SWAP_SMT_P4050 "4l1111ll" + +struct smt_p_4050 { + u_int p4050_flag ; + u_char p4050_pad ; + u_char p4050_cutoff ; + u_char p4050_alarm ; + u_char p4050_estimate ; + u_int p4050_reject_ct ; + u_int p4050_ct ; +} ; + +#define SWAP_SMT_P4051 "4lssss" +struct smt_p_4051 { + u_int p4051_multiple ; + u_short p4051_porttype ; + u_short p4051_connectstate ; + u_short p4051_pc_neighbor ; + u_short p4051_pc_withhold ; +} ; + +#define SWAP_SMT_P4052 "4ll" +struct smt_p_4052 { + u_int p4052_flag ; + u_int p4052_eberrorcount ; +} ; + +#define SWAP_SMT_P4053 "4lsslss" + +struct smt_p_4053 { + u_int p4053_multiple ; + u_short p4053_availablepaths ; + u_short p4053_currentpath ; + u_int p4053_requestedpaths ; + u_short p4053_mytype ; + u_short p4053_neighbortype ; +} ; + + +#define SMT_P_SETCOUNT 0x1035 +#define SWAP_SMT_P_SETCOUNT "l8" + +struct smt_p_setcount { + struct smt_para para ; /* generic parameter header */ + u_int count ; + u_char timestamp[8] ; +} ; + +/* + * SMT FRAMES + */ + +/* + * NIF : neighbor information frames + */ +struct smt_nif { + struct smt_header smt ; /* generic header */ + struct smt_p_una una ; /* UNA */ + struct smt_p_sde sde ; /* station descriptor */ + struct smt_p_state state ; /* station state */ +#ifdef SMT6_10 + struct smt_p_fsc fsc ; /* frame status cap. */ +#endif +} ; + +/* + * SIF : station information frames + */ +struct smt_sif_config { + struct smt_header smt ; /* generic header */ + struct smt_p_timestamp ts ; /* time stamp */ + struct smt_p_sde sde ; /* station descriptor */ + struct smt_p_version version ; /* supported versions */ + struct smt_p_state state ; /* station state */ + struct smt_p_policy policy ; /* station policy */ + struct smt_p_latency latency ; /* path latency */ + struct smt_p_neighbor neighbor ; /* neighbors, we have only one*/ +#ifdef OPT_PMF + struct smt_p_setcount setcount ; /* Set Count mandatory */ +#endif + /* WARNING : path MUST BE LAST FIELD !!! (see smt.c:smt_fill_path) */ + struct smt_p_path path ; /* path descriptor */ +} ; +#define SIZEOF_SMT_SIF_CONFIG (sizeof(struct smt_sif_config)- \ + sizeof(struct smt_p_path)) + +struct smt_sif_operation { + struct smt_header smt ; /* generic header */ + struct smt_p_timestamp ts ; /* time stamp */ + struct smt_p_mac_status status ; /* mac status */ + struct smt_p_mac_counter mc ; /* MAC counter */ + struct smt_p_mac_fnc fnc ; /* MAC frame not copied */ + struct smp_p_manufacturer man ; /* manufacturer field */ + struct smp_p_user user ; /* user field */ +#ifdef OPT_PMF + struct smt_p_setcount setcount ; /* Set Count mandatory */ +#endif + /* must be last */ + struct smt_p_lem lem[1] ; /* phy lem status */ +} ; +#define SIZEOF_SMT_SIF_OPERATION (sizeof(struct smt_sif_operation)- \ + sizeof(struct smt_p_lem)) + +/* + * ECF : echo frame + */ +struct smt_ecf { + struct smt_header smt ; /* generic header */ + struct smt_p_echo ec_echo ; /* echo parameter */ +} ; +#define SMT_ECF_LEN (sizeof(struct smt_header)+sizeof(struct smt_para)) + +/* + * RDF : request denied frame + */ +struct smt_rdf { + struct smt_header smt ; /* generic header */ + struct smt_p_reason reason ; /* reason code */ + struct smt_p_version version ; /* supported versions */ + struct smt_p_refused refused ; /* refused frame fragment */ +} ; + +/* + * SBA Request Allocation Responce Frame + */ +struct smt_sba_alc_res { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_reason reason ; /* reason code */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_0019 a_addr ; /* Allocation Address */ + struct smt_p_001a cat ; /* Category - from the request */ + struct smt_p_001d alloc ; /* SBA Allocatable */ +} ; + +/* + * SBA Request Allocation Request Frame + */ +struct smt_sba_alc_req { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_0017 pl_req ; /* requested payload */ + struct smt_p_0018 ov_req ; /* requested SBA overhead */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_0019 a_addr ; /* Allocation Address */ + struct smt_p_001a cat ; /* Category - from the request */ + struct smt_p_001b tneg ; /* max T-NEG */ + struct smt_p_001c segm ; /* minimum segment size */ +} ; + +/* + * SBA Change Allocation Request Frame + */ +struct smt_sba_chg { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_001a cat ; /* Category - from the request */ +} ; + +/* + * SBA Report Allocation Request Frame + */ +struct smt_sba_rep_req { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ +} ; + +/* + * SBA Report Allocation Response Frame + */ +struct smt_sba_rep_res { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ +} ; + +/* + * actions + */ +#define SMT_STATION_ACTION 1 +#define SMT_STATION_ACTION_CONNECT 0 +#define SMT_STATION_ACTION_DISCONNECT 1 +#define SMT_STATION_ACTION_PATHTEST 2 +#define SMT_STATION_ACTION_SELFTEST 3 +#define SMT_STATION_ACTION_DISABLE_A 4 +#define SMT_STATION_ACTION_DISABLE_B 5 +#define SMT_STATION_ACTION_DISABLE_M 6 + +#define SMT_PORT_ACTION 2 +#define SMT_PORT_ACTION_MAINT 0 +#define SMT_PORT_ACTION_ENABLE 1 +#define SMT_PORT_ACTION_DISABLE 2 +#define SMT_PORT_ACTION_START 3 +#define SMT_PORT_ACTION_STOP 4 + +#endif /* _SMT_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/smt_p.h linux/drivers/net/skfp/h/smt_p.h --- v2.2.17/drivers/net/skfp/h/smt_p.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/smt_p.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,326 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * defines for all SMT attributes + */ + +/* + * this boring file was produced by perl + * thanks Larry ! + */ +#define SMT_P0012 0x0012 + +#define SMT_P0015 0x0015 +#define SMT_P0016 0x0016 +#define SMT_P0017 0x0017 +#define SMT_P0018 0x0018 +#define SMT_P0019 0x0019 + +#define SMT_P001A 0x001a +#define SMT_P001B 0x001b +#define SMT_P001C 0x001c +#define SMT_P001D 0x001d + +#define SMT_P100A 0x100a +#define SMT_P100B 0x100b +#define SMT_P100C 0x100c +#define SMT_P100D 0x100d +#define SMT_P100E 0x100e +#define SMT_P100F 0x100f +#define SMT_P1010 0x1010 +#define SMT_P1011 0x1011 +#define SMT_P1012 0x1012 +#define SMT_P1013 0x1013 +#define SMT_P1014 0x1014 +#define SMT_P1015 0x1015 +#define SMT_P1016 0x1016 +#define SMT_P1017 0x1017 +#define SMT_P1018 0x1018 +#define SMT_P1019 0x1019 +#define SMT_P101A 0x101a +#define SMT_P101B 0x101b +#define SMT_P101C 0x101c +#define SMT_P101D 0x101d +#define SMT_P101E 0x101e +#define SMT_P101F 0x101f +#define SMT_P1020 0x1020 +#define SMT_P1021 0x1021 +#define SMT_P1022 0x1022 +#define SMT_P1023 0x1023 +#define SMT_P1024 0x1024 +#define SMT_P1025 0x1025 +#define SMT_P1026 0x1026 +#define SMT_P1027 0x1027 +#define SMT_P1028 0x1028 +#define SMT_P1029 0x1029 +#define SMT_P102A 0x102a +#define SMT_P102B 0x102b +#define SMT_P102C 0x102c +#define SMT_P102D 0x102d +#define SMT_P102E 0x102e +#define SMT_P102F 0x102f +#define SMT_P1030 0x1030 +#define SMT_P1031 0x1031 +#define SMT_P1032 0x1032 +#define SMT_P1033 0x1033 +#define SMT_P1034 0x1034 +#define SMT_P1035 0x1035 +#define SMT_P1036 0x1036 +#define SMT_P1037 0x1037 +#define SMT_P1038 0x1038 +#define SMT_P1039 0x1039 +#define SMT_P103A 0x103a +#define SMT_P103B 0x103b +#define SMT_P103C 0x103c +#define SMT_P103D 0x103d +#define SMT_P103E 0x103e +#define SMT_P103F 0x103f +#define SMT_P1040 0x1040 +#define SMT_P1041 0x1041 +#define SMT_P1042 0x1042 +#define SMT_P1043 0x1043 +#define SMT_P1044 0x1044 +#define SMT_P1045 0x1045 +#define SMT_P1046 0x1046 +#define SMT_P1047 0x1047 +#define SMT_P1048 0x1048 +#define SMT_P1049 0x1049 +#define SMT_P104A 0x104a +#define SMT_P104B 0x104b +#define SMT_P104C 0x104c +#define SMT_P104D 0x104d +#define SMT_P104E 0x104e +#define SMT_P104F 0x104f +#define SMT_P1050 0x1050 +#define SMT_P1051 0x1051 +#define SMT_P1052 0x1052 +#define SMT_P1053 0x1053 +#define SMT_P1054 0x1054 + +#define SMT_P10F0 0x10f0 +#define SMT_P10F1 0x10f1 +#ifdef ESS +#define SMT_P10F2 0x10f2 +#define SMT_P10F3 0x10f3 +#define SMT_P10F4 0x10f4 +#define SMT_P10F5 0x10f5 +#define SMT_P10F6 0x10f6 +#define SMT_P10F7 0x10f7 +#endif +#ifdef SBA +#define SMT_P10F8 0x10f8 +#define SMT_P10F9 0x10f9 +#endif + +#define SMT_P200A 0x200a +#define SMT_P200B 0x200b +#define SMT_P200C 0x200c +#define SMT_P200D 0x200d +#define SMT_P200E 0x200e +#define SMT_P200F 0x200f +#define SMT_P2010 0x2010 +#define SMT_P2011 0x2011 +#define SMT_P2012 0x2012 +#define SMT_P2013 0x2013 +#define SMT_P2014 0x2014 +#define SMT_P2015 0x2015 +#define SMT_P2016 0x2016 +#define SMT_P2017 0x2017 +#define SMT_P2018 0x2018 +#define SMT_P2019 0x2019 +#define SMT_P201A 0x201a +#define SMT_P201B 0x201b +#define SMT_P201C 0x201c +#define SMT_P201D 0x201d +#define SMT_P201E 0x201e +#define SMT_P201F 0x201f +#define SMT_P2020 0x2020 +#define SMT_P2021 0x2021 +#define SMT_P2022 0x2022 +#define SMT_P2023 0x2023 +#define SMT_P2024 0x2024 +#define SMT_P2025 0x2025 +#define SMT_P2026 0x2026 +#define SMT_P2027 0x2027 +#define SMT_P2028 0x2028 +#define SMT_P2029 0x2029 +#define SMT_P202A 0x202a +#define SMT_P202B 0x202b +#define SMT_P202C 0x202c +#define SMT_P202D 0x202d +#define SMT_P202E 0x202e +#define SMT_P202F 0x202f +#define SMT_P2030 0x2030 +#define SMT_P2031 0x2031 +#define SMT_P2032 0x2032 +#define SMT_P2033 0x2033 +#define SMT_P2034 0x2034 +#define SMT_P2035 0x2035 +#define SMT_P2036 0x2036 +#define SMT_P2037 0x2037 +#define SMT_P2038 0x2038 +#define SMT_P2039 0x2039 +#define SMT_P203A 0x203a +#define SMT_P203B 0x203b +#define SMT_P203C 0x203c +#define SMT_P203D 0x203d +#define SMT_P203E 0x203e +#define SMT_P203F 0x203f +#define SMT_P2040 0x2040 +#define SMT_P2041 0x2041 +#define SMT_P2042 0x2042 +#define SMT_P2043 0x2043 +#define SMT_P2044 0x2044 +#define SMT_P2045 0x2045 +#define SMT_P2046 0x2046 +#define SMT_P2047 0x2047 +#define SMT_P2048 0x2048 +#define SMT_P2049 0x2049 +#define SMT_P204A 0x204a +#define SMT_P204B 0x204b +#define SMT_P204C 0x204c +#define SMT_P204D 0x204d +#define SMT_P204E 0x204e +#define SMT_P204F 0x204f +#define SMT_P2050 0x2050 +#define SMT_P2051 0x2051 +#define SMT_P2052 0x2052 +#define SMT_P2053 0x2053 +#define SMT_P2054 0x2054 +#define SMT_P2055 0x2055 +#define SMT_P2056 0x2056 +#define SMT_P2057 0x2057 +#define SMT_P2058 0x2058 +#define SMT_P2059 0x2059 +#define SMT_P205A 0x205a +#define SMT_P205B 0x205b +#define SMT_P205C 0x205c +#define SMT_P205D 0x205d +#define SMT_P205E 0x205e +#define SMT_P205F 0x205f +#define SMT_P2060 0x2060 +#define SMT_P2061 0x2061 +#define SMT_P2062 0x2062 +#define SMT_P2063 0x2063 +#define SMT_P2064 0x2064 +#define SMT_P2065 0x2065 +#define SMT_P2066 0x2066 +#define SMT_P2067 0x2067 +#define SMT_P2068 0x2068 +#define SMT_P2069 0x2069 +#define SMT_P206A 0x206a +#define SMT_P206B 0x206b +#define SMT_P206C 0x206c +#define SMT_P206D 0x206d +#define SMT_P206E 0x206e +#define SMT_P206F 0x206f +#define SMT_P2070 0x2070 +#define SMT_P2071 0x2071 +#define SMT_P2072 0x2072 +#define SMT_P2073 0x2073 +#define SMT_P2074 0x2074 +#define SMT_P2075 0x2075 +#define SMT_P2076 0x2076 + +#define SMT_P208C 0x208c +#define SMT_P208D 0x208d +#define SMT_P208E 0x208e +#define SMT_P208F 0x208f +#define SMT_P2090 0x2090 + +#define SMT_P20F0 0x20F0 +#define SMT_P20F1 0x20F1 + +#define SMT_P320A 0x320a +#define SMT_P320B 0x320b +#define SMT_P320C 0x320c +#define SMT_P320D 0x320d +#define SMT_P320E 0x320e +#define SMT_P320F 0x320f +#define SMT_P3210 0x3210 +#define SMT_P3211 0x3211 +#define SMT_P3212 0x3212 +#define SMT_P3213 0x3213 +#define SMT_P3214 0x3214 +#define SMT_P3215 0x3215 +#define SMT_P3216 0x3216 +#define SMT_P3217 0x3217 + +#define SMT_P400A 0x400a +#define SMT_P400B 0x400b +#define SMT_P400C 0x400c +#define SMT_P400D 0x400d +#define SMT_P400E 0x400e +#define SMT_P400F 0x400f +#define SMT_P4010 0x4010 +#define SMT_P4011 0x4011 +#define SMT_P4012 0x4012 +#define SMT_P4013 0x4013 +#define SMT_P4014 0x4014 +#define SMT_P4015 0x4015 +#define SMT_P4016 0x4016 +#define SMT_P4017 0x4017 +#define SMT_P4018 0x4018 +#define SMT_P4019 0x4019 +#define SMT_P401A 0x401a +#define SMT_P401B 0x401b +#define SMT_P401C 0x401c +#define SMT_P401D 0x401d +#define SMT_P401E 0x401e +#define SMT_P401F 0x401f +#define SMT_P4020 0x4020 +#define SMT_P4021 0x4021 +#define SMT_P4022 0x4022 +#define SMT_P4023 0x4023 +#define SMT_P4024 0x4024 +#define SMT_P4025 0x4025 +#define SMT_P4026 0x4026 +#define SMT_P4027 0x4027 +#define SMT_P4028 0x4028 +#define SMT_P4029 0x4029 +#define SMT_P402A 0x402a +#define SMT_P402B 0x402b +#define SMT_P402C 0x402c +#define SMT_P402D 0x402d +#define SMT_P402E 0x402e +#define SMT_P402F 0x402f +#define SMT_P4030 0x4030 +#define SMT_P4031 0x4031 +#define SMT_P4032 0x4032 +#define SMT_P4033 0x4033 +#define SMT_P4034 0x4034 +#define SMT_P4035 0x4035 +#define SMT_P4036 0x4036 +#define SMT_P4037 0x4037 +#define SMT_P4038 0x4038 +#define SMT_P4039 0x4039 +#define SMT_P403A 0x403a +#define SMT_P403B 0x403b +#define SMT_P403C 0x403c +#define SMT_P403D 0x403d +#define SMT_P403E 0x403e +#define SMT_P403F 0x403f +#define SMT_P4040 0x4040 +#define SMT_P4041 0x4041 +#define SMT_P4042 0x4042 +#define SMT_P4043 0x4043 +#define SMT_P4044 0x4044 +#define SMT_P4045 0x4045 +#define SMT_P4046 0x4046 + +#define SMT_P4050 0x4050 +#define SMT_P4051 0x4051 +#define SMT_P4052 0x4052 +#define SMT_P4053 0x4053 diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/smtstate.h linux/drivers/net/skfp/h/smtstate.h --- v2.2.17/drivers/net/skfp/h/smtstate.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/smtstate.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,100 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * SMT state definitions + */ + +#ifndef KERNEL +/* + * PCM states + */ +#define PC0_OFF 0 +#define PC1_BREAK 1 +#define PC2_TRACE 2 +#define PC3_CONNECT 3 +#define PC4_NEXT 4 +#define PC5_SIGNAL 5 +#define PC6_JOIN 6 +#define PC7_VERIFY 7 +#define PC8_ACTIVE 8 +#define PC9_MAINT 9 + +/* + * PCM modes + */ +#define PM_NONE 0 +#define PM_PEER 1 +#define PM_TREE 2 + +/* + * PCM type + */ +#define TA 0 +#define TB 1 +#define TS 2 +#define TM 3 +#define TNONE 4 + +/* + * CFM states + */ +#define SC0_ISOLATED 0 /* isolated */ +#define SC1_WRAP_A 5 /* wrap A */ +#define SC2_WRAP_B 6 /* wrap B */ +#define SC4_THRU_A 12 /* through A */ +#define SC5_THRU_B 7 /* through B (SMt 6.2) */ +#define SC7_WRAP_S 8 /* SAS */ + +/* + * ECM states + */ +#define EC0_OUT 0 +#define EC1_IN 1 +#define EC2_TRACE 2 +#define EC3_LEAVE 3 +#define EC4_PATH_TEST 4 +#define EC5_INSERT 5 +#define EC6_CHECK 6 +#define EC7_DEINSERT 7 + +/* + * RMT states + */ +#define RM0_ISOLATED 0 +#define RM1_NON_OP 1 /* not operational */ +#define RM2_RING_OP 2 /* ring operational */ +#define RM3_DETECT 3 /* detect dupl addresses */ +#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ +#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ +#define RM6_DIRECTED 6 /* sending directed beacons */ +#define RM7_TRACE 7 /* trace initiated */ +#endif + +struct pcm_state { + unsigned char pcm_type ; /* TA TB TS TM */ + unsigned char pcm_state ; /* state PC[0-9]_* */ + unsigned char pcm_mode ; /* PM_{NONE,PEER,TREE} */ + unsigned char pcm_neighbor ; /* TA TB TS TM */ + unsigned char pcm_bsf ; /* flag bs : TRUE/FALSE */ + unsigned char pcm_lsf ; /* flag ls : TRUE/FALSE */ + unsigned char pcm_lct_fail ; /* counter lct_fail */ + unsigned char pcm_ls_rx ; /* rx line state */ + short pcm_r_val ; /* signaling bits */ + short pcm_t_val ; /* signaling bits */ +} ; + +struct smt_state { + struct pcm_state pcm_state[NUMPHYS] ; /* port A & port B */ +} ; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/supern_2.h linux/drivers/net/skfp/h/supern_2.h --- v2.2.17/drivers/net/skfp/h/supern_2.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/supern_2.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,1059 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + defines for AMD Supernet II chip set + the chips are refered to as + FPLUS Formac Plus + PLC Physical Layer + + added defines for AMD Supernet III chip set + added comments on differences between Supernet II and Supernet III + added defines for the Motorola ELM (MOT_ELM) +*/ + +#ifndef _SUPERNET_ +#define _SUPERNET_ + +/* + * Define Supernet 3 when used + */ +#ifdef PCI +#ifndef SUPERNET_3 +#define SUPERNET_3 +#endif +#define TAG +#endif + +#define MB 0xff +#define MW 0xffff +#define MD 0xffffffff + +/* + * FORMAC frame status (rx_msext) + */ +#define FS_EI (1<<2) +#define FS_AI (1<<1) +#define FS_CI (1<<0) + +#define FS_MSVALID (1<<15) /* end of queue */ +#define FS_MSRABT (1<<14) /* frame was aborted during reception*/ +#define FS_SSRCRTG (1<<12) /* if SA has set MSB (source-routing)*/ +#define FS_SEAC2 (FS_EI<<9) /* error indicator */ +#define FS_SEAC1 (FS_AI<<9) /* address indicator */ +#define FS_SEAC0 (FS_CI<<9) /* copy indicator */ +#define FS_SFRMERR (1<<8) /* error detected (CRC or length) */ +#define FS_SADRRG (1<<7) /* address recognized */ +#define FS_SFRMTY2 (1<<6) /* frame-class bit */ +#define FS_SFRMTY1 (1<<5) /* frame-type bit (impementor) */ +#define FS_SFRMTY0 (1<<4) /* frame-type bit (LLC) */ +#define FS_ERFBB1 (1<<1) /* byte offset (depends on LSB bit) */ +#define FS_ERFBB0 (1<<0) /* - " - */ + +/* + * status frame type + */ +#define FRM_SMT (0) /* asynchr. frames */ +#define FRM_LLCA (1) +#define FRM_IMPA (2) +#define FRM_MAC (4) /* synchr. frames */ +#define FRM_LLCS (5) +#define FRM_IMPS (6) + +/* + * bits in rx_descr.i (receive frame status word) + */ +#define RX_MSVALID ((long)1<<31) /* memory status valid */ +#define RX_MSRABT ((long)1<<30) /* memory status receive abort */ +#define RX_FS_E ((long)FS_SEAC2<<16) /* error indicator */ +#define RX_FS_A ((long)FS_SEAC1<<16) /* address indicator */ +#define RX_FS_C ((long)FS_SEAC0<<16) /* copy indicator */ +#define RX_FS_CRC ((long)FS_SFRMERR<<16)/* error detected */ +#define RX_FS_ADDRESS ((long)FS_SADRRG<<16) /* address recognized */ +#define RX_FS_MAC ((long)FS_SFRMTY2<<16)/* MAC frame */ +#define RX_FS_SMT ((long)0<<16) /* SMT frame */ +#define RX_FS_IMPL ((long)FS_SFRMTY1<<16)/* implementer frame */ +#define RX_FS_LLC ((long)FS_SFRMTY0<<16)/* LLC frame */ + +/* + * receive frame descriptor + */ +union rx_descr { + struct { +#ifdef LITTLE_ENDIAN + unsigned rx_length :16 ; /* frame length lower/upper byte */ + unsigned rx_erfbb :2 ; /* received frame byte boundary */ + unsigned rx_reserv2:2 ; /* reserved */ + unsigned rx_sfrmty :3 ; /* frame type bits */ + unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ + unsigned rx_sfrmerr:1 ; /* received frame not valid */ + unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ + unsigned rx_seac1 :1 ; /* address-match A-indicator */ + unsigned rx_seac2 :1 ; /* frame-error E-indicator */ + unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ + unsigned rx_reserv1:1 ; /* reserved */ + unsigned rx_msrabt :1 ; /* memory status receive abort */ + unsigned rx_msvalid:1 ; /* memory status valid */ +#else + unsigned rx_msvalid:1 ; /* memory status valid */ + unsigned rx_msrabt :1 ; /* memory status receive abort */ + unsigned rx_reserv1:1 ; /* reserved */ + unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ + unsigned rx_seac2 :1 ; /* frame-error E-indicator */ + unsigned rx_seac1 :1 ; /* address-match A-indicator */ + unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ + unsigned rx_sfrmerr:1 ; /* received frame not valid */ + unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ + unsigned rx_sfrmty :3 ; /* frame type bits */ + unsigned rx_erfbb :2 ; /* received frame byte boundary */ + unsigned rx_reserv2:2 ; /* reserved */ + unsigned rx_length :16 ; /* frame length lower/upper byte */ +#endif + } r ; + long i ; +} ; + +/* defines for Receive Frame Descriptor access */ +#define RD_S_ERFBB 0x00030000L /* received frame byte boundary */ +#define RD_S_RES2 0x000c0000L /* reserved */ +#define RD_S_SFRMTY 0x00700000L /* frame type bits */ +#define RD_S_SADRRG 0x00800000L /* DA == MA or broad-/multicast */ +#define RD_S_SFRMERR 0x01000000L /* received frame not valid */ +#define RD_S_SEAC 0x0e000000L /* frame status indicators */ +#define RD_S_SEAC0 0x02000000L /* frame-copied case-indicator */ +#define RD_S_SEAC1 0x04000000L /* address-match A-indicator */ +#define RD_S_SEAC2 0x08000000L /* frame-error E-indicator */ +#define RD_S_SSRCRTG 0x10000000L /* == 1 SA has MSB set */ +#define RD_S_RES1 0x20000000L /* reserved */ +#define RD_S_MSRABT 0x40000000L /* memory status receive abort */ +#define RD_S_MSVALID 0x80000000L /* memory status valid */ + +#define RD_STATUS 0xffff0000L +#define RD_LENGTH 0x0000ffffL + +/* defines for Receive Frames Status Word values */ +/*RD_S_SFRMTY*/ +#define RD_FRM_SMT (unsigned long)(0<<20) /* asynchr. frames */ +#define RD_FRM_LLCA (unsigned long)(1<<20) +#define RD_FRM_IMPA (unsigned long)(2<<20) +#define RD_FRM_MAC (unsigned long)(4<<20) /* synchr. frames */ +#define RD_FRM_LLCS (unsigned long)(5<<20) +#define RD_FRM_IMPS (unsigned long)(6<<20) + +#define TX_DESCRIPTOR 0x40000000L +#define TX_OFFSET_3 0x18000000L + +#define TXP1 2 + +/* + * transmit frame descriptor + */ +union tx_descr { + struct { +#ifdef LITTLE_ENDIAN + unsigned tx_length:16 ; /* frame length lower/upper byte */ + unsigned tx_res :8 ; /* reserved (bit 16..23) */ + unsigned tx_xmtabt:1 ; /* transmit abort */ + unsigned tx_nfcs :1 ; /* no frame check sequence */ + unsigned tx_xdone :1 ; /* give up token */ + unsigned tx_rpxm :2 ; /* byte offset */ + unsigned tx_pat1 :2 ; /* must be TXP1 */ + unsigned tx_more :1 ; /* more frame in chain */ +#else + unsigned tx_more :1 ; /* more frame in chain */ + unsigned tx_pat1 :2 ; /* must be TXP1 */ + unsigned tx_rpxm :2 ; /* byte offset */ + unsigned tx_xdone :1 ; /* give up token */ + unsigned tx_nfcs :1 ; /* no frame check sequence */ + unsigned tx_xmtabt:1 ; /* transmit abort */ + unsigned tx_res :8 ; /* reserved (bit 16..23) */ + unsigned tx_length:16 ; /* frame length lower/upper byte */ +#endif + } t ; + long i ; +} ; + +/* defines for Transmit Descriptor access */ +#define TD_C_MORE 0x80000000L /* more frame in chain */ +#define TD_C_DESCR 0x60000000L /* must be TXP1 */ +#define TD_C_TXFBB 0x18000000L /* byte offset */ +#define TD_C_XDONE 0x04000000L /* give up token */ +#define TD_C_NFCS 0x02000000L /* no frame check sequence */ +#define TD_C_XMTABT 0x01000000L /* transmit abort */ + +#define TD_C_LNCNU 0x0000ff00L +#define TD_C_LNCNL 0x000000ffL +#define TD_C_LNCN 0x0000ffffL /* frame length lower/upper byte */ + +/* + * transmit pointer + */ +union tx_pointer { + struct t { +#ifdef LITTLE_ENDIAN + unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ + unsigned tp_res :8 ; /* reserved (bit 16..23) */ + unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ +#else + unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ + unsigned tp_res :8 ; /* reserved (bit 16..23) */ + unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ +#endif + } t ; + long i ; +} ; + +/* defines for Nontag Mode Pointer access */ +#define TD_P_CNTRL 0xff000000L +#define TD_P_RPXU 0x0000ff00L +#define TD_P_RPXL 0x000000ffL +#define TD_P_RPX 0x0000ffffL + + +#define TX_PATTERN 0xa0 +#define TX_POINTER_END 0xa0000000L +#define TX_INT_PATTERN 0xa0000000L + +struct tx_queue { + struct tx_queue *tq_next ; + u_short tq_pack_offset ; /* offset buffer memory */ + u_char tq_pad[2] ; +} ; + +/* + defines for FORMAC Plus (Am79C830) +*/ + +/* + * FORMAC+ read/write (r/w) registers + */ +#define FM_CMDREG1 0x00 /* write command reg 1 instruction */ +#define FM_CMDREG2 0x01 /* write command reg 2 instruction */ +#define FM_ST1U 0x00 /* read upper 16-bit of status reg 1 */ +#define FM_ST1L 0x01 /* read lower 16-bit of status reg 1 */ +#define FM_ST2U 0x02 /* read upper 16-bit of status reg 2 */ +#define FM_ST2L 0x03 /* read lower 16-bit of status reg 2 */ +#define FM_IMSK1U 0x04 /* r/w upper 16-bit of IMSK 1 */ +#define FM_IMSK1L 0x05 /* r/w lower 16-bit of IMSK 1 */ +#define FM_IMSK2U 0x06 /* r/w upper 16-bit of IMSK 2 */ +#define FM_IMSK2L 0x07 /* r/w lower 16-bit of IMSK 2 */ +#define FM_SAID 0x08 /* r/w short addr.-individual */ +#define FM_LAIM 0x09 /* r/w long addr.-ind. (MSW of LAID) */ +#define FM_LAIC 0x0a /* r/w long addr.-ind. (middle)*/ +#define FM_LAIL 0x0b /* r/w long addr.-ind. (LSW) */ +#define FM_SAGP 0x0c /* r/w short address-group */ +#define FM_LAGM 0x0d /* r/w long addr.-gr. (MSW of LAGP) */ +#define FM_LAGC 0x0e /* r/w long addr.-gr. (middle) */ +#define FM_LAGL 0x0f /* r/w long addr.-gr. (LSW) */ +#define FM_MDREG1 0x10 /* r/w 16-bit mode reg 1 */ +#define FM_STMCHN 0x11 /* read state-machine reg */ +#define FM_MIR1 0x12 /* read upper 16-bit of MAC Info Reg */ +#define FM_MIR0 0x13 /* read lower 16-bit of MAC Info Reg */ +#define FM_TMAX 0x14 /* r/w 16-bit TMAX reg */ +#define FM_TVX 0x15 /* write 8-bit TVX reg with NP7-0 + read TVX on NP7-0, timer on NP15-8*/ +#define FM_TRT 0x16 /* r/w upper 16-bit of TRT timer */ +#define FM_THT 0x17 /* r/w upper 16-bit of THT timer */ +#define FM_TNEG 0x18 /* read upper 16-bit of TNEG (TTRT) */ +#define FM_TMRS 0x19 /* read lower 5-bit of TNEG,TRT,THT */ + /* F E D C B A 9 8 7 6 5 4 3 2 1 0 + x |-TNEG4-0| |-TRT4-0-| |-THT4-0-| (x-late count) */ +#define FM_TREQ0 0x1a /* r/w 16-bit TREQ0 reg (LSW of TRT) */ +#define FM_TREQ1 0x1b /* r/w 16-bit TREQ1 reg (MSW of TRT) */ +#define FM_PRI0 0x1c /* r/w priority r. for asyn.-queue 0 */ +#define FM_PRI1 0x1d /* r/w priority r. for asyn.-queue 1 */ +#define FM_PRI2 0x1e /* r/w priority r. for asyn.-queue 2 */ +#define FM_TSYNC 0x1f /* r/w 16-bit of the TSYNC register */ +#define FM_MDREG2 0x20 /* r/w 16-bit mode reg 2 */ +#define FM_FRMTHR 0x21 /* r/w the frame threshold register */ +#define FM_EACB 0x22 /* r/w end addr of claim/beacon area */ +#define FM_EARV 0x23 /* r/w end addr of receive queue */ +/* Supernet 3 */ +#define FM_EARV1 FM_EARV + +#define FM_EAS 0x24 /* r/w end addr of synchr. queue */ +#define FM_EAA0 0x25 /* r/w end addr of asyn. queue 0 */ +#define FM_EAA1 0x26 /* r/w end addr of asyn. queue 1 */ +#define FM_EAA2 0x27 /* r/w end addr of asyn. queue 2 */ +#define FM_SACL 0x28 /* r/w start addr of claim frame */ +#define FM_SABC 0x29 /* r/w start addr of beacon frame */ +#define FM_WPXSF 0x2a /* r/w the write ptr. for special fr.*/ +#define FM_RPXSF 0x2b /* r/w the read ptr. for special fr. */ +#define FM_RPR 0x2d /* r/w the read ptr. for receive qu. */ +#define FM_WPR 0x2e /* r/w the write ptr. for receive qu.*/ +#define FM_SWPR 0x2f /* r/w the shadow wr.-ptr. for rec.q.*/ +/* Supernet 3 */ +#define FM_RPR1 FM_RPR +#define FM_WPR1 FM_WPR +#define FM_SWPR1 FM_SWPR + +#define FM_WPXS 0x30 /* r/w the write ptr. for synchr. qu.*/ +#define FM_WPXA0 0x31 /* r/w the write ptr. for asyn. qu.0 */ +#define FM_WPXA1 0x32 /* r/w the write ptr. for asyn. qu.1 */ +#define FM_WPXA2 0x33 /* r/w the write ptr. for asyn. qu.2 */ +#define FM_SWPXS 0x34 /* r/w the shadow wr.-ptr. for syn.q.*/ +#define FM_SWPXA0 0x35 /* r/w the shad. wr.-ptr. for asyn.q0*/ +#define FM_SWPXA1 0x36 /* r/w the shad. wr.-ptr. for asyn.q1*/ +#define FM_SWPXA2 0x37 /* r/w the shad. wr.-ptr. for asyn.q2*/ +#define FM_RPXS 0x38 /* r/w the read ptr. for synchr. qu. */ +#define FM_RPXA0 0x39 /* r/w the read ptr. for asyn. qu. 0 */ +#define FM_RPXA1 0x3a /* r/w the read ptr. for asyn. qu. 1 */ +#define FM_RPXA2 0x3b /* r/w the read ptr. for asyn. qu. 2 */ +#define FM_MARR 0x3c /* r/w the memory read addr register */ +#define FM_MARW 0x3d /* r/w the memory write addr register*/ +#define FM_MDRU 0x3e /* r/w upper 16-bit of mem. data reg */ +#define FM_MDRL 0x3f /* r/w lower 16-bit of mem. data reg */ + +/* following instructions relate to MAC counters and timer */ +#define FM_TMSYNC 0x40 /* r/w upper 16 bits of TMSYNC timer */ +#define FM_FCNTR 0x41 /* r/w the 16-bit frame counter */ +#define FM_LCNTR 0x42 /* r/w the 16-bit lost counter */ +#define FM_ECNTR 0x43 /* r/w the 16-bit error counter */ + +/* Supernet 3: extensions to old register block */ +#define FM_FSCNTR 0x44 /* r/? Frame Strip Counter */ +#define FM_FRSELREG 0x45 /* r/w Frame Selection Register */ + +/* Supernet 3: extensions for 2. receive queue etc. */ +#define FM_MDREG3 0x60 /* r/w Mode Register 3 */ +#define FM_ST3U 0x61 /* read upper 16-bit of status reg 3 */ +#define FM_ST3L 0x62 /* read lower 16-bit of status reg 3 */ +#define FM_IMSK3U 0x63 /* r/w upper 16-bit of IMSK reg 3 */ +#define FM_IMSK3L 0x64 /* r/w lower 16-bit of IMSK reg 3 */ +#define FM_IVR 0x65 /* read Interrupt Vector register */ +#define FM_IMR 0x66 /* r/w Interrupt mask register */ +/* 0x67 Hidden */ +#define FM_RPR2 0x68 /* r/w the read ptr. for rec. qu. 2 */ +#define FM_WPR2 0x69 /* r/w the write ptr. for rec. qu. 2 */ +#define FM_SWPR2 0x6a /* r/w the shadow wptr. for rec. q. 2 */ +#define FM_EARV2 0x6b /* r/w end addr of rec. qu. 2 */ +#define FM_UNLCKDLY 0x6c /* r/w Auto Unlock Delay register */ + /* Bit 15-8: RECV2 unlock threshold */ + /* Bit 7-0: RECV1 unlock threshold */ +/* 0x6f-0x73 Hidden */ +#define FM_LTDPA1 0x79 /* r/w Last Trans desc ptr for A1 qu. */ +/* 0x80-0x9a PLCS registers of built-in PLCS (Supernet 3 only) */ + +/* Supernet 3: Adderss Filter Registers */ +#define FM_AFCMD 0xb0 /* r/w Address Filter Command Reg */ +#define FM_AFSTAT 0xb2 /* r/w Address Filter Status Reg */ +#define FM_AFBIST 0xb4 /* r/w Address Filter BIST signature */ +#define FM_AFCOMP2 0xb6 /* r/w Address Filter Comparand 2 */ +#define FM_AFCOMP1 0xb8 /* r/w Address Filter Comparand 1 */ +#define FM_AFCOMP0 0xba /* r/w Address Filter Comparand 0 */ +#define FM_AFMASK2 0xbc /* r/w Address Filter Mask 2 */ +#define FM_AFMASK1 0xbe /* r/w Address Filter Mask 1 */ +#define FM_AFMASK0 0xc0 /* r/w Address Filter Mask 0 */ +#define FM_AFPERS 0xc2 /* r/w Address Filter Personality Reg */ + +/* Supernet 3: Orion (PDX?) Registers */ +#define FM_ORBIST 0xd0 /* r/w Orion BIST signature */ +#define FM_ORSTAT 0xd2 /* r/w Orion Status Register */ + + +/* + * Mode Register 1 (MDREG1) + */ +#define FM_RES0 0x0001 /* reserved */ + /* SN3: other definition */ +#define FM_XMTINH_HOLD 0x0002 /* transmit-inhibit/hold bit */ + /* SN3: other definition */ +#define FM_HOFLXI 0x0003 /* SN3: Hold / Flush / Inhibit */ +#define FM_FULL_HALF 0x0004 /* full-duplex/half-duplex bit */ +#define FM_LOCKTX 0x0008 /* lock-transmit-asynchr.-queues bit */ +#define FM_EXGPA0 0x0010 /* extended-group-addressing bit 0 */ +#define FM_EXGPA1 0x0020 /* extended-group-addressing bit 1 */ +#define FM_DISCRY 0x0040 /* disable-carry bit */ + /* SN3: reserved */ +#define FM_SELRA 0x0080 /* select input from PHY (1=RA,0=RB) */ + +#define FM_ADDET 0x0700 /* address detection */ +#define FM_MDAMA (0<<8) /* address detection : DA = MA */ +#define FM_MDASAMA (1<<8) /* address detection : DA=MA||SA=MA */ +#define FM_MRNNSAFNMA (2<<8) /* rec. non-NSA frames DA=MA&&SA!=MA */ +#define FM_MRNNSAF (3<<8) /* rec. non-NSA frames DA = MA */ +#define FM_MDISRCV (4<<8) /* disable receive function */ +#define FM_MRES0 (5<<8) /* reserve */ +#define FM_MLIMPROM (6<<8) /* limited-promiscuous mode */ +#define FM_MPROMISCOUS (7<<8) /* address detection : promiscous */ + +#define FM_SELSA 0x0800 /* select-short-address bit */ + +#define FM_MMODE 0x7000 /* mode select */ +#define FM_MINIT (0<<12) /* initialize */ +#define FM_MMEMACT (1<<12) /* memory activate */ +#define FM_MONLINESP (2<<12) /* on-line special */ +#define FM_MONLINE (3<<12) /* on-line (FDDI operational mode) */ +#define FM_MILOOP (4<<12) /* internal loopback */ +#define FM_MRES1 (5<<12) /* reserved */ +#define FM_MRES2 (6<<12) /* reserved */ +#define FM_MELOOP (7<<12) /* external loopback */ + +#define FM_SNGLFRM 0x8000 /* single-frame-receive mode */ + /* SN3: reserved */ + +#define MDR1INIT (FM_MINIT | FM_MDAMA) + +/* + * Mode Register 2 (MDREG2) + */ +#define FM_AFULL 0x000f /* 4-bit value (empty loc.in txqueue)*/ +#define FM_RCVERR 0x0010 /* rec.-errored-frames bit */ +#define FM_SYMCTL 0x0020 /* sysmbol-control bit */ + /* SN3: reserved */ +#define FM_SYNPRQ 0x0040 /* synchron.-NP-DMA-request bit */ +#define FM_ENNPRQ 0x0080 /* enable-NP-DMA-request bit */ +#define FM_ENHSRQ 0x0100 /* enable-host-request bit */ +#define FM_RXFBB01 0x0600 /* rec. frame byte boundary bit0 & 1 */ +#define FM_LSB 0x0800 /* determ. ordering of bytes in buffer*/ +#define FM_PARITY 0x1000 /* 1 = even, 0 = odd */ +#define FM_CHKPAR 0x2000 /* 1 = parity of 32-bit buffer BD-bus*/ +#define FM_STRPFCS 0x4000 /* 1 = strips FCS field of rec.frame */ +#define FM_BMMODE 0x8000 /* Buffer-Memory-Mode (1 = tag mode) */ + /* SN3: 1 = tag, 0 = modified tag */ + +/* + * Status Register 1, Upper 16 Bits (ST1U) + */ +#define FM_STEFRMS 0x0001 /* transmit end of frame: synchr. qu.*/ +#define FM_STEFRMA0 0x0002 /* transmit end of frame: asyn. qu.0 */ +#define FM_STEFRMA1 0x0004 /* transmit end of frame: asyn. qu.1 */ +#define FM_STEFRMA2 0x0008 /* transmit end of frame: asyn. qu.2 */ + /* SN3: reserved */ +#define FM_STECFRMS 0x0010 /* transmit end of chain of syn. qu. */ + /* SN3: reserved */ +#define FM_STECFRMA0 0x0020 /* transmit end of chain of asyn. q0 */ + /* SN3: reserved */ +#define FM_STECFRMA1 0x0040 /* transmit end of chain of asyn. q1 */ + /* SN3: STECMDA1 */ +#define FM_STECMDA1 0x0040 /* SN3: 'no description' */ +#define FM_STECFRMA2 0x0080 /* transmit end of chain of asyn. q2 */ + /* SN3: reserved */ +#define FM_STEXDONS 0x0100 /* transmit until XDONE in syn. qu. */ +#define FM_STBFLA 0x0200 /* asynchr.-queue trans. buffer full */ +#define FM_STBFLS 0x0400 /* synchr.-queue transm. buffer full */ +#define FM_STXABRS 0x0800 /* synchr. queue transmit-abort */ +#define FM_STXABRA0 0x1000 /* asynchr. queue 0 transmit-abort */ +#define FM_STXABRA1 0x2000 /* asynchr. queue 1 transmit-abort */ +#define FM_STXABRA2 0x4000 /* asynchr. queue 2 transmit-abort */ + /* SN3: reserved */ +#define FM_SXMTABT 0x8000 /* transmit abort */ + +/* + * Status Register 1, Lower 16 Bits (ST1L) + */ +#define FM_SQLCKS 0x0001 /* queue lock for synchr. queue */ +#define FM_SQLCKA0 0x0002 /* queue lock for asynchr. queue 0 */ +#define FM_SQLCKA1 0x0004 /* queue lock for asynchr. queue 1 */ +#define FM_SQLCKA2 0x0008 /* queue lock for asynchr. queue 2 */ + /* SN3: reserved */ +#define FM_STXINFLS 0x0010 /* transmit instruction full: syn. */ + /* SN3: reserved */ +#define FM_STXINFLA0 0x0020 /* transmit instruction full: asyn.0 */ + /* SN3: reserved */ +#define FM_STXINFLA1 0x0040 /* transmit instruction full: asyn.1 */ + /* SN3: reserved */ +#define FM_STXINFLA2 0x0080 /* transmit instruction full: asyn.2 */ + /* SN3: reserved */ +#define FM_SPCEPDS 0x0100 /* parity/coding error: syn. queue */ +#define FM_SPCEPDA0 0x0200 /* parity/coding error: asyn. queue0 */ +#define FM_SPCEPDA1 0x0400 /* parity/coding error: asyn. queue1 */ +#define FM_SPCEPDA2 0x0800 /* parity/coding error: asyn. queue2 */ + /* SN3: reserved */ +#define FM_STBURS 0x1000 /* transmit buffer underrun: syn. q. */ +#define FM_STBURA0 0x2000 /* transmit buffer underrun: asyn.0 */ +#define FM_STBURA1 0x4000 /* transmit buffer underrun: asyn.1 */ +#define FM_STBURA2 0x8000 /* transmit buffer underrun: asyn.2 */ + /* SN3: reserved */ + +/* + * Status Register 2, Upper 16 Bits (ST2U) + */ +#define FM_SOTRBEC 0x0001 /* other beacon received */ +#define FM_SMYBEC 0x0002 /* my beacon received */ +#define FM_SBEC 0x0004 /* beacon state entered */ +#define FM_SLOCLM 0x0008 /* low claim received */ +#define FM_SHICLM 0x0010 /* high claim received */ +#define FM_SMYCLM 0x0020 /* my claim received */ +#define FM_SCLM 0x0040 /* claim state entered */ +#define FM_SERRSF 0x0080 /* error in special frame */ +#define FM_SNFSLD 0x0100 /* NP and FORMAC+ simultaneous load */ +#define FM_SRFRCTOV 0x0200 /* receive frame counter overflow */ + /* SN3: reserved */ +#define FM_SRCVFRM 0x0400 /* receive frame */ + /* SN3: reserved */ +#define FM_SRCVOVR 0x0800 /* receive FIFO overflow */ +#define FM_SRBFL 0x1000 /* receive buffer full */ +#define FM_SRABT 0x2000 /* receive abort */ +#define FM_SRBMT 0x4000 /* receive buffer empty */ +#define FM_SRCOMP 0x8000 /* receive complete. Nontag mode */ + +/* + * Status Register 2, Lower 16 Bits (ST2L) + * Attention: SN3 docu shows these bits the other way around + */ +#define FM_SRES0 0x0001 /* reserved */ +#define FM_SESTRIPTK 0x0001 /* SN3: 'no description' */ +#define FM_STRTEXR 0x0002 /* TRT expired in claim | beacon st. */ +#define FM_SDUPCLM 0x0004 /* duplicate claim received */ +#define FM_SSIFG 0x0008 /* short interframe gap */ +#define FM_SFRMCTR 0x0010 /* frame counter overflow */ +#define FM_SERRCTR 0x0020 /* error counter overflow */ +#define FM_SLSTCTR 0x0040 /* lost counter overflow */ +#define FM_SPHINV 0x0080 /* PHY invalid */ +#define FM_SADET 0x0100 /* address detect */ +#define FM_SMISFRM 0x0200 /* missed frame */ +#define FM_STRTEXP 0x0400 /* TRT expired and late count > 0 */ +#define FM_STVXEXP 0x0800 /* TVX expired */ +#define FM_STKISS 0x1000 /* token issued */ +#define FM_STKERR 0x2000 /* token error */ +#define FM_SMULTDA 0x4000 /* multiple destination address */ +#define FM_SRNGOP 0x8000 /* ring operational */ + +/* + * Supernet 3: + * Status Register 3, Upper 16 Bits (ST3U) + */ +#define FM_SRQUNLCK1 0x0001 /* receive queue unlocked queue 1 */ +#define FM_SRQUNLCK2 0x0002 /* receive queue unlocked queue 2 */ +#define FM_SRPERRQ1 0x0004 /* receive parity error rx queue 1 */ +#define FM_SRPERRQ2 0x0008 /* receive parity error rx queue 2 */ + /* Bit 4-10: reserved */ +#define FM_SRCVOVR2 0x0800 /* receive FIFO overfull rx queue 2 */ +#define FM_SRBFL2 0x1000 /* receive buffer full rx queue 2 */ +#define FM_SRABT2 0x2000 /* receive abort rx queue 2 */ +#define FM_SRBMT2 0x4000 /* receive buf empty rx queue 2 */ +#define FM_SRCOMP2 0x8000 /* receive comp rx queue 2 */ + +/* + * Supernet 3: + * Status Register 3, Lower 16 Bits (ST3L) + */ +#define FM_AF_BIST_DONE 0x0001 /* Address Filter BIST is done */ +#define FM_PLC_BIST_DONE 0x0002 /* internal PLC Bist is done */ +#define FM_PDX_BIST_DONE 0x0004 /* PDX BIST is done */ + /* Bit 3: reserved */ +#define FM_SICAMDAMAT 0x0010 /* Status internal CAM DA match */ +#define FM_SICAMDAXACT 0x0020 /* Status internal CAM DA exact match */ +#define FM_SICAMSAMAT 0x0040 /* Status internal CAM SA match */ +#define FM_SICAMSAXACT 0x0080 /* Status internal CAM SA exact match */ + +/* + * MAC State-Machine Register FM_STMCHN + */ +#define FM_MDRTAG 0x0004 /* tag bit of long word read */ +#define FM_SNPPND 0x0008 /* r/w from buffer mem. is pending */ +#define FM_TXSTAT 0x0070 /* transmitter state machine state */ +#define FM_RCSTAT 0x0380 /* receiver state machine state */ +#define FM_TM01 0x0c00 /* indicate token mode */ +#define FM_SIM 0x1000 /* indicate send immediate-mode */ +#define FM_REV 0xe000 /* FORMAC Plus revision number */ + +/* + * Supernet 3 + * Mode Register 3 + */ +#define FM_MENRS 0x0001 /* Ena enhanced rec status encoding */ +#define FM_MENXS 0x0002 /* Ena enhanced xmit status encoding */ +#define FM_MENXCT 0x0004 /* Ena EXACT/INEXACT matching */ +#define FM_MENAFULL 0x0008 /* Ena enh QCTRL encoding for AFULL */ +#define FM_MEIND 0x0030 /* Ena enh A,C indicator settings */ +#define FM_MENQCTRL 0x0040 /* Ena enh QCTRL encoding */ +#define FM_MENRQAUNLCK 0x0080 /* Ena rec q auto unlock */ +#define FM_MENDAS 0x0100 /* Ena DAS connections by cntr MUX */ +#define FM_MENPLCCST 0x0200 /* Ena Counter Segm test in PLC blck */ +#define FM_MENSGLINT 0x0400 /* Ena Vectored Interrupt reading */ +#define FM_MENDRCV 0x0800 /* Ena dual receive queue operation */ +#define FM_MENFCLOC 0x3000 /* Ena FC location within frm data */ +#define FM_MENTRCMD 0x4000 /* Ena ASYNC1 xmit only after command */ +#define FM_MENTDLPBK 0x8000 /* Ena TDAT to RDAT lkoopback */ + +/* + * Supernet 3 + * Frame Selection Register + */ +#define FM_RECV1 0x000f /* options for receive queue 1 */ +#define FM_RCV1_ALL (0<<0) /* receive all frames */ +#define FM_RCV1_LLC (1<<0) /* rec all LLC frames */ +#define FM_RCV1_SMT (2<<0) /* rec all SMT frames */ +#define FM_RCV1_NSMT (3<<0) /* rec non-SMT frames */ +#define FM_RCV1_IMP (4<<0) /* rec Implementor frames */ +#define FM_RCV1_MAC (5<<0) /* rec all MAC frames */ +#define FM_RCV1_SLLC (6<<0) /* rec all sync LLC frames */ +#define FM_RCV1_ALLC (7<<0) /* rec all async LLC frames */ +#define FM_RCV1_VOID (8<<0) /* rec all void frames */ +#define FM_RCV1_ALSMT (9<<0) /* rec all async LLC & SMT frames */ +#define FM_RECV2 0x00f0 /* options for receive queue 2 */ +#define FM_RCV2_ALL (0<<4) /* receive all other frames */ +#define FM_RCV2_LLC (1<<4) /* rec all LLC frames */ +#define FM_RCV2_SMT (2<<4) /* rec all SMT frames */ +#define FM_RCV2_NSMT (3<<4) /* rec non-SMT frames */ +#define FM_RCV2_IMP (4<<4) /* rec Implementor frames */ +#define FM_RCV2_MAC (5<<4) /* rec all MAC frames */ +#define FM_RCV2_SLLC (6<<4) /* rec all sync LLC frames */ +#define FM_RCV2_ALLC (7<<4) /* rec all async LLC frames */ +#define FM_RCV2_VOID (8<<4) /* rec all void frames */ +#define FM_RCV2_ALSMT (9<<4) /* rec all async LLC & SMT frames */ +#define FM_ENXMTADSWAP 0x4000 /* enh rec addr swap (phys -> can) */ +#define FM_ENRCVADSWAP 0x8000 /* enh tx addr swap (can -> phys) */ + +/* + * Supernet 3: + * Address Filter Command Register (AFCMD) + */ +#define FM_INST 0x0007 /* Address Filter Operation */ +#define FM_IINV_CAM (0<<0) /* Invalidate CAM */ +#define FM_IWRITE_CAM (1<<0) /* Write CAM */ +#define FM_IREAD_CAM (2<<0) /* Read CAM */ +#define FM_IRUN_BIST (3<<0) /* Run BIST */ +#define FM_IFIND (4<<0) /* Find */ +#define FM_IINV (5<<0) /* Invalidate */ +#define FM_ISKIP (6<<0) /* Skip */ +#define FM_ICL_SKIP (7<<0) /* Clear all SKIP bits */ + +/* + * Supernet 3: + * Address Filter Status Register (AFSTAT) + */ + /* Bit 0-4: reserved */ +#define FM_REV_NO 0x00e0 /* Revision Number of Address Filter */ +#define FM_BIST_DONE 0x0100 /* BIST complete */ +#define FM_EMPTY 0x0200 /* CAM empty */ +#define FM_ERROR 0x0400 /* Error (improper operation) */ +#define FM_MULT 0x0800 /* Multiple Match */ +#define FM_EXACT 0x1000 /* Exact Match */ +#define FM_FOUND 0x2000 /* Comparand found in CAM */ +#define FM_FULL 0x4000 /* CAM full */ +#define FM_DONE 0x8000 /* DONE indicator */ + +/* + * Supernet 3: + * BIST Signature Register (AFBIST) + */ +#define AF_BIST_SIGNAT 0x0553 /* Address Filter BIST Signature */ + +/* + * Supernet 3: + * Personality Register (AFPERS) + */ +#define FM_VALID 0x0001 /* CAM Entry Valid */ +#define FM_DA 0x0002 /* Destination Address */ +#define FM_DAX 0x0004 /* Destination Address Exact */ +#define FM_SA 0x0008 /* Source Address */ +#define FM_SAX 0x0010 /* Source Address Exact */ +#define FM_SKIP 0x0020 /* Skip this entry */ + +/* + * instruction set for command register 1 (NPADDR6-0 = 0x00) + */ +#define FM_IRESET 0x01 /* software reset */ +#define FM_IRMEMWI 0x02 /* load Memory Data Reg., inc MARR */ +#define FM_IRMEMWO 0x03 /* load MDR from buffer memory, n.i. */ +#define FM_IIL 0x04 /* idle/listen */ +#define FM_ICL 0x05 /* claim/listen */ +#define FM_IBL 0x06 /* beacon/listen */ +#define FM_ILTVX 0x07 /* load TVX timer from TVX reg */ +#define FM_INRTM 0x08 /* nonrestricted token mode */ +#define FM_IENTM 0x09 /* enter nonrestricted token mode */ +#define FM_IERTM 0x0a /* enter restricted token mode */ +#define FM_IRTM 0x0b /* restricted token mode */ +#define FM_ISURT 0x0c /* send unrestricted token */ +#define FM_ISRT 0x0d /* send restricted token */ +#define FM_ISIM 0x0e /* enter send-immediate mode */ +#define FM_IESIM 0x0f /* exit send-immediate mode */ +#define FM_ICLLS 0x11 /* clear synchronous queue lock */ +#define FM_ICLLA0 0x12 /* clear asynchronous queue 0 lock */ +#define FM_ICLLA1 0x14 /* clear asynchronous queue 1 lock */ +#define FM_ICLLA2 0x18 /* clear asynchronous queue 2 lock */ + /* SN3: reserved */ +#define FM_ICLLR 0x20 /* clear receive queue (SN3:1) lock */ +#define FM_ICLLR2 0x21 /* SN3: clear receive queue 2 lock */ +#define FM_ITRXBUS 0x22 /* SN3: Tristate X-Bus (SAS only) */ +#define FM_IDRXBUS 0x23 /* SN3: drive X-Bus */ +#define FM_ICLLAL 0x3f /* clear all queue locks */ + +/* + * instruction set for command register 2 (NPADDR6-0 = 0x01) + */ +#define FM_ITRS 0x01 /* transmit synchronous queue */ + /* SN3: reserved */ +#define FM_ITRA0 0x02 /* transmit asynchronous queue 0 */ + /* SN3: reserved */ +#define FM_ITRA1 0x04 /* transmit asynchronous queue 1 */ + /* SN3: reserved */ +#define FM_ITRA2 0x08 /* transmit asynchronous queue 2 */ + /* SN3: reserved */ +#define FM_IACTR 0x10 /* abort current transmit activity */ +#define FM_IRSTQ 0x20 /* reset transmit queues */ +#define FM_ISTTB 0x30 /* set tag bit */ +#define FM_IERSF 0x40 /* enable receive single frame */ + /* SN3: reserved */ +#define FM_ITR 0x50 /* SN3: Transmit Command */ + + +/* + * defines for PLC (Am79C864) + */ + +/* + * PLC read/write (r/w) registers + */ +#define PL_CNTRL_A 0x00 /* control register A (r/w) */ +#define PL_CNTRL_B 0x01 /* control register B (r/w) */ +#define PL_INTR_MASK 0x02 /* interrupt mask (r/w) */ +#define PL_XMIT_VECTOR 0x03 /* transmit vector register (r/w) */ +#define PL_VECTOR_LEN 0x04 /* transmit vector length (r/w) */ +#define PL_LE_THRESHOLD 0x05 /* link error event threshold (r/w) */ +#define PL_C_MIN 0x06 /* minimum connect state time (r/w) */ +#define PL_TL_MIN 0x07 /* min. line state transmit t. (r/w) */ +#define PL_TB_MIN 0x08 /* minimum break time (r/w) */ +#define PL_T_OUT 0x09 /* signal timeout (r/w) */ +#define PL_CNTRL_C 0x0a /* control register C (r/w) */ +#define PL_LC_LENGTH 0x0b /* link confidence test time (r/w) */ +#define PL_T_SCRUB 0x0c /* scrub time = MAC TVX (r/w) */ +#define PL_NS_MAX 0x0d /* max. noise time before break (r/w)*/ +#define PL_TPC_LOAD_V 0x0e /* TPC timer load value (write only) */ +#define PL_TNE_LOAD_V 0x0f /* TNE timer load value (write only) */ +#define PL_STATUS_A 0x10 /* status register A (read only) */ +#define PL_STATUS_B 0x11 /* status register B (read only) */ +#define PL_TPC 0x12 /* timer for PCM (ro) [20.48 us] */ +#define PL_TNE 0x13 /* time of noise event [0.32 us] */ +#define PL_CLK_DIV 0x14 /* TNE clock divider (read only) */ +#define PL_BIST_SIGNAT 0x15 /* built in self test signature (ro)*/ +#define PL_RCV_VECTOR 0x16 /* receive vector reg. (read only) */ +#define PL_INTR_EVENT 0x17 /* interrupt event reg. (read only) */ +#define PL_VIOL_SYM_CTR 0x18 /* violation symbol count. (read o) */ +#define PL_MIN_IDLE_CTR 0x19 /* minimum idle counter (read only) */ +#define PL_LINK_ERR_CTR 0x1a /* link error event ctr.(read only) */ +#ifdef MOT_ELM +#define PL_T_FOT_ASS 0x1e /* FOTOFF Assert Timer */ +#define PL_T_FOT_DEASS 0x1f /* FOTOFF Deassert Timer */ +#endif /* MOT_ELM */ + +#ifdef MOT_ELM +/* + * Special Quad-Elm Registers. + * A Quad-ELM consists of for ELMs and these additional registers. + */ +#define QELM_XBAR_W 0x80 /* Crossbar Control ELM W */ +#define QELM_XBAR_X 0x81 /* Crossbar Control ELM X */ +#define QELM_XBAR_Y 0x82 /* Crossbar Control ELM Y */ +#define QELM_XBAR_Z 0x83 /* Crossbar Control ELM Z */ +#define QELM_XBAR_P 0x84 /* Crossbar Control Bus P */ +#define QELM_XBAR_S 0x85 /* Crossbar Control Bus S */ +#define QELM_XBAR_R 0x86 /* Crossbar Control Bus R */ +#define QELM_WR_XBAR 0x87 /* Write the Crossbar now (write) */ +#define QELM_CTR_W 0x88 /* Counter W */ +#define QELM_CTR_X 0x89 /* Counter X */ +#define QELM_CTR_Y 0x8a /* Counter Y */ +#define QELM_CTR_Z 0x8b /* Counter Z */ +#define QELM_INT_MASK 0x8c /* Interrupt mask register */ +#define QELM_INT_DATA 0x8d /* Interrupt data (event) register */ +#define QELM_ELMB 0x00 /* Elm base */ +#define QELM_ELM_SIZE 0x20 /* ELM size */ +#endif /* MOT_ELM */ +/* + * PLC control register A (PL_CNTRL_A: log. addr. 0x00) + * It is used for timer configuration, specification of PCM MAINT state option, + * counter interrupt frequency, PLC data path config. and Built In Self Test. + */ +#define PL_RUN_BIST 0x0001 /* begin running its Built In Self T.*/ +#define PL_RF_DISABLE 0x0002 /* disable the Repeat Filter state m.*/ +#define PL_SC_REM_LOOP 0x0004 /* remote loopback path */ +#define PL_SC_BYPASS 0x0008 /* by providing a physical bypass */ +#define PL_LM_LOC_LOOP 0x0010 /* loop path just after elastic buff.*/ +#define PL_EB_LOC_LOOP 0x0020 /* loop path just prior to PDT/PDR IF*/ +#define PL_FOT_OFF 0x0040 /* assertion of /FOTOFF pin of PLC */ +#define PL_LOOPBACK 0x0080 /* it cause the /LPBCK pin ass. low */ +#define PL_MINI_CTR_INT 0x0100 /* partially contr. when bit is ass. */ +#define PL_VSYM_CTR_INT 0x0200 /* controls when int bit is asserted */ +#define PL_ENA_PAR_CHK 0x0400 /* enable parity check */ +#define PL_REQ_SCRUB 0x0800 /* limited access to scrub capability*/ +#define PL_TPC_16BIT 0x1000 /* causes the TPC as a 16 bit timer */ +#define PL_TNE_16BIT 0x2000 /* causes the TNE as a 16 bit timer */ +#define PL_NOISE_TIMER 0x4000 /* allows the noise timing function */ + +/* + * PLC control register B (PL_CNTRL_B: log. addr. 0x01) + * It contains signals and requeste to direct the process of PCM and it is also + * used to control the Line State Match interrupt. + */ +#define PL_PCM_CNTRL 0x0003 /* control PCM state machine */ +#define PL_PCM_NAF (0) /* state is not affected */ +#define PL_PCM_START (1) /* goes to the BREAK state */ +#define PL_PCM_TRACE (2) /* goes to the TRACE state */ +#define PL_PCM_STOP (3) /* goes to the OFF state */ + +#define PL_MAINT 0x0004 /* if OFF state --> MAINT state */ +#define PL_LONG 0x0008 /* perf. a long Link Confid.Test(LCT)*/ +#define PL_PC_JOIN 0x0010 /* if NEXT state --> JOIN state */ + +#define PL_PC_LOOP 0x0060 /* loopback used in the LCT */ +#define PL_NOLCT (0<<5) /* no LCT is performed */ +#define PL_TPDR (1<<5) /* PCM asserts transmit PDR */ +#define PL_TIDLE (2<<5) /* PCM asserts transmit idle */ +#define PL_RLBP (3<<5) /* trans. PDR & remote loopb. path */ + +#define PL_CLASS_S 0x0080 /* signif. that single att. station */ + +#define PL_MAINT_LS 0x0700 /* line state while in the MAINT st. */ +#define PL_M_QUI0 (0<<8) /* transmit QUIET line state */ +#define PL_M_IDLE (1<<8) /* transmit IDLE line state */ +#define PL_M_HALT (2<<8) /* transmit HALT line state */ +#define PL_M_MASTR (3<<8) /* transmit MASTER line state */ +#define PL_M_QUI1 (4<<8) /* transmit QUIET line state */ +#define PL_M_QUI2 (5<<8) /* transmit QUIET line state */ +#define PL_M_TPDR (6<<8) /* tr. PHY_DATA requ.-symbol is tr.ed*/ +#define PL_M_QUI3 (7<<8) /* transmit QUIET line state */ + +#define PL_MATCH_LS 0x7800 /* line state to be comp. with curr.*/ +#define PL_I_ANY (0<<11) /* Int. on any change in *_LINE_ST */ +#define PL_I_IDLE (1<<11) /* Interrupt on IDLE line state */ +#define PL_I_HALT (2<<11) /* Interrupt on HALT line state */ +#define PL_I_MASTR (4<<11) /* Interrupt on MASTER line state */ +#define PL_I_QUIET (8<<11) /* Interrupt on QUIET line state */ + +#define PL_CONFIG_CNTRL 0x8000 /* control over scrub, byp. & loopb.*/ + +/* + * PLC control register C (PL_CNTRL_C: log. addr. 0x0a) + * It contains the scrambling control registers (PLC-S only) + */ +#define PL_C_CIPHER_ENABLE (1<<0) /* enable scrambler */ +#define PL_C_CIPHER_LPBCK (1<<1) /* loopback scrambler */ +#define PL_C_SDOFF_ENABLE (1<<6) /* enable SDOFF timer */ +#define PL_C_SDON_ENABLE (1<<7) /* enable SDON timer */ +#ifdef MOT_ELM +#define PL_C_FOTOFF_CTRL (3<<2) /* FOTOFF timer control */ +#define PL_C_FOTOFF_TIM (0<<2) /* FOTOFF use timer for (de)-assert */ +#define PL_C_FOTOFF_INA (2<<2) /* FOTOFF forced inactive */ +#define PL_C_FOTOFF_ACT (3<<2) /* FOTOFF forced active */ +#define PL_C_FOTOFF_SRCE (1<<4) /* FOTOFF source is PCM state != OFF */ +#define PL_C_RXDATA_EN (1<<5) /* Rec scr data forced to 0 */ +#define PL_C_SDNRZEN (1<<8) /* Monitor rec descr. data for act */ +#else /* nMOT_ELM */ +#define PL_C_FOTOFF_CTRL (3<<8) /* FOTOFF timer control */ +#define PL_C_FOTOFF_0 (0<<8) /* timer off */ +#define PL_C_FOTOFF_30 (1<<8) /* 30uS */ +#define PL_C_FOTOFF_50 (2<<8) /* 50uS */ +#define PL_C_FOTOFF_NEVER (3<<8) /* never */ +#define PL_C_SDON_TIMER (3<<10) /* SDON timer control */ +#define PL_C_SDON_084 (0<<10) /* 0.84 uS */ +#define PL_C_SDON_132 (1<<10) /* 1.32 uS */ +#define PL_C_SDON_252 (2<<10) /* 2.52 uS */ +#define PL_C_SDON_512 (3<<10) /* 5.12 uS */ +#define PL_C_SOFF_TIMER (3<<12) /* SDOFF timer control */ +#define PL_C_SOFF_076 (0<<12) /* 0.76 uS */ +#define PL_C_SOFF_132 (1<<12) /* 1.32 uS */ +#define PL_C_SOFF_252 (2<<12) /* 2.52 uS */ +#define PL_C_SOFF_512 (3<<12) /* 5.12 uS */ +#define PL_C_TSEL (3<<14) /* scrambler path select */ +#endif /* nMOT_ELM */ + +/* + * PLC status register A (PL_STATUS_A: log. addr. 0x10) + * It is used to report status information to the Node Processor about the + * Line State Machine (LSM). + */ +#ifdef MOT_ELM +#define PLC_INT_MASK 0xc000 /* ELM integration bits in status A */ +#define PLC_INT_C 0x0000 /* ELM Revision Band C */ +#define PLC_INT_CAMEL 0x4000 /* ELM integrated into CAMEL */ +#define PLC_INT_QE 0x8000 /* ELM integrated into Quad ELM */ +#define PLC_REV_MASK 0x3800 /* revision bits in status A */ +#define PLC_REVISION_B 0x0000 /* rev bits for ELM Rev B */ +#define PLC_REVISION_QA 0x0800 /* rev bits for ELM core in QELM-A */ +#else /* nMOT_ELM */ +#define PLC_REV_MASK 0xf800 /* revision bits in status A */ +#define PLC_REVISION_A 0x0000 /* revision bits for PLC */ +#define PLC_REVISION_S 0xf800 /* revision bits for PLC-S */ +#define PLC_REV_SN3 0x7800 /* revision bits for PLC-S in IFCP */ +#endif /* nMOT_ELM */ +#define PL_SYM_PR_CTR 0x0007 /* contains the LSM symbol pair Ctr. */ +#define PL_UNKN_LINE_ST 0x0008 /* unknown line state bit from LSM */ +#define PL_LSM_STATE 0x0010 /* state bit of LSM */ + +#define PL_LINE_ST 0x00e0 /* contains recogn. line state of LSM*/ +#define PL_L_NLS (0<<5) /* noise line state */ +#define PL_L_ALS (1<<5) /* activ line state */ +#define PL_L_UND (2<<5) /* undefined */ +#define PL_L_ILS4 (3<<5) /* idle l. s. (after 4 idle symbols) */ +#define PL_L_QLS (4<<5) /* quiet line state */ +#define PL_L_MLS (5<<5) /* master line state */ +#define PL_L_HLS (6<<5) /* halt line state */ +#define PL_L_ILS16 (7<<5) /* idle line state (after 16 idle s.)*/ + +#define PL_PREV_LINE_ST 0x0300 /* value of previous line state */ +#define PL_P_QLS (0<<8) /* quiet line state */ +#define PL_P_MLS (1<<8) /* master line state */ +#define PL_P_HLS (2<<8) /* halt line state */ +#define PL_P_ILS16 (3<<8) /* idle line state (after 16 idle s.)*/ + +#define PL_SIGNAL_DET 0x0400 /* 1=that signal detect is deasserted*/ + + +/* + * PLC status register B (PL_STATUS_B: log. addr. 0x11) + * It contains signals and status from the repeat filter and PCM state machine. + */ +#define PL_BREAK_REASON 0x0007 /* reason for PCM state mach.s to br.*/ +#define PL_B_NOT (0) /* PCM SM has not gone to BREAK state*/ +#define PL_B_PCS (1) /* PC_Start issued */ +#define PL_B_TPC (2) /* TPC timer expired after T_OUT */ +#define PL_B_TNE (3) /* TNE timer expired after NS_MAX */ +#define PL_B_QLS (4) /* quit line state detected */ +#define PL_B_ILS (5) /* idle line state detected */ +#define PL_B_HLS (6) /* halt line state detected */ + +#define PL_TCF 0x0008 /* transmit code flag (start exec.) */ +#define PL_RCF 0x0010 /* receive code flag (start exec.) */ +#define PL_LSF 0x0020 /* line state flag (l.s. has been r.)*/ +#define PL_PCM_SIGNAL 0x0040 /* indic. that XMIT_VECTOR hb.written*/ + +#define PL_PCM_STATE 0x0780 /* state bits of PCM state machine */ +#define PL_PC0 (0<<7) /* OFF - when /RST or PCM_CNTRL */ +#define PL_PC1 (1<<7) /* BREAK - entry point in start PCM*/ +#define PL_PC2 (2<<7) /* TRACE - to localize stuck Beacon*/ +#define PL_PC3 (3<<7) /* CONNECT - synchronize ends of conn*/ +#define PL_PC4 (4<<7) /* NEXT - to seperate the signalng*/ +#define PL_PC5 (5<<7) /* SIGNAL - PCM trans/rec. bit infos*/ +#define PL_PC6 (6<<7) /* JOIN - 1. state to activ conn. */ +#define PL_PC7 (7<<7) /* VERIFY - 2. - " - (3. ACTIVE) */ +#define PL_PC8 (8<<7) /* ACTIVE - PHY has been incorporated*/ +#define PL_PC9 (9<<7) /* MAINT - for test purposes or so + that PCM op. completely in softw. */ + +#define PL_PCI_SCRUB 0x0800 /* scrubbing function is being exec. */ + +#define PL_PCI_STATE 0x3000 /* Physical Connect. Insertion SM */ +#define PL_CI_REMV (0<<12) /* REMOVED */ +#define PL_CI_ISCR (1<<12) /* INSERT_SCRUB */ +#define PL_CI_RSCR (2<<12) /* REMOVE_SCRUB */ +#define PL_CI_INS (3<<12) /* INSERTED */ + +#define PL_RF_STATE 0xc000 /* state bit of repeate filter SM */ +#define PL_RF_REPT (0<<14) /* REPEAT */ +#define PL_RF_IDLE (1<<14) /* IDLE */ +#define PL_RF_HALT1 (2<<14) /* HALT1 */ +#define PL_RF_HALT2 (3<<14) /* HALT2 */ + + +/* + * PLC interrupt event register (PL_INTR_EVENT: log. addr. 0x17) + * It is read only and is clearde whenever it is read! + * It is used by the PLC to report events to the node processor. + */ +#define PL_PARITY_ERR 0x0001 /* p. error h.b.detected on TX9-0 inp*/ +#define PL_LS_MATCH 0x0002 /* l.s.== l.s. PLC_CNTRL_B's MATCH_LS*/ +#define PL_PCM_CODE 0x0004 /* transmit&receive | LCT complete */ +#define PL_TRACE_PROP 0x0008 /* master l.s. while PCM ACTIV|TRACE */ +#define PL_SELF_TEST 0x0010 /* QUIET|HALT while PCM in TRACE st. */ +#define PL_PCM_BREAK 0x0020 /* PCM has entered the BREAK state */ +#define PL_PCM_ENABLED 0x0040 /* asserted SC_JOIN, scrub. & ACTIV */ +#define PL_TPC_EXPIRED 0x0080 /* TPC timer reached zero */ +#define PL_TNE_EXPIRED 0x0100 /* TNE timer reached zero */ +#define PL_EBUF_ERR 0x0200 /* elastic buff. det. over-|underflow*/ +#define PL_PHYINV 0x0400 /* physical layer invalid signal */ +#define PL_VSYM_CTR 0x0800 /* violation symbol counter has incr.*/ +#define PL_MINI_CTR 0x1000 /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ +#define PL_LE_CTR 0x2000 /* link error event counter */ +#define PL_LSDO 0x4000 /* SDO input pin changed to a 1 */ +#define PL_NP_ERR 0x8000 /* NP has requested to r/w an inv. r.*/ + +/* + * The PLC interrupt mask register (PL_INTR_MASK: log. addr. 0x02) constr. is + * equal PL_INTR_EVENT register. + * For each set bit, the setting of corresponding bit generate an int to NP. + */ + +#ifdef MOT_ELM +/* + * Quad ELM Crosbar Control register values (QELM_XBAR_?) + */ +#define QELM_XOUT_IDLE 0x0000 /* Idles/Passthrough */ +#define QELM_XOUT_P 0x0001 /* Output to: Bus P */ +#define QELM_XOUT_S 0x0002 /* Output to: Bus S */ +#define QELM_XOUT_R 0x0003 /* Output to: Bus R */ +#define QELM_XOUT_W 0x0004 /* Output to: ELM W */ +#define QELM_XOUT_X 0x0005 /* Output to: ELM X */ +#define QELM_XOUT_Y 0x0006 /* Output to: ELM Y */ +#define QELM_XOUT_Z 0x0007 /* Output to: ELM Z */ + +/* + * Quad ELM Interrupt data and event registers. + */ +#define QELM_NP_ERR (1<<15) /* Node Processor Error */ +#define QELM_COUNT_Z (1<<7) /* Counter Z Interrupt */ +#define QELM_COUNT_Y (1<<6) /* Counter Y Interrupt */ +#define QELM_COUNT_X (1<<5) /* Counter X Interrupt */ +#define QELM_COUNT_W (1<<4) /* Counter W Interrupt */ +#define QELM_ELM_Z (1<<3) /* ELM Z Interrupt */ +#define QELM_ELM_Y (1<<2) /* ELM Y Interrupt */ +#define QELM_ELM_X (1<<1) /* ELM X Interrupt */ +#define QELM_ELM_W (1<<0) /* ELM W Interrupt */ +#endif /* MOT_ELM */ +/* + * PLC Timing Parameters + */ +#define TP_C_MIN 0xff9c /* 2 ms */ +#define TP_TL_MIN 0xfff0 /* 0.3 ms */ +#define TP_TB_MIN 0xff10 /* 5 ms */ +#define TP_T_OUT 0xd9db /* 200 ms */ +#define TP_LC_LENGTH 0xf676 /* 50 ms */ +#define TP_LC_LONGLN 0xa0a2 /* 500 ms */ +#define TP_T_SCRUB 0xff6d /* 3.5 ms */ +#define TP_NS_MAX 0xf021 /* 1.3 ms */ + +/* + * BIST values + */ +#define PLC_BIST 0x6ecd /* BIST signature for PLC */ +#define PLCS_BIST 0x5b6b /* BIST signature for PLC-S */ +#define PLC_ELM_B_BIST 0x6ecd /* BIST signature of ELM Rev. B */ +#define PLC_ELM_D_BIST 0x5b6b /* BIST signature of ELM Rev. D */ +#define PLC_CAM_A_BIST 0x9e75 /* BIST signature of CAMEL Rev. A */ +#define PLC_CAM_B_BIST 0x5b6b /* BIST signature of CAMEL Rev. B */ +#define PLC_IFD_A_BIST 0x9e75 /* BIST signature of IFDDI Rev. A */ +#define PLC_IFD_B_BIST 0x5b6b /* BIST signature of IFDDI Rev. B */ +#define PLC_QELM_A_BIST 0x5b6b /* BIST signature of QELM Rev. A */ + +/* + FDDI board recources + */ + +/* + * request register array (log. addr: RQA_A + a<<1 {a=0..7}) write only. + * It specifies to FORMAC+ the type of buffer memory access the host requires. + */ +#define RQ_NOT 0 /* not request */ +#define RQ_RES 1 /* reserved */ +#define RQ_SFW 2 /* special frame write */ +#define RQ_RRQ 3 /* read request: receive queue */ +#define RQ_WSQ 4 /* write request: synchronous queue */ +#define RQ_WA0 5 /* write requ.: asynchronous queue 0 */ +#define RQ_WA1 6 /* write requ.: asynchronous queue 1 */ +#define RQ_WA2 7 /* write requ.: asynchronous queue 2 */ + +#define SZ_LONG (sizeof(long)) + +/* + * FDDI defaults + * NOTE : In the ANSI docs, times are specified in units of "symbol time". + * AMD chips use BCLK as unit. 1 BCKL == 2 symbols + */ +#define COMPLREF ((u_long)32*256*256) /* two's complement 21 bit */ +#define MSTOBCLK(x) ((u_long)(x)*12500L) +#define MSTOTVX(x) (((u_long)(x)*1000L)/80/255) + +#endif /* _SUPERNET_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/targethw.h linux/drivers/net/skfp/h/targethw.h --- v2.2.17/drivers/net/skfp/h/targethw.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/targethw.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,173 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#ifndef _TARGETHW_ +#define _TARGETHW_ + + /* + * PCI Watermark definition + */ +#ifdef PCI +#define RX_WATERMARK 24 +#define TX_WATERMARK 24 +#define SK_ML_ID_1 0x20 +#define SK_ML_ID_2 0x30 +#endif + +#include "h/skfbi.h" +#ifndef TAG_MODE +#include "h/fplus.h" +#else +#include "h/fplustm.h" +#endif + +#ifndef HW_PTR +#ifdef MEM_MAPPED_IO +#define HW_PTR u_long +#else +#define HW_PTR u_short +#endif +#endif + +#ifdef MULT_OEM +#define OI_STAT_LAST 0 /* end of OEM data base */ +#define OI_STAT_PRESENT 1 /* entry present but not empty */ +#define OI_STAT_VALID 2 /* holds valid ID, but is not active */ +#define OI_STAT_ACTIVE 3 /* holds valid ID, entry is active */ + /* active = adapter is supported */ + +/* Memory representation of IDs must match representation in adapter. */ +struct s_oem_ids { + u_char oi_status ; /* Stat: last, present, valid, active */ + u_char oi_mark[5] ; /* "PID00" .. "PID07" .. */ + u_char oi_id[4] ; /* id bytes, representation as */ + /* defined by hardware, */ +#ifdef PCI + u_char oi_sub_id[4] ; /* sub id bytes, representation as */ + /* defined by hardware, */ +#endif +#ifdef ISA + u_char oi_logo_len ; /* the length of the adapter logo */ + u_char oi_logo[6] ; /* the adapter logo */ + u_char oi_reserved1 ; +#endif /* ISA */ +} ; +#endif /* MULT_OEM */ + + +struct s_smt_hw { + /* + * global + */ + HW_PTR iop ; /* IO base address */ + short dma ; /* DMA channel */ + short irq ; /* IRQ level */ + short eprom ; /* FLASH prom */ +#ifndef PCI + short DmaWriteExtraBytes ; /* add bytes for DMA write */ +#endif + +#ifndef SYNC + u_short n_a_send ; /* pending send requests */ +#endif + +#if (defined(EISA) || defined(MCA) || defined(PCI)) + short slot ; /* slot number */ + short max_slots ; /* maximum number of slots */ +#endif + +#if (defined(PCI) || defined(MCA)) + short wdog_used ; /* TRUE if the watch dog is used */ +#endif + +#ifdef MCA + short slot_32 ; /* 32bit slot (1) or 16bit slot (0) */ + short rev ; /* Board revision (FMx_REV). */ + short VFullRead ; /* V_full value for DMA read */ + short VFullWrite ; /* V_full value for DMA write */ +#endif + +#ifdef EISA + short led ; /* LED for FE card */ + + short dma_rmode ; /* read mode */ + short dma_wmode ; /* write mode */ + short dma_emode ; /* extend mode */ + + /* DMA controller channel dependent io addresses */ + u_short dma_base_word_count ; + u_short dma_base_address ; + u_short dma_base_address_page ; +#endif + +#ifdef PCI + u_short pci_handle ; /* handle to access the BIOS func */ + u_long is_imask ; /* int maske for the int source reg */ + u_long phys_mem_addr ; /* physical memory address */ + u_short mc_dummy ; /* work around for MC compiler bug */ + /* + * state of the hardware + */ + u_short hw_state ; /* started or stopped */ + +#define STARTED 1 +#define STOPPED 0 + + int hw_is_64bit ; /* does we have a 64 bit adapter */ +#endif + +#ifdef TAG_MODE + u_long pci_fix_value ; /* value parsed by PCIFIX */ +#endif + + /* + * hwt.c + */ + u_long t_start ; /* HWT start */ + u_long t_stop ; /* HWT stop */ + u_short timer_activ ; /* HWT timer active */ + + /* + * PIC + */ + u_char pic_a1 ; + u_char pic_21 ; + + /* + * GENERIC ; do not modify beyond this line + */ + + /* + * physical and canonical address + */ + struct fddi_addr fddi_home_addr ; + struct fddi_addr fddi_canon_addr ; + struct fddi_addr fddi_phys_addr ; + + /* + * mac variables + */ + struct mac_parameter mac_pa ; /* tmin, tmax, tvx, treq .. */ + struct mac_counter mac_ct ; /* recv., lost, error */ + u_short mac_ring_is_up ; /* ring is up flag */ + + struct s_smt_fp fp ; /* formac+ */ + +#ifdef MULT_OEM + struct s_oem_ids *oem_id ; /* pointer to selected id */ + int oem_min_status ; /* IDs to take care of */ +#endif /* MULT_OEM */ + +} ; +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/targetos.h linux/drivers/net/skfp/h/targetos.h --- v2.2.17/drivers/net/skfp/h/targetos.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/targetos.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,164 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +/* + * Operating system specific definitions for driver and + * hardware module. + */ + +#ifndef TARGETOS_H +#define TARGETOS_H + + +//-------- those should go into include/linux/pci.h +#define PCI_VENDOR_ID_SK 0x1148 +#define PCI_DEVICE_ID_SK_FP 0x4000 +//-------- + + + +//-------- those should go into include/linux/if_fddi.h +#define FDDI_MAC_HDR_LEN 13 + +#define FDDI_RII 0x01 /* routing information bit */ +#define FDDI_RCF_DIR_BIT 0x80 +#define FDDI_RCF_LEN_MASK 0x1f +#define FDDI_RCF_BROADCAST 0x8000 +#define FDDI_RCF_LIMITED_BROADCAST 0xA000 +#define FDDI_RCF_FRAME2K 0x20 +#define FDDI_RCF_FRAME4K 0x30 +//-------- + + +#undef ADDR + +#include +#include +#include +#include +#include +#include +#include + +// is redefined by linux, but we need our definition +#undef ADDR +#ifdef MEM_MAPPED_IO +#define ADDR(a) (char far *) smc->hw.iop+(a) +#else +#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) +#endif + +#include "h/hwmtm.h" + +#define TRUE 1 +#define FALSE 0 + +// HWM Definitions +// ----------------------- +#define FDDI_TRACE(string, arg1, arg2, arg3) // Performance analysis. +#ifdef PCI +#define NDD_TRACE(string, arg1, arg2, arg3) // Performance analysis. +#endif // PCI +#define SMT_PAGESIZE PAGE_SIZE // Size of a memory page (power of 2). +// ----------------------- + + +// SMT Definitions +// ----------------------- +#define TICKS_PER_SECOND HZ +#define SMC_VERSION 1 +// ----------------------- + + +// OS-Driver Definitions +// ----------------------- +#define NO_ADDRESS 0xffe0 /* No Device (I/O) Address */ +#define SKFP_MAX_NUM_BOARDS 8 /* maximum number of PCI boards */ + +#define SK_BUS_TYPE_PCI 0 +#define SK_BUS_TYPE_EISA 1 + +#define FP_IO_LEN 256 /* length of IO area used */ + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int + +#define MAX_TX_QUEUE_LEN 20 // number of packets queued by driver +#define MAX_FRAME_SIZE 4550 + +#define RX_LOW_WATERMARK NUM_RECEIVE_BUFFERS / 2 +#define TX_LOW_WATERMARK NUM_TRANSMIT_BUFFERS - 2 + +/* +** Include the IOCTL stuff +*/ +#include + +#define SKFPIOCTL SIOCDEVPRIVATE + +struct s_skfp_ioctl { + unsigned short cmd; /* Command to run */ + unsigned short len; /* Length of the data buffer */ + unsigned char *data; /* Pointer to the data buffer */ +}; + +/* +** Recognised ioctl commands for the driver +*/ +#define SKFP_GET_STATS 0x05 /* Get the driver statistics */ +#define SKFP_CLR_STATS 0x06 /* Zero out the driver statistics */ + +// The per-adapter driver structure +struct s_smt_os { + struct device *dev; + struct device *next_module; + u32 bus_type;/* bus type (0 == PCI, 1 == EISA) */ + struct pci_dev pdev; /* PCI device structure */ + + unsigned long base_addr; + unsigned char factory_mac_addr[8]; + ulong SharedMemSize; + ulong SharedMemHeap; + void* SharedMemAddr; + + ulong QueueSkb; + struct sk_buff_head SendSkbQueue; + + ulong MaxFrameSize; + u8 ResetRequested; + + // MAC statistics structure + struct fddi_statistics MacStat; + + // receive into this local buffer if no skb available + // data will be not valid, because multiple RxDs can + // point here at the same time, it must be at least + // MAX_FRAME_SIZE bytes in size + unsigned char *LocalRxBuffer; + + // Version (required by SMT module). + u_long smc_version ; + + // Required by Hardware Module (HWM). + struct hw_modul hwm ; + + // For SMP-savety + spinlock_t DriverLock; + +}; + +typedef struct s_smt_os skfddi_priv; + +#endif // _TARGETOS_ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/h/types.h linux/drivers/net/skfp/h/types.h --- v2.2.17/drivers/net/skfp/h/types.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/h/types.h Fri Sep 1 13:48:23 2000 @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * (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. + * + ******************************************************************************/ + +#include +/* + ---------------------- + Basic SMT system types + ---------------------- +*/ +#ifndef _TYPES_ +#define _TYPES_ + +#define _packed +#ifndef far +#define far +#endif +#ifndef _far +#define _far +#endif + +#ifndef MEM_MAPPED_IO // "normal" IO +#define inp(p) inb(p) +#define inpw(p) inw(p) +#define inpd(p) inl(p) +#define outp(p,c) outb(c,p) +#define outpw(p,s) outw(s,p) +#define outpd(p,l) outl(l,p) +#else // memory mapped io +#define inp(a) readb(a) +#define inpw(a) readw(a) +#define inpd(a) readl(a) +#define outp(a,v) writeb(v, a) +#define outpw(a,v) writew(v, a) +#define outpd(a,v) writel(v, a) +#endif + +#endif /* _TYPES_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/hwmtm.c linux/drivers/net/skfp/hwmtm.c --- v2.2.17/drivers/net/skfp/hwmtm.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/hwmtm.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,2241 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +#ifndef lint +static char const ID_sccs[] = "@(#)hwmtm.c 1.40 99/05/31 (C) SK" ; +#endif + +#define HWMTM + +#ifndef FDDI +#define FDDI +#endif + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "h/skfbiinc.h" + +/* + ------------------------------------------------------------- + DOCUMENTATION + ------------------------------------------------------------- + BEGIN_MANUAL_ENTRY(DOCUMENTATION) + + T B D + + END_MANUAL_ENTRY +*/ +/* + ------------------------------------------------------------- + LOCAL VARIABLES: + ------------------------------------------------------------- +*/ +#ifdef COMMON_MB_POOL +static SMbuf *mb_start = 0 ; +static SMbuf *mb_free = 0 ; +static int mb_init = FALSE ; +static int call_count = 0 ; +#endif + +/* + ------------------------------------------------------------- + EXTERNE VARIABLES: + ------------------------------------------------------------- +*/ + +#ifdef DEBUG +#ifndef DEBUG_BRD +extern struct smt_debug debug ; +#endif +#endif + +#ifdef NDIS_OS2 +extern u_char offDepth ; +extern u_char force_irq_pending ; +#endif + +/* + ------------------------------------------------------------- + LOCAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +static void queue_llc_rx(), smt_to_llc(), + init_txd_ring(), init_rxd_ring(), + queue_txd_mb() ; + +static u_long init_descr_ring(), repair_txd_ring(), + repair_rxd_ring() ; + +static SMbuf *get_llc_rx(), *get_txd_mb() ; + + +/* + ------------------------------------------------------------- + EXTERNAL FUNCTIONS: + ------------------------------------------------------------- +*/ +/* The external SMT functions are listed in cmtdef.h */ + +extern void *mac_drv_get_space(), *mac_drv_get_desc_mem(), + init_board(), mac_drv_fill_rxd(), + plc1_irq(), mac_drv_tx_complete(), + plc2_irq(), mac1_irq(), + mac2_irq(), mac3_irq(), + timer_irq(), mac_drv_rx_complete(), + mac_drv_requeue_rxd(), init_plc(), + mac_drv_clear_rxd(), llc_restart_tx(), + ev_dispatcher(), smt_force_irq() ; + +#ifdef USE_OS_CPY +extern void hwm_cpy_rxd2mb(), hwm_cpy_txd2mb() ; +#endif +#ifdef ALL_RX_COMPLETE +extern void mac_drv_all_receives_complete() ; +#endif + +extern u_long mac_drv_virt2phys(), dma_master() ; + +#ifdef NDIS_OS2 +extern void post_proc() ; +#else +extern void dma_complete() ; +#endif + +extern int init_fplus(), mac_drv_rx_init() ; + +/* + ------------------------------------------------------------- + PUBLIC FUNCTIONS: + ------------------------------------------------------------- +*/ + void process_receive(), smt_send_mbuf(), + fddi_isr(), mac_drv_clear_txd(), + smt_free_mbuf(), init_driver_fplus(), + mac_drv_rx_mode(), init_fddi_driver(), + mac_drv_clear_tx_queue(), + mac_drv_clear_rx_queue(), + hwm_tx_frag(), hwm_rx_frag() ; + + int mac_drv_rx_frag(), mac_drv_init(), + hwm_tx_init() ; + + u_int mac_drv_check_space() ; + + SMbuf *smt_get_mbuf() ; + +#ifdef DEBUG + void mac_drv_debug_lev() ; +#endif + +/* + ------------------------------------------------------------- + MACROS: + ------------------------------------------------------------- +*/ +#ifndef UNUSED +#ifdef lint +#define UNUSED(x) (x) = (x) +#else +#define UNUSED(x) +#endif +#endif + +#ifdef USE_CAN_ADDR +#define MA smc->hw.fddi_canon_addr.a +#define GROUP_ADDR_BIT 0x01 +#else +#define MA smc->hw.fddi_home_addr.a +#define GROUP_ADDR_BIT 0x80 +#endif + +#define RXD_TXD_COUNT (HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\ + SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) + +#ifdef MB_OUTSIDE_SMC +#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\ + MAX_MBUF*sizeof(SMbuf)) +#define EXT_VIRT_MEM_2 ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) +#else +#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) +#endif + + /* + * define critical read for 16 Bit drivers + */ +#if defined(NDIS_OS2) || defined(ODI2) +#define CR_READ(var) ((var) & 0xffff0000 | ((var) & 0xffff)) +#else +#define CR_READ(var) (u_long)(var) +#endif + +#define IMASK_SLOW (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ + IS_R1_C | IS_XA_C | IS_XS_C) + +/* + ------------------------------------------------------------- + INIT- AND SMT FUNCTIONS: + ------------------------------------------------------------- +*/ + + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_check_space) + * u_int mac_drv_check_space() + * + * function DOWNCALL (drvsr.c) + * This function calculates the needed non virtual + * memory for MBufs, RxD and TxD descriptors etc. + * needed by the driver. + * + * return u_int memory in bytes + * + * END_MANUAL_ENTRY + */ +u_int mac_drv_check_space() +{ +#ifdef MB_OUTSIDE_SMC +#ifdef COMMON_MB_POOL + call_count++ ; + if (call_count == 1) { + return(EXT_VIRT_MEM) ; + } + else { + return(EXT_VIRT_MEM_2) ; + } +#else + return (EXT_VIRT_MEM) ; +#endif +#else + return (0) ; +#endif +} + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_init) + * void mac_drv_init(smc) + * + * function DOWNCALL (drvsr.c) + * In this function the hardware module allocates it's + * memory. + * The operating system dependent module should call + * mac_drv_init once, after the adatper is detected. + * END_MANUAL_ENTRY + */ +int mac_drv_init(smc) +struct s_smc *smc ; +{ + if (sizeof(struct s_smt_fp_rxd) % 16) { + SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ; + } + if (sizeof(struct s_smt_fp_txd) % 16) { + SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ; + } + + /* + * get the required memory for the RxDs and TxDs + */ + if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *) + mac_drv_get_desc_mem(smc,(u_int) + (RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) { + return(1) ; /* no space the hwm modul can't work */ + } + + /* + * get the memory for the SMT MBufs + */ +#ifndef MB_OUTSIDE_SMC + smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ; +#else +#ifndef COMMON_MB_POOL + if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc, + MAX_MBUF*sizeof(SMbuf)))) { + return(1) ; /* no space the hwm modul can't work */ + } +#else + if (!mb_start) { + if (!(mb_start = (SMbuf *) mac_drv_get_space(smc, + MAX_MBUF*sizeof(SMbuf)))) { + return(1) ; /* no space the hwm modul can't work */ + } + } +#endif +#endif + return (0) ; +} + +/* + * BEGIN_MANUAL_ENTRY(init_driver_fplus) + * init_driver_fplus(smc) + * + * Sets hardware modul specific values for the mode register 2 + * (e.g. the byte alignment for the received frames, the position of the + * least significant byte etc.) + * END_MANUAL_ENTRY + */ +void init_driver_fplus(smc) +struct s_smc *smc ; +{ + smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ; + +#ifdef PCI + smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ; +#endif + smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ; + +#ifdef USE_CAN_ADDR + /* enable address bit swapping */ + smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ; +#endif +} + +static u_long init_descr_ring(smc,start,count) +struct s_smc *smc ; +union s_fp_descr volatile *start; +int count ; +{ + int i ; + union s_fp_descr volatile *d1 ; + union s_fp_descr volatile *d2 ; + u_long phys ; + + DB_GEN("descr ring starts at = %x ",(void *)start,0,3) ; + for (i=count-1, d1=start; i ; i--) { + d2 = d1 ; + d1++ ; /* descr is owned by the host */ + d2->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ; + d2->r.rxd_next = &d1->r ; + phys = mac_drv_virt2phys(smc,(void *)d1) ; + d2->r.rxd_nrdadr = AIX_REVERSE(phys) ; + } + DB_GEN("descr ring ends at = %x ",(void *)d1,0,3) ; + d1->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ; + d1->r.rxd_next = &start->r ; + phys = mac_drv_virt2phys(smc,(void *)start) ; + d1->r.rxd_nrdadr = AIX_REVERSE(phys) ; + + for (i=count, d1=start; i ; i--) { + DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ; + d1++; + } + return(phys) ; +} + +static void init_txd_ring(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_txd volatile *ds ; + struct s_smt_tx_queue *queue ; + u_long phys ; + + /* + * initialize the transmit descriptors + */ + ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p + + SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ; + queue = smc->hw.fp.tx[QUEUE_A0] ; + DB_GEN("Init async TxD ring, %d TxDs ",HWM_ASYNC_TXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + HWM_ASYNC_TXD_COUNT) ; + phys = AIX_REVERSE(ds->txd_ntdadr) ; + ds++ ; + queue->tx_curr_put = queue->tx_curr_get = ds ; + ds-- ; + queue->tx_free = HWM_ASYNC_TXD_COUNT ; + queue->tx_used = 0 ; + outpd(ADDR(B5_XA_DA),phys) ; + + ds = (struct s_smt_fp_txd volatile *) ((char *)ds + + HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ; + queue = smc->hw.fp.tx[QUEUE_S] ; + DB_GEN("Init sync TxD ring, %d TxDs ",HWM_SYNC_TXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + HWM_SYNC_TXD_COUNT) ; + phys = AIX_REVERSE(ds->txd_ntdadr) ; + ds++ ; + queue->tx_curr_put = queue->tx_curr_get = ds ; + queue->tx_free = HWM_SYNC_TXD_COUNT ; + queue->tx_used = 0 ; + outpd(ADDR(B5_XS_DA),phys) ; +} + +static void init_rxd_ring(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_rxd volatile *ds ; + struct s_smt_rx_queue *queue ; + u_long phys ; + + /* + * initialize the receive descriptors + */ + ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ; + queue = smc->hw.fp.rx[QUEUE_R1] ; + DB_GEN("Init RxD ring, %d RxDs ",SMT_R1_RXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + SMT_R1_RXD_COUNT) ; + phys = AIX_REVERSE(ds->rxd_nrdadr) ; + ds++ ; + queue->rx_curr_put = queue->rx_curr_get = ds ; + queue->rx_free = SMT_R1_RXD_COUNT ; + queue->rx_used = 0 ; + outpd(ADDR(B4_R1_DA),phys) ; +} + +/* + * BEGIN_MANUAL_ENTRY(init_fddi_driver) + * void init_fddi_driver(smc,mac_addr) + * + * initializes the driver and it's variables + * + * END_MANUAL_ENTRY + */ +void init_fddi_driver(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; /* canonical address */ +{ + SMbuf *mb ; + int i ; + + init_board(smc,mac_addr) ; + (void)init_fplus(smc) ; + + /* + * initialize the SMbufs for the SMT + */ +#ifndef COMMON_MB_POOL + mb = smc->os.hwm.mbuf_pool.mb_start ; + smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ; + for (i = 0; i < MAX_MBUF; i++) { + mb->sm_use_count = 1 ; + smt_free_mbuf(smc,mb) ; + mb++ ; + } +#else + mb = mb_start ; + if (!mb_init) { + mb_free = 0 ; + for (i = 0; i < MAX_MBUF; i++) { + mb->sm_use_count = 1 ; + smt_free_mbuf(smc,mb) ; + mb++ ; + } + mb_init = TRUE ; + } +#endif + + /* + * initialize the other variables + */ + smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ; + smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ; + smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ; + smc->os.hwm.pass_llc_promisc = TRUE ; + smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ; + smc->os.hwm.detec_count = 0 ; + smc->os.hwm.rx_break = 0 ; + smc->os.hwm.rx_len_error = 0 ; + smc->os.hwm.isr_flag = FALSE ; + + /* + * make sure that the start pointer is 16 byte aligned + */ + i = 16 - ((long)smc->os.hwm.descr_p & 0xf) ; + if (i != 16) { + DB_GEN("i = %d",i,0,3) ; + smc->os.hwm.descr_p = (union s_fp_descr volatile *) + ((char *)smc->os.hwm.descr_p+i) ; + } + DB_GEN("pt to descr area = %x",(void *)smc->os.hwm.descr_p,0,3) ; + + init_txd_ring(smc) ; + init_rxd_ring(smc) ; + mac_drv_fill_rxd(smc) ; + + init_plc(smc) ; +} + + +SMbuf *smt_get_mbuf(smc) +struct s_smc *smc ; +{ + register SMbuf *mb ; + +#ifndef COMMON_MB_POOL + mb = smc->os.hwm.mbuf_pool.mb_free ; +#else + mb = mb_free ; +#endif + if (mb) { +#ifndef COMMON_MB_POOL + smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ; +#else + mb_free = mb->sm_next ; +#endif + mb->sm_off = 8 ; + mb->sm_use_count = 1 ; + } + DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ; + return (mb) ; /* May be NULL */ +} + +void smt_free_mbuf(smc, mb) +struct s_smc *smc ; +SMbuf *mb; +{ + + if (mb) { + mb->sm_use_count-- ; + DB_GEN("free_mbuf: sm_use_count = %d",mb->sm_use_count,0,3) ; + /* + * If the use_count is != zero the MBuf is queued + * more than once and must not queued into the + * free MBuf queue + */ + if (!mb->sm_use_count) { + DB_GEN("free SMbuf: mb = %x",(void *)mb,0,3) ; +#ifndef COMMON_MB_POOL + mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ; + smc->os.hwm.mbuf_pool.mb_free = mb ; +#else + mb->sm_next = mb_free ; + mb_free = mb ; +#endif + } + } + else + SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; +} + + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_repair_descr) + * void mac_drv_repair_descr(smc) + * + * function called from SMT (HWM / hwmtm.c) + * The BMU is idle when this function is called. + * Mac_drv_repair_descr sets up the physical address + * for all receive and transmit queues where the BMU + * should continue. + * It may be that the BMU was reseted during a fragmented + * transfer. In this case there are some fragments which will + * never completed by the BMU. The OWN bit of this fragments + * must be switched to be owned by the host. + * + * Give a start command to the receive BMU. + * Start the transmit BMUs if transmit frames pending. + * + * END_MANUAL_ENTRY + */ +void mac_drv_repair_descr(smc) +struct s_smc *smc ; +{ + u_long phys ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ; + return ; + } + + /* + * repair tx queues: don't start + */ + phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ; + outpd(ADDR(B5_XA_DA),phys) ; + if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) { + outpd(ADDR(B0_XA_CSR),CSR_START) ; + } + phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ; + outpd(ADDR(B5_XS_DA),phys) ; + if (smc->hw.fp.tx_q[QUEUE_S].tx_used) { + outpd(ADDR(B0_XS_CSR),CSR_START) ; + } + + /* + * repair rx queues + */ + phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ; + outpd(ADDR(B4_R1_DA),phys) ; + outpd(ADDR(B0_R1_CSR),CSR_START) ; +} + +static u_long repair_txd_ring(smc,queue) +struct s_smc *smc ; +struct s_smt_tx_queue *queue ; +{ + int i ; + int tx_used ; + u_long phys ; + u_long tbctrl ; + struct s_smt_fp_txd volatile *t ; + + SK_UNUSED(smc) ; + + t = queue->tx_curr_get ; + tx_used = queue->tx_used ; + for (i = tx_used+queue->tx_free-1 ; i ; i-- ) { + t = t->txd_next ; + } + phys = AIX_REVERSE(t->txd_ntdadr) ; + + t = queue->tx_curr_get ; + while (tx_used) { + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; + tbctrl = AIX_REVERSE(t->txd_tbctrl) ; + + if (tbctrl & BMU_OWN) { + if (tbctrl & BMU_STF) { + break ; /* exit the loop */ + } + else { + /* + * repair the descriptor + */ + t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ; + } + } + phys = AIX_REVERSE(t->txd_ntdadr) ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + t = t->txd_next ; + tx_used-- ; + } + return(phys) ; +} + +/* + * Repairs the receive descriptor ring and returns the physical address + * where the BMU should continue working. + * + * o The physical address where the BMU was stopped has to be + * determined. This is the next RxD after rx_curr_get with an OWN + * bit set. + * o The BMU should start working at beginning of the next frame. + * RxDs with an OWN bit set but with a reset STF bit should be + * skipped and owned by the driver (OWN = 0). + */ +static u_long repair_rxd_ring(smc,queue) +struct s_smc *smc ; +struct s_smt_rx_queue *queue ; +{ + int i ; + int rx_used ; + u_long phys ; + u_long rbctrl ; + struct s_smt_fp_rxd volatile *r ; + + SK_UNUSED(smc) ; + + r = queue->rx_curr_get ; + rx_used = queue->rx_used ; + for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) { + r = r->rxd_next ; + } + phys = AIX_REVERSE(r->rxd_nrdadr) ; + + r = queue->rx_curr_get ; + while (rx_used) { + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + rbctrl = AIX_REVERSE(r->rxd_rbctrl) ; + + if (rbctrl & BMU_OWN) { + if (rbctrl & BMU_STF) { + break ; /* exit the loop */ + } + else { + /* + * repair the descriptor + */ + r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; + } + } + phys = AIX_REVERSE(r->rxd_nrdadr) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + rx_used-- ; + } + return(phys) ; +} + + +/* + ------------------------------------------------------------- + INTERRUPT SERVICE ROUTINE: + ------------------------------------------------------------- +*/ + +/* + * BEGIN_MANUAL_ENTRY(fddi_isr) + * void fddi_isr(smc) + * + * function DOWNCALL (drvsr.c) + * interrupt service routine, handles the interrupt requests + * generated by the FDDI adapter. + * + * NOTE: The operating system dependent module must garantee that the + * interrupts of the adapter are disabled when it calls fddi_isr. + * + * About the USE_BREAK_ISR mechanismn: + * + * The main requirement of this mechanismn is to force an timer IRQ when + * leaving process_receive() with leave_isr set. process_receive() may + * be called at any time from anywhere! + * To be sure we don't miss such event we set 'force_irq' per default. + * We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND + * 'force_irq' are set. 'force_irq' may be reset if a receive complete + * IRQ is pending. + * + * END_MANUAL_ENTRY + */ +void fddi_isr(smc) +struct s_smc *smc ; +{ + u_long is ; /* ISR source */ + u_short stu, stl ; + SMbuf *mb ; + +#ifdef USE_BREAK_ISR + int force_irq ; +#endif + +#ifdef ODI2 + if (smc->os.hwm.rx_break) { + mac_drv_fill_rxd(smc) ; + if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) { + smc->os.hwm.rx_break = 0 ; + process_receive(smc) ; + } + else { + smc->os.hwm.detec_count = 0 ; + smt_force_irq(smc) ; + } + } +#endif + smc->os.hwm.isr_flag = TRUE ; + +#ifdef USE_BREAK_ISR + force_irq = TRUE ; + if (smc->os.hwm.leave_isr) { + smc->os.hwm.leave_isr = FALSE ; + process_receive(smc) ; + } +#endif + + while ((is = GET_ISR() & ISR_MASK)) { + NDD_TRACE("CH0B",is,0,0) ; + DB_GEN("ISA = 0x%x",is,0,7) ; + + if (is & IMASK_SLOW) { + NDD_TRACE("CH1b",is,0,0) ; + if (is & IS_PLINT1) { /* PLC1 */ + plc1_irq(smc) ; + } + if (is & IS_PLINT2) { /* PLC2 */ + plc2_irq(smc) ; + } + if (is & IS_MINTR1) { /* FORMAC+ STU1(U/L) */ + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + DB_GEN("Slow transmit complete",0,0,6) ; + mac1_irq(smc,stu,stl) ; + } + if (is & IS_MINTR2) { /* FORMAC+ STU2(U/L) */ + stu= inpw(FM_A(FM_ST2U)) ; + stl= inpw(FM_A(FM_ST2L)) ; + DB_GEN("Slow receive complete",0,0,6) ; + DB_GEN("stl = %x : stu = %x",stl,stu,7) ; + mac2_irq(smc,stu,stl) ; + } + if (is & IS_MINTR3) { /* FORMAC+ STU3(U/L) */ + stu= inpw(FM_A(FM_ST3U)) ; + stl= inpw(FM_A(FM_ST3L)) ; + DB_GEN("FORMAC Mode Register 3",0,0,6) ; + mac3_irq(smc,stu,stl) ; + } + if (is & IS_TIMINT) { /* Timer 82C54-2 */ + timer_irq(smc) ; +#ifdef NDIS_OS2 + force_irq_pending = 0 ; +#endif + /* + * out of RxD detection + */ + if (++smc->os.hwm.detec_count > 4) { + /* + * check out of RxD condition + */ + process_receive(smc) ; + } + } + if (is & IS_TOKEN) { /* Restricted Token Monitor */ + rtm_irq(smc) ; + } + if (is & IS_R1_P) { /* Parity error rx queue 1 */ + /* clear IRQ */ + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ; + SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; + } + if (is & IS_R1_C) { /* Encoding error rx queue 1 */ + /* clear IRQ */ + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ; + } + if (is & IS_XA_C) { /* Encoding error async tx q */ + /* clear IRQ */ + outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ; + } + if (is & IS_XS_C) { /* Encoding error sync tx q */ + /* clear IRQ */ + outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ; + } + } + + /* + * Fast Tx complete Async/Sync Queue (BMU service) + */ + if (is & (IS_XS_F|IS_XA_F)) { + DB_GEN("Fast tx complete queue",0,0,6) ; + /* + * clear IRQ, Note: no IRQ is lost, because + * we always service both queues + */ + outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ; + outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ; + mac_drv_clear_txd(smc) ; + llc_restart_tx(smc) ; + } + + /* + * Fast Rx Complete (BMU service) + */ + if (is & IS_R1_F) { + DB_GEN("Fast receive complete",0,0,6) ; + /* clear IRQ */ +#ifndef USE_BREAK_ISR + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; + process_receive(smc) ; +#else + process_receive(smc) ; + if (smc->os.hwm.leave_isr) { + force_irq = FALSE ; + } else { + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; + process_receive(smc) ; + } +#endif + } + +#ifndef NDIS_OS2 + while ((mb = get_llc_rx(smc))) { + smt_to_llc(smc,mb) ; + } +#else + if (offDepth) + post_proc() ; + + while (!offDepth && (mb = get_llc_rx(smc))) { + smt_to_llc(smc,mb) ; + } + + if (!offDepth && smc->os.hwm.rx_break) { + process_receive(smc) ; + } +#endif + if (smc->q.ev_get != smc->q.ev_put) { + NDD_TRACE("CH2a",0,0,0) ; + ev_dispatcher(smc) ; + } +#ifdef NDIS_OS2 + post_proc() ; + if (offDepth) { /* leave fddi_isr because */ + break ; /* indications not allowed */ + } +#endif +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr) { + break ; /* leave fddi_isr */ + } +#endif + + /* NOTE: when the isr is left, no rx is pending */ + } /* end of interrupt source polling loop */ + +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr && force_irq) { + smt_force_irq(smc) ; + } +#endif + smc->os.hwm.isr_flag = FALSE ; + NDD_TRACE("CH0E",0,0,0) ; +} + + +/* + ------------------------------------------------------------- + RECEIVE FUNCTIONS: + ------------------------------------------------------------- +*/ + +#ifndef NDIS_OS2 +/* + * BEGIN_MANUAL_ENTRY(mac_drv_rx_mode) + * void mac_drv_rx_mode(smc,mode) + * + * function DOWNCALL (fplus.c) + * Corresponding to the parameter mode, the operating system + * dependent module can activate several receive modes. + * + * para mode = 1: RX_ENABLE_ALLMULTI enable all multicasts + * = 2: RX_DISABLE_ALLMULTI disable "enable all multicasts" + * = 3: RX_ENABLE_PROMISC enable promiscuous + * = 4: RX_DISABLE_PROMISC disable promiscuous + * = 5: RX_ENABLE_NSA enable rec. of all NSA frames + * (disabled after 'driver reset' & 'set station address') + * = 6: RX_DISABLE_NSA disable rec. of all NSA frames + * + * = 21: RX_ENABLE_PASS_SMT ( see description ) + * = 22: RX_DISABLE_PASS_SMT ( " " ) + * = 23: RX_ENABLE_PASS_NSA ( " " ) + * = 24: RX_DISABLE_PASS_NSA ( " " ) + * = 25: RX_ENABLE_PASS_DB ( " " ) + * = 26: RX_DISABLE_PASS_DB ( " " ) + * = 27: RX_DISABLE_PASS_ALL ( " " ) + * = 28: RX_DISABLE_LLC_PROMISC ( " " ) + * = 29: RX_ENABLE_LLC_PROMISC ( " " ) + * + * + * RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_SMT, the hardware module + * duplicates all SMT frames with the frame control + * FC_SMT_INFO and passes them to the LLC receive channel + * by calling mac_drv_rx_init. + * The SMT Frames which are sent by the local SMT and the NSA + * frames whose A- and C-Indicator is not set are also duplicated + * and passed. + * The receive mode RX_DISABLE_PASS_SMT disables the passing + * of SMT frames. + * + * RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_NSA, the hardware module + * duplicates all NSA frames with frame control FC_SMT_NSA + * and a set A-Indicator and passed them to the LLC + * receive channel by calling mac_drv_rx_init. + * All NSA Frames which are sent by the local SMT + * are also duplicated and passed. + * The receive mode RX_DISABLE_PASS_NSA disables the passing + * of NSA frames with the A- or C-Indicator set. + * + * NOTE: For fear that the hardware module receives NSA frames with + * a reset A-Indicator, the operating system dependent module + * has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA + * before activate the RX_ENABLE_PASS_NSA mode and after every + * 'driver reset' and 'set station address'. + * + * RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_DB, direct BEACON frames + * (FC_BEACON frame control) are passed to the LLC receive + * channel by mac_drv_rx_init. + * The receive mode RX_DISABLE_PASS_DB disables the passing + * of direct BEACON frames. + * + * RX_DISABLE_PASS_ALL + * + * Disables all special receives modes. It is equal to + * call mac_drv_set_rx_mode successively with the + * parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT, + * RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB. + * + * RX_ENABLE_LLC_PROMISC + * + * (default) all received LLC frames and all SMT/NSA/DBEACON + * frames depending on the attitude of the flags + * PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the + * LLC layer + * + * RX_DISABLE_LLC_PROMISC + * + * all received SMT/NSA/DBEACON frames depending on the + * attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON + * will be delivered to the LLC layer. + * all received LLC frames with a directed address, Multicast + * or Broadcast address will be delivered to the LLC + * layer too. + * + * END_MANUAL_ENTRY + */ +void mac_drv_rx_mode(smc,mode) +struct s_smc *smc ; +int mode ; +{ + switch(mode) { + case RX_ENABLE_PASS_SMT: + smc->os.hwm.pass_SMT = TRUE ; + break ; + case RX_DISABLE_PASS_SMT: + smc->os.hwm.pass_SMT = FALSE ; + break ; + case RX_ENABLE_PASS_NSA: + smc->os.hwm.pass_NSA = TRUE ; + break ; + case RX_DISABLE_PASS_NSA: + smc->os.hwm.pass_NSA = FALSE ; + break ; + case RX_ENABLE_PASS_DB: + smc->os.hwm.pass_DB = TRUE ; + break ; + case RX_DISABLE_PASS_DB: + smc->os.hwm.pass_DB = FALSE ; + break ; + case RX_DISABLE_PASS_ALL: + smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ; + smc->os.hwm.pass_DB = FALSE ; + smc->os.hwm.pass_llc_promisc = TRUE ; + mac_set_rx_mode(smc,RX_DISABLE_NSA) ; + break ; + case RX_DISABLE_LLC_PROMISC: + smc->os.hwm.pass_llc_promisc = FALSE ; + break ; + case RX_ENABLE_LLC_PROMISC: + smc->os.hwm.pass_llc_promisc = TRUE ; + break ; + case RX_ENABLE_ALLMULTI: + case RX_DISABLE_ALLMULTI: + case RX_ENABLE_PROMISC: + case RX_DISABLE_PROMISC: + case RX_ENABLE_NSA: + case RX_DISABLE_NSA: + default: + mac_set_rx_mode(smc,mode) ; + break ; + } +} +#endif /* ifndef NDIS_OS2 */ + +/* + * process receive queue + */ +void process_receive(smc) +struct s_smc *smc ; +{ + int i ; + int n ; + int frag_count ; /* number of RxDs of the curr rx buf */ + int used_frags ; /* number of RxDs of the curr frame */ + struct s_smt_rx_queue *queue ; /* points to the queue ctl struct */ + struct s_smt_fp_rxd volatile *r ; /* rxd pointer */ + struct s_smt_fp_rxd volatile *rxd ; /* first rxd of rx frame */ + u_long rbctrl ; /* receive buffer control word */ + u_long rfsw ; /* receive frame status word */ + u_short rx_used ; + u_char far *virt ; + char far *data ; + SMbuf *mb ; + u_char fc ; /* Frame control */ + int len ; /* Frame length */ + + smc->os.hwm.detec_count = 0 ; + queue = smc->hw.fp.rx[QUEUE_R1] ; + NDD_TRACE("RHxB",0,0,0) ; + for ( ; ; ) { + r = queue->rx_curr_get ; + rx_used = queue->rx_used ; + frag_count = 0 ; + +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr) { + goto rx_end ; + } +#endif +#ifdef NDIS_OS2 + if (offDepth) { + smc->os.hwm.rx_break = 1 ; + goto rx_end ; + } + smc->os.hwm.rx_break = 0 ; +#endif +#ifdef ODI2 + if (smc->os.hwm.rx_break) { + goto rx_end ; + } +#endif + n = 0 ; + do { + DB_RX("Check RxD %x for OWN and EOF",(void *)r,0,5) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + rbctrl = CR_READ(r->rxd_rbctrl) ; + rbctrl = AIX_REVERSE(rbctrl) ; + + if (rbctrl & BMU_OWN) { + NDD_TRACE("RHxE",r,rfsw,rbctrl) ; + DB_RX("End of RxDs",0,0,4) ; + goto rx_end ; + } + /* + * out of RxD detection + */ + if (!rx_used) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ; + /* Either we don't have an RxD or all + * RxDs are filled. Therefore it's allowed + * for to set the STOPPED flag */ + smc->hw.hw_state = STOPPED ; + mac_drv_clear_rx_queue(smc) ; + smc->hw.hw_state = STARTED ; + mac_drv_fill_rxd(smc) ; + smc->os.hwm.detec_count = 0 ; + goto rx_end ; + } + rfsw = AIX_REVERSE(r->rxd_rfsw) ; + if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) { + /* + * The BMU_STF bit is deleted, 1 frame is + * placed into more than 1 rx buffer + * + * skip frame by setting the rx len to 0 + * + * if fragment count == 0 + * The missing STF bit belongs to the + * current frame, search for the + * EOF bit to complete the frame + * else + * the fragment belongs to the next frame, + * exit the loop and process the frame + */ + SK_BREAK() ; + rfsw = 0 ; + if (frag_count) { + break ; + } + } + n += rbctrl & 0xffff ; + r = r->rxd_next ; + frag_count++ ; + rx_used-- ; + } while (!(rbctrl & BMU_EOF)) ; + used_frags = frag_count ; + DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ; + + /* may be next 2 DRV_BUF_FLUSH() can be skipped, because */ + /* BMU_ST_BUF will not be changed by the ASIC */ + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + while (rx_used && !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) { + DB_RX("Check STF bit in %x",(void *)r,0,5) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + frag_count++ ; + rx_used-- ; + } + DB_RX("STF bit found",0,0,5) ; + + /* + * The received frame is finished for the process receive + */ + rxd = queue->rx_curr_get ; + queue->rx_curr_get = r ; + queue->rx_free += frag_count ; + queue->rx_used = rx_used ; + + /* + * ASIC Errata no. 7 (STF - Bit Bug) + */ + rxd->rxd_rbctrl &= AIX_REVERSE(~BMU_STF) ; + + for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){ + DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; + dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); + } + smc->hw.fp.err_stats.err_valid++ ; + smc->mib.m[MAC0].fddiMACCopied_Ct++ ; + + /* the length of the data including the FC */ + len = (rfsw & RD_LENGTH) - 4 ; + + DB_RX("frame length = %d",len,0,4) ; + /* + * check the frame_lenght and all error flags + */ + if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){ + if (rfsw & RD_S_MSRABT) { + DB_RX("Frame aborted by the FORMAC",0,0,2) ; + smc->hw.fp.err_stats.err_abort++ ; + } + /* + * check frame status + */ + if (rfsw & RD_S_SEAC2) { + DB_RX("E-Indicator set",0,0,2) ; + smc->hw.fp.err_stats.err_e_indicator++ ; + } + if (rfsw & RD_S_SFRMERR) { + DB_RX("CRC error",0,0,2) ; + smc->hw.fp.err_stats.err_crc++ ; + } + if (rfsw & RX_FS_IMPL) { + DB_RX("Implementer frame",0,0,2) ; + smc->hw.fp.err_stats.err_imp_frame++ ; + } + goto abort_frame ; + } + if (len > FDDI_RAW_MTU-4) { + DB_RX("Frame to long error",0,0,2) ; + smc->hw.fp.err_stats.err_too_long++ ; + goto abort_frame ; + } + /* + * SUPERNET 3 Bug: FORMAC delivers status words + * of aborded frames to the BMU + */ + if (len <= 4) { + DB_RX("Frame length = 0",0,0,2) ; + goto abort_frame ; + } + + if (len != (n-4)) { + DB_RX("BMU: rx len differs: [%d:%d]",len,n,4); + smc->os.hwm.rx_len_error++ ; + goto abort_frame ; + } + + /* + * Check SA == MA + */ + virt = (u_char far *) rxd->rxd_virt ; + DB_RX("FC = %x",*virt,0,2) ; + if (virt[12] == MA[5] && + virt[11] == MA[4] && + virt[10] == MA[3] && + virt[9] == MA[2] && + virt[8] == MA[1] && + (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) { + goto abort_frame ; + } + + /* + * test if LLC frame + */ + if (rfsw & RX_FS_LLC) { + /* + * if pass_llc_promisc is disable + * if DA != Multicast or Broadcast or DA!=MA + * abort the frame + */ + if (!smc->os.hwm.pass_llc_promisc) { + if(!(virt[1] & GROUP_ADDR_BIT)) { + if (virt[6] != MA[5] || + virt[5] != MA[4] || + virt[4] != MA[3] || + virt[3] != MA[2] || + virt[2] != MA[1] || + virt[1] != MA[0]) { + DB_RX("DA != MA and not multi- or broadcast",0,0,2) ; + goto abort_frame ; + } + } + } + + /* + * LLC frame received + */ + DB_RX("LLC - receive",0,0,4) ; + mac_drv_rx_complete(smc,rxd,frag_count,len) ; + } + else { + if (!(mb = smt_get_mbuf(smc))) { + smc->hw.fp.err_stats.err_no_buf++ ; + DB_RX("No SMbuf; receive terminated",0,0,4) ; + goto abort_frame ; + } + data = smtod(mb,char *) - 1 ; + + /* + * copy the frame into a SMT_MBuf + */ +#ifdef USE_OS_CPY + hwm_cpy_rxd2mb(rxd,data,len) ; +#else + for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){ + n = AIX_REVERSE(r->rxd_rbctrl) & RD_LENGTH ; + DB_RX("cp SMT frame to mb: len = %d",n,0,6) ; + memcpy(data,r->rxd_virt,n) ; + data += n ; + } + data = smtod(mb,char *) - 1 ; +#endif + fc = *(char *)mb->sm_data = *data ; + mb->sm_len = len - 1 ; /* len - fc */ + data++ ; + + /* + * SMT frame received + */ + switch(fc) { + case FC_SMT_INFO : + smc->hw.fp.err_stats.err_smt_frame++ ; + DB_RX("SMT frame received ",0,0,5) ; + + if (smc->os.hwm.pass_SMT) { + DB_RX("pass SMT frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + + smt_received_pack(smc,mb,(int)(rfsw>>25)) ; + break ; + case FC_SMT_NSA : + smc->hw.fp.err_stats.err_smt_frame++ ; + DB_RX("SMT frame received ",0,0,5) ; + + /* if pass_NSA set pass the NSA frame or */ + /* pass_SMT set and the A-Indicator */ + /* is not set, pass the NSA frame */ + if (smc->os.hwm.pass_NSA || + (smc->os.hwm.pass_SMT && + !(rfsw & A_INDIC))) { + DB_RX("pass SMT frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + + smt_received_pack(smc,mb,(int)(rfsw>>25)) ; + break ; + case FC_BEACON : + if (smc->os.hwm.pass_DB) { + DB_RX("pass DB frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + smt_free_mbuf(smc,mb) ; + break ; + default : + /* + * unknown FC abord the frame + */ + DB_RX("unknown FC error",0,0,2) ; + smt_free_mbuf(smc,mb) ; + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count) ; + if ((fc & 0xf0) == FC_MAC) + smc->hw.fp.err_stats.err_mac_frame++ ; + else + smc->hw.fp.err_stats.err_imp_frame++ ; + + break ; + } + } + + DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; + NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ; + + continue ; + /*--------------------------------------------------------------------*/ +abort_frame: + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count) ; + + DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; + NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ; + } +rx_end: +#ifdef ALL_RX_COMPLETE + mac_drv_all_receives_complete(smc) ; +#endif + return ; /* lint bug: needs return detect end of function */ +} + +static void smt_to_llc(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + u_char fc ; + + DB_RX("send a queued frame to the llc layer",0,0,4) ; + smc->os.hwm.r.len = mb->sm_len ; + smc->os.hwm.r.mb_pos = smtod(mb,char *) ; + fc = *smc->os.hwm.r.mb_pos ; + (void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc, + smc->os.hwm.r.mb_pos,(int)mb->sm_len) ; + smt_free_mbuf(smc,mb) ; +} + +/* + * BEGIN_MANUAL_ENTRY(hwm_rx_frag) + * void hwm_rx_frag(smc,virt,phys,len,frame_status) + * + * function MACRO (hardware module, hwmtm.h) + * This function calls dma_master for preparing the + * system hardware for the DMA transfer and initializes + * the current RxD with the length and the physical and + * virtual address of the fragment. Furthermore, it sets the + * STF and EOF bits depending on the frame status byte, + * switches the OWN flag of the RxD, so that it is owned by the + * adapter and issues an rx_start. + * + * para virt virtual pointer to the fragment + * len the length of the fragment + * frame_status status of the frame, see design description + * + * NOTE: It is possible to call this function with a fragment length + * of zero. + * + * END_MANUAL_ENTRY + */ +void hwm_rx_frag(smc,virt,phys,len,frame_status) +struct s_smc *smc ; +char far *virt ; +u_long phys ; +int len ; +int frame_status ; +{ + struct s_smt_fp_rxd volatile *r ; + u_int rbctrl ; + + NDD_TRACE("RHfB",virt,len,frame_status) ; + DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ; + r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ; + r->rxd_virt = virt ; + r->rxd_rbadr = AIX_REVERSE(phys) ; + rbctrl = AIX_REVERSE( (((u_long)frame_status & + (FIRST_FRAG|LAST_FRAG))<<26) | + (((u_long) frame_status & FIRST_FRAG) << 21) | + BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ; + r->rxd_rbctrl = rbctrl ; + + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + outpd(ADDR(B0_R1_CSR),CSR_START) ; + smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ; + smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ; + smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ; + NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ; +} + +#ifndef NDIS_OS2 +/* + * BEGIN_MANUAL_ENTRY(mac_drv_rx_frag) + * int mac_drv_rx_frag(smc,virt,len) + * + * function DOWNCALL (hwmtm.c) + * mac_drv_rx_frag fills the fragment with a part of the frame. + * + * para virt the virtual address of the fragment + * len the length in bytes of the fragment + * + * return 0: success code, no errors possible + * + * END_MANUAL_ENTRY + */ +int mac_drv_rx_frag(smc,virt,len) +struct s_smc *smc ; +void far *virt ; +int len ; +{ + NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ; + + DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ; + memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ; + smc->os.hwm.r.mb_pos += len ; + + NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ; + return(0) ; +} +#endif + + +/* + * BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue) + * + * void mac_drv_clear_rx_queue(smc) + * struct s_smc *smc ; + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_rx_queue is called by the OS-specific module + * after it has issued a card_stop. + * In this case, the frames in the receive queue are obsolete and + * should be removed. For removing mac_drv_clear_rx_queue + * calls dma_master for each RxD and mac_drv_clear_rxd for each + * receive buffer. + * + * NOTE: calling sequence card_stop: + * CLI_FBI(), card_stop(), + * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), + * + * NOTE: The caller is responsible that the BMUs are idle + * when this function is called. + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_rx_queue(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_rxd volatile *r ; + struct s_smt_fp_rxd volatile *next_rxd ; + struct s_smt_rx_queue *queue ; + int frag_count ; + int i ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ; + return ; + } + + queue = smc->hw.fp.rx[QUEUE_R1] ; + DB_RX("clear_rx_queue",0,0,5) ; + + /* + * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers + */ + r = queue->rx_curr_get ; + while (queue->rx_used) { + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ; + r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; + frag_count = 1 ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + while (r != queue->rx_curr_put && + !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) { + DB_RX("Check STF bit in %x",(void *)r,0,5) ; + r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + frag_count++ ; + } + DB_RX("STF bit found",0,0,5) ; + next_rxd = r ; + + for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){ + DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; + dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); + } + + DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ", + (void *)queue->rx_curr_get,frag_count,5) ; + mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ; + + queue->rx_curr_get = next_rxd ; + queue->rx_used -= frag_count ; + queue->rx_free += frag_count ; + } +} + + +/* + ------------------------------------------------------------- + SEND FUNCTIONS: + ------------------------------------------------------------- +*/ + +/* + * BEGIN_MANUAL_ENTRY(hwm_tx_init) + * int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status) + * + * function DOWN_CALL (hardware module, hwmtm.c) + * hwm_tx_init checks if the frame can be sent through the + * corresponding send queue. + * + * para fc the frame control. To determine through which + * send queue the frame should be transmitted. + * 0x50 - 0x57: asynchronous LLC frame + * 0xD0 - 0xD7: synchronous LLC frame + * 0x41, 0x4F: SMT frame to the network + * 0x42: SMT frame to the network and to the local SMT + * 0x43: SMT frame to the local SMT + * frag_count count of the fragments for this frame + * frame_len length of the frame + * frame_status status of the frame, the send queue bit is already + * specified + * + * return frame_status + * + * END_MANUAL_ENTRY + */ +int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status) +struct s_smc *smc ; +u_char fc ; +int frag_count ; +int frame_len ; +int frame_status ; +{ + NDD_TRACE("THiB",fc,frag_count,frame_len) ; + smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ; + smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ; + smc->os.hwm.tx_len = frame_len ; + DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ; + if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) { + frame_status |= LAN_TX ; + } + else { + switch (fc) { + case FC_SMT_INFO : + case FC_SMT_NSA : + frame_status |= LAN_TX ; + break ; + case FC_SMT_LOC : + frame_status |= LOC_TX ; + break ; + case FC_SMT_LAN_LOC : + frame_status |= LAN_TX | LOC_TX ; + break ; + default : + SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ; + } + } + if (!smc->hw.mac_ring_is_up) { + frame_status &= ~LAN_TX ; + frame_status |= RING_DOWN ; + DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; + } + if (frag_count > smc->os.hwm.tx_p->tx_free) { +#ifndef NDIS_OS2 + mac_drv_clear_txd(smc) ; + if (frag_count > smc->os.hwm.tx_p->tx_free) { + DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; + frame_status &= ~LAN_TX ; + frame_status |= OUT_OF_TXD ; + } +#else + DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; + frame_status &= ~LAN_TX ; + frame_status |= OUT_OF_TXD ; +#endif + } + DB_TX("frame_status = %x",frame_status,0,3) ; + NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ; + return(frame_status) ; +} + +/* + * BEGIN_MANUAL_ENTRY(hwm_tx_frag) + * void hwm_tx_frag(smc,virt,phys,len,frame_status) + * + * function DOWNCALL (hardware module, hwmtm.c) + * If the frame should be sent to the LAN, this function calls + * dma_master, fills the current TxD with the virtual and the + * physical address, sets the STF and EOF bits dependent on + * the frame status, and requests the BMU to start the + * transmit. + * If the frame should be sent to the local SMT, an SMT_MBuf + * is allocated if the FIRST_FRAG bit is set in the frame_status. + * The fragment of the frame is copied into the SMT MBuf. + * The function smt_received_pack is called if the LAST_FRAG + * bit is set in the frame_status word. + * + * para virt virtual pointer to the fragment + * len the length of the fragment + * frame_status status of the frame, see design description + * + * return nothing returned, no parameter is modified + * + * NOTE: It is possible to invoke this macro with a fragment length + * of zero. + * + * END_MANUAL_ENTRY + */ +void hwm_tx_frag(smc,virt,phys,len,frame_status) +struct s_smc *smc ; +char far *virt ; +u_long phys ; +int len ; +int frame_status ; +{ + struct s_smt_fp_txd volatile *t ; + struct s_smt_tx_queue *queue ; + u_int tbctrl ; + + queue = smc->os.hwm.tx_p ; + + NDD_TRACE("THfB",virt,len,frame_status) ; + /* Bug fix: AF / May 31 1999 (#missing) + * snmpinfo problem reported by IBM is caused by invalid + * t-pointer (txd) if LAN_TX is not set but LOC_TX only. + * Set: t = queue->tx_curr_put here ! + */ + t = queue->tx_curr_put ; + + DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ; + if (frame_status & LAN_TX) { + /* '*t' is already defined */ + DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ; + t->txd_virt = virt ; + t->txd_txdscr = AIX_REVERSE(smc->os.hwm.tx_descr) ; + t->txd_tbadr = AIX_REVERSE(phys) ; + tbctrl = AIX_REVERSE((((u_long)frame_status & + (FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) | + BMU_OWN|BMU_CHECK |len) ; + t->txd_tbctrl = tbctrl ; + +#ifndef AIX + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(queue->tx_bmu_ctl,CSR_START) ; +#else /* ifndef AIX */ + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + if (frame_status & QUEUE_A0) { + outpd(ADDR(B0_XA_CSR),CSR_START) ; + } + else { + outpd(ADDR(B0_XS_CSR),CSR_START) ; + } +#endif + queue->tx_free-- ; + queue->tx_used++ ; + queue->tx_curr_put = t->txd_next ; + if (frame_status & LAST_FRAG) { + smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; + } + } + if (frame_status & LOC_TX) { + DB_TX("LOC_TX: ",0,0,3) ; + if (frame_status & FIRST_FRAG) { + if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) { + smc->hw.fp.err_stats.err_no_buf++ ; + DB_TX("No SMbuf; transmit terminated",0,0,4) ; + } + else { + smc->os.hwm.tx_data = + smtod(smc->os.hwm.tx_mb,char *) - 1 ; +#ifdef USE_OS_CPY +#ifdef PASS_1ST_TXD_2_TX_COMP + hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, + smc->os.hwm.tx_len) ; +#endif +#endif + } + } + if (smc->os.hwm.tx_mb) { +#ifndef USE_OS_CPY + DB_TX("copy fragment into MBuf ",0,0,3) ; + memcpy(smc->os.hwm.tx_data,virt,len) ; + smc->os.hwm.tx_data += len ; +#endif + if (frame_status & LAST_FRAG) { +#ifdef USE_OS_CPY +#ifndef PASS_1ST_TXD_2_TX_COMP + /* + * hwm_cpy_txd2mb(txd,data,len) copies 'len' + * bytes from the virtual pointer in 'rxd' + * to 'data'. The virtual pointer of the + * os-specific tx-buffer should be written + * in the LAST txd. + */ + hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, + smc->os.hwm.tx_len) ; +#endif /* nPASS_1ST_TXD_2_TX_COMP */ +#endif /* USE_OS_CPY */ + smc->os.hwm.tx_data = + smtod(smc->os.hwm.tx_mb,char *) - 1 ; + *(char *)smc->os.hwm.tx_mb->sm_data = + *smc->os.hwm.tx_data ; + smc->os.hwm.tx_data++ ; + smc->os.hwm.tx_mb->sm_len = + smc->os.hwm.tx_len - 1 ; + DB_TX("pass LLC frame to SMT ",0,0,3) ; + smt_received_pack(smc,smc->os.hwm.tx_mb, + RD_FS_LOCAL) ; + } + } + } + NDD_TRACE("THfE",t,queue->tx_free,0) ; +} + + +/* + * queues a receive for later send + */ +static void queue_llc_rx(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ; + smc->os.hwm.queued_rx_frames++ ; + mb->sm_next = (SMbuf *)NULL ; + if (smc->os.hwm.llc_rx_pipe == 0) { + smc->os.hwm.llc_rx_pipe = mb ; + } + else { + smc->os.hwm.llc_rx_tail->sm_next = mb ; + } + smc->os.hwm.llc_rx_tail = mb ; + + /* + * force an timer IRQ to receive the data + */ + if (!smc->os.hwm.isr_flag) { + smt_force_irq(smc) ; + } +} + +/* + * get a SMbuf from the llc_rx_queue + */ +static SMbuf *get_llc_rx(smc) +struct s_smc *smc ; +{ + SMbuf *mb ; + + if ((mb = smc->os.hwm.llc_rx_pipe)) { + smc->os.hwm.queued_rx_frames-- ; + smc->os.hwm.llc_rx_pipe = mb->sm_next ; + } + DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ; + return(mb) ; +} + +/* + * queues a transmit SMT MBuf during the time were the MBuf is + * queued the TxD ring + */ +static void queue_txd_mb(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ; + smc->os.hwm.queued_txd_mb++ ; + mb->sm_next = (SMbuf *)NULL ; + if (smc->os.hwm.txd_tx_pipe == 0) { + smc->os.hwm.txd_tx_pipe = mb ; + } + else { + smc->os.hwm.txd_tx_tail->sm_next = mb ; + } + smc->os.hwm.txd_tx_tail = mb ; +} + +/* + * get a SMbuf from the txd_tx_queue + */ +static SMbuf *get_txd_mb(smc) +struct s_smc *smc ; +{ + SMbuf *mb ; + + if ((mb = smc->os.hwm.txd_tx_pipe)) { + smc->os.hwm.queued_txd_mb-- ; + smc->os.hwm.txd_tx_pipe = mb->sm_next ; + } + DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ; + return(mb) ; +} + +/* + * SMT Send function + */ +void smt_send_mbuf(smc,mb,fc) +struct s_smc *smc; +SMbuf *mb; +int fc; +{ + char far *data ; + int len ; + int n ; + int i ; + int frag_count ; + int frame_status ; + SK_LOC_DECL(char far,*virt[3]) ; + int frag_len[3] ; + struct s_smt_tx_queue *queue ; + struct s_smt_fp_txd volatile *t ; + u_long phys ; + u_int tbctrl ; + + NDD_TRACE("THSB",mb,fc,0) ; + DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ; + + mb->sm_off-- ; /* set to fc */ + mb->sm_len++ ; /* + fc */ + data = smtod(mb,char *) ; + *data = fc ; + if (fc == FC_SMT_LOC) + *data = FC_SMT_INFO ; + + /* + * determine the frag count and the virt addresses of the frags + */ + frag_count = 0 ; + len = mb->sm_len ; + while (len) { + n = SMT_PAGESIZE - ((long)data & (SMT_PAGESIZE-1)) ; + if (n >= len) { + n = len ; + } + DB_TX("frag: virt/len = 0x%x/%d ",(void *)data,n,5) ; + virt[frag_count] = data ; + frag_len[frag_count] = n ; + frag_count++ ; + len -= n ; + data += n ; + } + + /* + * determine the frame status + */ + queue = smc->hw.fp.tx[QUEUE_A0] ; + if (fc == FC_BEACON || fc == FC_SMT_LOC) { + frame_status = LOC_TX ; + } + else { + frame_status = LAN_TX ; + if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) || + (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO))) + frame_status |= LOC_TX ; + } + + if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) { + if (frame_status &= ~LAN_TX) { + DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; + } + else { + DB_TX("Ring is down: terminate transmission",0,0,2) ; + smt_free_mbuf(smc,mb) ; + return ; + } + } + DB_TX("frame_status = 0x%x ",frame_status,0,5) ; + + if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) { + mb->sm_use_count = 2 ; + } + + if (frame_status & LAN_TX) { + t = queue->tx_curr_put ; + frame_status |= FIRST_FRAG ; + for (i = 0; i < frag_count; i++) { + DB_TX("init TxD = 0x%x",(void *)t,0,5) ; + if (i == frag_count-1) { + frame_status |= LAST_FRAG ; + t->txd_txdscr = AIX_REVERSE(TX_DESCRIPTOR | + (((u_long)(mb->sm_len-1)&3) << 27)) ; + } + t->txd_virt = virt[i] ; + phys = dma_master(smc, (void far *)virt[i], + frag_len[i], DMA_RD|SMT_BUF) ; + t->txd_tbadr = AIX_REVERSE(phys) ; + tbctrl = AIX_REVERSE((((u_long) frame_status & + (FIRST_FRAG|LAST_FRAG)) << 26) | + BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ; + t->txd_tbctrl = tbctrl ; +#ifndef AIX + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(queue->tx_bmu_ctl,CSR_START) ; +#else + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(ADDR(B0_XA_CSR),CSR_START) ; +#endif + frame_status &= ~FIRST_FRAG ; + queue->tx_curr_put = t = t->txd_next ; + queue->tx_free-- ; + queue->tx_used++ ; + } + smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; + queue_txd_mb(smc,mb) ; + } + + if (frame_status & LOC_TX) { + DB_TX("pass Mbuf to LLC queue",0,0,5) ; + queue_llc_rx(smc,mb) ; + } + + /* + * We need to unqueue the free SMT_MBUFs here, because it may + * be that the SMT want's to send more than 1 frame for one down call + */ + mac_drv_clear_txd(smc) ; + NDD_TRACE("THSE",t,queue->tx_free,frag_count) ; +} + +/* BEGIN_MANUAL_ENTRY(mac_drv_clear_txd) + * void mac_drv_clear_txd(smc) + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_txd searches in both send queues for TxD's + * which were finished by the adapter. It calls dma_complete + * for each TxD. If the last fragment of an LLC frame is + * reached, it calls mac_drv_tx_complete to release the + * send buffer. + * + * return nothing + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_txd(smc) +struct s_smc *smc ; +{ + struct s_smt_tx_queue *queue ; + struct s_smt_fp_txd volatile *t1 ; + struct s_smt_fp_txd volatile *t2=0 ; + SMbuf *mb ; + u_long tbctrl ; + int i ; + int frag_count ; + int n ; + + NDD_TRACE("THcB",0,0,0) ; + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + t1 = queue->tx_curr_get ; + DB_TX("clear_txd: QUEUE = %d (0=sync/1=async)",i,0,5) ; + + for ( ; ; ) { + frag_count = 0 ; + + do { + DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ; + DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ; + tbctrl = CR_READ(t1->txd_tbctrl) ; + tbctrl = AIX_REVERSE(tbctrl) ; + + if (tbctrl & BMU_OWN || !queue->tx_used){ + DB_TX("End of TxDs queue %d",i,0,4) ; + goto free_next_queue ; /* next queue */ + } + t1 = t1->txd_next ; + frag_count++ ; + } while (!(tbctrl & BMU_EOF)) ; + + t1 = queue->tx_curr_get ; + for (n = frag_count; n; n--) { + tbctrl = AIX_REVERSE(t1->txd_tbctrl) ; + dma_complete(smc, + (union s_fp_descr volatile *) t1, + (int) (DMA_RD | + ((tbctrl & BMU_SMT_TX) >> 18))) ; + t2 = t1 ; + t1 = t1->txd_next ; + } + + if (tbctrl & BMU_SMT_TX) { + mb = get_txd_mb(smc) ; + smt_free_mbuf(smc,mb) ; + } + else { +#ifndef PASS_1ST_TXD_2_TX_COMP + DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ; + mac_drv_tx_complete(smc,t2) ; +#else + DB_TX("mac_drv_tx_comp for TxD 0x%x", + queue->tx_curr_get,0,4) ; + mac_drv_tx_complete(smc,queue->tx_curr_get) ; +#endif + } + queue->tx_curr_get = t1 ; + queue->tx_free += frag_count ; + queue->tx_used -= frag_count ; + } +free_next_queue: ; + } + NDD_TRACE("THcE",0,0,0) ; +} + +/* + * BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue) + * + * void mac_drv_clear_tx_queue(smc) + * struct s_smc *smc ; + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_tx_queue is called from the SMT when + * the RMT state machine has entered the ISOLATE state. + * This function is also called by the os-specific module + * after it has called the function card_stop(). + * In this case, the frames in the send queues are obsolete and + * should be removed. + * + * note calling sequence: + * CLI_FBI(), card_stop(), + * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), + * + * NOTE: The caller is responsible that the BMUs are idle + * when this function is called. + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_tx_queue(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_txd volatile *t ; + struct s_smt_tx_queue *queue ; + int tx_used ; + int i ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ; + return ; + } + + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + DB_TX("clear_tx_queue: QUEUE = %d (0=sync/1=async)",i,0,5) ; + + /* + * switch the OWN bit of all pending frames to the host + */ + t = queue->tx_curr_get ; + tx_used = queue->tx_used ; + while (tx_used) { + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; + DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ; + t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + t = t->txd_next ; + tx_used-- ; + } + } + + /* + * release all TxD's for both send queues + */ + mac_drv_clear_txd(smc) ; + + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + t = queue->tx_curr_get ; + + /* + * write the phys pointer of the NEXT descriptor into the + * BMU's current address descriptor pointer and set + * tx_curr_get and tx_curr_put to this position + */ + if (i == QUEUE_S) { + outpd(ADDR(B5_XS_DA),AIX_REVERSE(t->txd_ntdadr)) ; + } + else { + outpd(ADDR(B5_XA_DA),AIX_REVERSE(t->txd_ntdadr)) ; + } + + queue->tx_curr_put = queue->tx_curr_get->txd_next ; + queue->tx_curr_get = queue->tx_curr_put ; + } +} + + +/* + ------------------------------------------------------------- + TEST FUNCTIONS: + ------------------------------------------------------------- +*/ + +#ifdef DEBUG +/* + * BEGIN_MANUAL_ENTRY(mac_drv_debug_lev) + * void mac_drv_debug_lev(smc,flag,lev) + * + * function DOWNCALL (drvsr.c) + * To get a special debug info the user can assign a debug level + * to any debug flag. + * + * para flag debug flag, possible values are: + * = 0: reset all debug flags (the defined level is + * ignored) + * = 1: debug.d_smtf + * = 2: debug.d_smt + * = 3: debug.d_ecm + * = 4: debug.d_rmt + * = 5: debug.d_cfm + * = 6: debug.d_pcm + * + * = 10: debug.d_os.hwm_rx (hardware module receive path) + * = 11: debug.d_os.hwm_tx(hardware module transmit path) + * = 12: debug.d_os.hwm_gen(hardware module general flag) + * + * lev debug level + * + * END_MANUAL_ENTRY + */ +void mac_drv_debug_lev(smc,flag,lev) +struct s_smc *smc ; +int flag ; +int lev ; +{ + switch(flag) { + case (int)NULL: + DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ; + DB_P.d_cfm = 0 ; + DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ; +#ifdef SBA + DB_P.d_sba = 0 ; +#endif +#ifdef ESS + DB_P.d_ess = 0 ; +#endif + break ; + case DEBUG_SMTF: + DB_P.d_smtf = lev ; + break ; + case DEBUG_SMT: + DB_P.d_smt = lev ; + break ; + case DEBUG_ECM: + DB_P.d_ecm = lev ; + break ; + case DEBUG_RMT: + DB_P.d_rmt = lev ; + break ; + case DEBUG_CFM: + DB_P.d_cfm = lev ; + break ; + case DEBUG_PCM: + DB_P.d_pcm = lev ; + break ; + case DEBUG_SBA: +#ifdef SBA + DB_P.d_sba = lev ; +#endif + break ; + case DEBUG_ESS: +#ifdef ESS + DB_P.d_ess = lev ; +#endif + break ; + case DB_HWM_RX: + DB_P.d_os.hwm_rx = lev ; + break ; + case DB_HWM_TX: + DB_P.d_os.hwm_tx = lev ; + break ; + case DB_HWM_GEN: + DB_P.d_os.hwm_gen = lev ; + break ; + default: + break ; + } +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/hwt.c linux/drivers/net/skfp/hwt.c --- v2.2.17/drivers/net/skfp/hwt.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/hwt.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,314 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + * Timer Driver for FBI board (timer chip 82C54) + */ + +/* + * Modifications: + * + * 28-Jun-1994 sw Edit v1.6. + * MCA: Added support for the SK-NET FDDI-FM2 adapter. The + * following functions have been added(+) or modified(*): + * hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*) + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)hwt.c 1.13 97/04/23 (C) SK " ; +#endif + +/* + * Prototypes of local functions. + */ +/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */ +/*static*/ void hwt_restart() ; + +/************************ + * + * hwt_start + * + * Start hardware timer (clock ticks are 16us). + * + * void hwt_start( + * struct s_smc *smc, + * u_long time) ; + * In + * smc - A pointer to the SMT Context structure. + * + * time - The time in units of 16us to load the timer with. + * Out + * Nothing. + * + ************************/ +#define HWT_MAX (65000) + +void hwt_start(smc, time) +struct s_smc *smc ; +u_long time ; +{ + u_short cnt ; + + if (time > HWT_MAX) + time = HWT_MAX ; + + smc->hw.t_start = time ; + smc->hw.t_stop = 0L ; + + cnt = (u_short)time ; + /* + * if time < 16 us + * time = 16 us + */ + if (!cnt) + cnt++ ; +#ifndef PCI + /* + * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0 + * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT) + */ + OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ + OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */ + OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */ + /* + * start timer by switching counter 0 to mode 3 + * T0 resolution 16 us (CLK0=0.16us) + */ + OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */ + OUT_82c54_TIMER(0,100) ; /* LSB */ + OUT_82c54_TIMER(0,0) ; /* MSB */ +#else /* PCI */ + outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */ + outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */ +#endif /* PCI */ + smc->hw.timer_activ = TRUE ; +} + +/************************ + * + * hwt_stop + * + * Stop hardware timer. + * + * void hwt_stop( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_stop(smc) +struct s_smc *smc ; +{ +#ifndef PCI + /* stop counter 0 by switching to mode 0 */ + OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */ + OUT_82c54_TIMER(0,0) ; /* LSB */ + OUT_82c54_TIMER(0,0) ; /* MSB */ +#else /* PCI */ + outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; + outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; +#endif /* PCI */ + + smc->hw.timer_activ = FALSE ; +} + +/************************ + * + * hwt_init + * + * Initialize hardware timer. + * + * void hwt_init( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_init(smc) +struct s_smc *smc ; +{ + smc->hw.t_start = 0 ; + smc->hw.t_stop = 0 ; + smc->hw.timer_activ = FALSE ; + + hwt_restart(smc) ; +} + +/************************ + * + * hwt_restart + * + * Clear timer interrupt. + * + * void hwt_restart( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_restart(smc) +struct s_smc *smc ; +{ + hwt_stop(smc) ; +#ifndef PCI + OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ + OUT_82c54_TIMER(1,1 ) ; /* LSB */ + OUT_82c54_TIMER(1,0 ) ; /* MSB */ +#endif +} + +/************************ + * + * hwt_read + * + * Stop hardware timer and read time elapsed since last start. + * + * u_long hwt_read(smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * The elapsed time since last start in units of 16us. + * + ************************/ +u_long hwt_read(smc) +struct s_smc *smc ; +{ + u_short tr ; +#ifndef PCI + u_short is ; +#else + u_long is ; +#endif + + if (smc->hw.timer_activ) { + hwt_stop(smc) ; +#ifndef PCI + OUT_82c54_TIMER(3,1<<6) ; /* latch command */ + tr = IN_82c54_TIMER(1) & 0xff ; + tr += (IN_82c54_TIMER(1) & 0xff)<<8 ; +#else /* PCI */ + tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; +#endif /* PCI */ + is = GET_ISR() ; + /* Check if timer expired (or wraparound). */ + if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { + hwt_restart(smc) ; + smc->hw.t_stop = smc->hw.t_start ; + } + else + smc->hw.t_stop = smc->hw.t_start - tr ; + } + return (smc->hw.t_stop) ; +} + +#ifdef PCI +/************************ + * + * hwt_quick_read + * + * Stop hardware timer and read timer value and start the timer again. + * + * u_long hwt_read(smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * current timer value in units of 80ns. + * + ************************/ +u_long hwt_quick_read(smc) +struct s_smc *smc ; +{ + u_long interval ; + u_long time ; + + interval = inpd(ADDR(B2_TI_INI)) ; + outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; + time = inpd(ADDR(B2_TI_VAL)) ; + outpd(ADDR(B2_TI_INI),time) ; + outpw(ADDR(B2_TI_CRTL), TIM_START) ; + outpd(ADDR(B2_TI_INI),interval) ; + + return(time) ; +} + +/************************ + * + * hwt_wait_time(smc,start,duration) + * + * This function returnes after the amount of time is elapsed + * since the start time. + * + * para start start time + * duration time to wait + * + * NOTE: The fuction will return immediatly, if the timer is not + * started + ************************/ +void hwt_wait_time(smc,start,duration) +struct s_smc *smc ; +u_long start ; +long duration ; +{ + long diff ; + long interval ; + int wrapped ; + + /* + * check if timer is running + */ + if (smc->hw.timer_activ == FALSE || + hwt_quick_read(smc) == hwt_quick_read(smc)) { + return ; + } + + interval = inpd(ADDR(B2_TI_INI)) ; + if (interval > duration) { + do { + diff = (long)(start - hwt_quick_read(smc)) ; + if (diff < 0) { + diff += interval ; + } + } while (diff <= duration) ; + } + else { + diff = interval ; + wrapped = 0 ; + do { + if (!wrapped) { + if (hwt_quick_read(smc) >= start) { + diff += interval ; + wrapped = 1 ; + } + } + else { + if (hwt_quick_read(smc) < start) { + wrapped = 0 ; + } + } + } while (diff <= duration) ; + } +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/lnkstat.c linux/drivers/net/skfp/lnkstat.c --- v2.2.17/drivers/net/skfp/lnkstat.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/lnkstat.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,209 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + IBM FDDI read error log function +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/lnkstat.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)lnkstat.c 1.8 97/04/11 (C) SK " ; +#endif + +#ifdef sun +#define _far +#endif + +#define EL_IS_OK(x,l) ((((int)&(((struct s_error_log *)0)->x)) + \ + sizeof(er->x)) <= l) + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_get_error_word(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT error work for AIX events. + +Return smt_error_word These bits are supported: + + SMT_ERL_ALC == [PS/PA].fddiPORTLerFlag + SMT_ERL_BLC == [PB].fddiPORTLerFlag + SMT_ERL_NCC == fddiMACNotCopiedFlag + SMT_ERL_FEC == fddiMACFrameErrorFlag + + END_MANUAL_ENTRY() + */ +u_long smt_get_error_word(smc) +struct s_smc *smc ; +{ + u_long st; + + /* + * smt error word low + */ + st = 0 ; + if (smc->s.sas == SMT_SAS) { + if (smc->mib.p[PS].fddiPORTLerFlag) + st |= SMT_ERL_ALC ; + } + else { + if (smc->mib.p[PA].fddiPORTLerFlag) + st |= SMT_ERL_ALC ; + if (smc->mib.p[PB].fddiPORTLerFlag) + st |= SMT_ERL_BLC ; + } + if (smc->mib.m[MAC0].fddiMACNotCopiedFlag) + st |= SMT_ERL_NCC ; /* not copied condition */ + if (smc->mib.m[MAC0].fddiMACFrameErrorFlag) + st |= SMT_ERL_FEC ; /* frame error condition */ + + return st; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_get_event_word(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT event work for AIX events. + +Return smt_event_word always 0 + + END_MANUAL_ENTRY() + */ +u_long smt_get_event_word(smc) +struct s_smc *smc ; +{ + return (u_long) 0; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_get_port_event_word(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT port event work for AIX events. + +Return smt_port_event_word always 0 + + END_MANUAL_ENTRY() + */ +u_long smt_get_port_event_word(smc) +struct s_smc *smc ; +{ + return (u_long) 0; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_read_errorlog(smc,p,len) + struct s_smc *smc ; + char _far *p ; + int len ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT error log field for AIX events. + +Para p pointer to the error log field + len len of the error log field + +Return len used len of the error log field + + END_MANUAL_ENTRY() + */ +int smt_read_errorlog(smc,p,len) +struct s_smc *smc ; +char _far *p ; +int len ; +{ + int i ; + int st ; + struct s_error_log _far *er ; + + er = (struct s_error_log _far *) p ; + if (len > sizeof(struct s_error_log)) + len = sizeof(struct s_error_log) ; + for (i = 0 ; i < len ; i++) + *p++ = 0 ; + /* + * set count + */ + if (EL_IS_OK(set_count_high,len)) { + er->set_count_low = (u_short)smc->mib.fddiSMTSetCount.count ; + er->set_count_high = + (u_short)(smc->mib.fddiSMTSetCount.count >> 16L) ; + } + /* + * aci + */ + if (EL_IS_OK(aci_id_code,len)) { + er->aci_id_code = 0 ; + } + /* + * purge counter is missed frames; 16 bits only + */ + if (EL_IS_OK(purge_frame_counter,len)) { + if (smc->mib.m[MAC0].fddiMACCopied_Ct > 0xffff) + er->purge_frame_counter = 0xffff ; + else + er->purge_frame_counter = + (u_short)smc->mib.m[MAC0].fddiMACCopied_Ct ; + } + /* + * CMT and RMT state machines + */ + if (EL_IS_OK(ecm_state,len)) + er->ecm_state = smc->mib.fddiSMTECMState ; + + if (EL_IS_OK(pcm_b_state,len)) { + if (smc->s.sas == SMT_SAS) { + er->pcm_a_state = smc->y[PS].mib->fddiPORTPCMState ; + er->pcm_b_state = 0 ; + } + else { + er->pcm_a_state = smc->y[PA].mib->fddiPORTPCMState ; + er->pcm_b_state = smc->y[PB].mib->fddiPORTPCMState ; + } + } + if (EL_IS_OK(cfm_state,len)) + er->cfm_state = smc->mib.fddiSMTCF_State ; + if (EL_IS_OK(rmt_state,len)) + er->rmt_state = smc->mib.m[MAC0].fddiMACRMTState ; + + /* + * smt error word low (we only need the low order 16 bits.) + */ + + st = smt_get_error_word(smc) & 0xffff ; + + if (EL_IS_OK(smt_error_low,len)) + er->smt_error_low = st ; + + if (EL_IS_OK(ucode_version_level,len)) + er->ucode_version_level = 0x0101 ; + return(len) ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/pcmplc.c linux/drivers/net/skfp/pcmplc.c --- v2.2.17/drivers/net/skfp/pcmplc.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/pcmplc.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,2094 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + PCM + Physical Connection Management +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependant functions are referenced : + * sm_pm_control() + * sm_ph_linestate() + * sm_pm_ls_latch() + * + * The following HW dependant events are required : + * PC_QLS + * PC_ILS + * PC_HLS + * PC_MLS + * PC_NSE + * PC_LEM + * + */ + + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ; +#endif + +#ifdef FDDI_MIB +extern int snmp_fddi_trap( +#ifdef ANSIC +struct s_smc * smc, int type, int index +#endif +); +#endif +#ifdef CONCENTRATOR +extern int plc_is_installed( +#ifdef ANSIC +struct s_smc *smc , +int p +#endif +) ; +#endif +/* + * FSM Macros + */ +#define AFLAG (0x20) +#define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG) +#define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +/* + * PCM states + */ +#define PC0_OFF 0 +#define PC1_BREAK 1 +#define PC2_TRACE 2 +#define PC3_CONNECT 3 +#define PC4_NEXT 4 +#define PC5_SIGNAL 5 +#define PC6_JOIN 6 +#define PC7_VERIFY 7 +#define PC8_ACTIVE 8 +#define PC9_MAINT 9 + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const pcm_states[] = { + "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT", + "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT" +} ; + +/* + * symbolic event names + */ +static const char * const pcm_events[] = { + "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL", + "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR", + "PC_ENABLE","PC_DISABLE", + "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE", + "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN", + "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT", + "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT", + "PC_NSE","PC_LEM" +} ; +#endif + +#ifdef MOT_ELM +/* + * PCL-S control register + * this register in the PLC-S controls the scrambling parameters + */ +#define PLCS_CONTROL_C_U 0 +#define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \ + PL_C_CIPHER_ENABLE) +#define PLCS_FASSERT_U 0 +#define PLCS_FASSERT_S 0xFd76 /* 52.0 us */ +#define PLCS_FDEASSERT_U 0 +#define PLCS_FDEASSERT_S 0 +#else /* nMOT_ELM */ +/* + * PCL-S control register + * this register in the PLC-S controls the scrambling parameters + * can be patched for ANSI compliance if standard changes + */ +static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ; +static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ; + +#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8)) +#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8)) +#endif /* nMOT_ELM */ + +/* + * external vars + */ +/* struct definition see 'cmtdef.h' (also used by CFM) */ + +#define PS_OFF 0 +#define PS_BIT3 1 +#define PS_BIT4 2 +#define PS_BIT7 3 +#define PS_LCT 4 +#define PS_BIT8 5 +#define PS_JOIN 6 +#define PS_ACTIVE 7 + +#define LCT_LEM_MAX 255 + +/* + * PLC timing parameter + */ + +#define PLC_MS(m) ((int)((0x10000L-(m*100000L/2048)))) +#define SLOW_TL_MIN PLC_MS(6) +#define SLOW_C_MIN PLC_MS(10) + +static const struct plt { + int timer ; /* relative plc timer address */ + int para ; /* default timing parameters */ +} pltm[] = { + { PL_C_MIN, SLOW_C_MIN }, /* min t. to remain Connect State */ + { PL_TL_MIN, SLOW_TL_MIN }, /* min t. to transmit a Line State */ + { PL_TB_MIN, TP_TB_MIN }, /* min break time */ + { PL_T_OUT, TP_T_OUT }, /* Signaling timeout */ + { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */ + { PL_T_SCRUB, TP_T_SCRUB }, /* Scrub Time == MAC TVX time ! */ + { PL_NS_MAX, TP_NS_MAX }, /* max t. that noise is tolerated */ + { 0,0 } +} ; + +/* + * interrupt mask + */ +#ifdef SUPERNET_3 +/* + * Do we need the EBUF error during signaling, too, to detect SUPERNET_3 + * PLL bug? + */ +static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; +#else /* SUPERNET_3 */ +/* + * We do NOT need the elasticity buffer error during signaling. + */ +static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST ; +#endif /* SUPERNET_3 */ +static int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; + +/* external functions */ +void all_selection_criteria (); + +/* internal functions */ +static void pcm_fsm() ; +static void pc_rcode_actions() ; +static void pc_tcode_actions() ; +static void reset_lem_struct() ; +static void plc_init() ; +static void sm_ph_lem_start() ; +static void sm_ph_lem_stop() ; +static void sm_ph_linestate() ; +static void real_init_plc() ; + +/* + * SMT timer interface + * start PCM timer 0 + */ +static void start_pcm_timer0(smc,value,event,phy) +struct s_smc *smc ; +u_long value; +int event; +struct s_phy *phy; +{ + phy->timer0_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&phy->pcm_timer0,value, + EV_TOKEN(EVENT_PCM+phy->np,event)) ; +} +/* + * SMT timer interface + * stop PCM timer 0 + */ +static void stop_pcm_timer0(smc,phy) +struct s_smc *smc ; +struct s_phy *phy; +{ + if (phy->pcm_timer0.tm_active) + smt_timer_stop(smc,&phy->pcm_timer0) ; +} + +/* + init PCM state machine (called by driver) + clear all PCM vars and flags +*/ +void pcm_init(smc) +struct s_smc *smc ; +{ + int i ; + int np ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + + for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) { + /* Indicates the type of PHY being used */ + mib = phy->mib ; + mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ; + phy->np = np ; + switch (smc->s.sas) { +#ifdef CONCENTRATOR + case SMT_SAS : + mib->fddiPORTMy_Type = (np == PS) ? TS : TM ; + break ; + case SMT_DAS : + mib->fddiPORTMy_Type = (np == PA) ? TA : + (np == PB) ? TB : TM ; + break ; + case SMT_NAC : + mib->fddiPORTMy_Type = TM ; + break; +#else + case SMT_SAS : + mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ; + mib->fddiPORTHardwarePresent = (np == PS) ? TRUE : + FALSE ; +#ifndef SUPERNET_3 + smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ; +#else + smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ; +#endif + break ; + case SMT_DAS : + mib->fddiPORTMy_Type = (np == PB) ? TB : TA ; + break ; +#endif + } + /* + * set PMD-type + */ + phy->pmd_scramble = 0 ; + switch (phy->pmd_type[PMD_SK_PMD]) { + case 'P' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; + break ; + case 'L' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ; + break ; + case 'D' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + case 'S' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + phy->pmd_scramble = TRUE ; + break ; + case 'U' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + phy->pmd_scramble = TRUE ; + break ; + case '1' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; + break ; + case '2' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; + break ; + case '3' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; + break ; + case '4' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; + break ; + case 'H' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; + break ; + case 'I' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + case 'G' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + default: + mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; + break ; + } + /* + * A and B port can be on primary and secondary path + */ + switch (mib->fddiPORTMy_Type) { + case TA : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_SEC_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_SEC_PREFER | + MIB_P_PATH_THRU ; + break ; + case TB : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_PRIM_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_PRIM_PREFER | + MIB_P_PATH_CON_PREFER | + MIB_P_PATH_THRU ; + break ; + case TS : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_PRIM_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_PRIM_PREFER ; + break ; + case TM : + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_SEC_ALTER | + MIB_P_PATH_PRIM_ALTER ; + mib->fddiPORTRequestedPaths[3] = 0 ; + break ; + } + + phy->pc_lem_fail = FALSE ; + mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ; + mib->fddiPORTLCTFail_Ct = 0 ; + mib->fddiPORTBS_Flag = 0 ; + mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + mib->fddiPORTNeighborType = TNONE ; + phy->ls_flag = 0 ; + phy->rc_flag = 0 ; + phy->tc_flag = 0 ; + phy->td_flag = 0 ; + if (np >= PM) + phy->phy_name = '0' + np - PM ; + else + phy->phy_name = 'A' + np ; + phy->wc_flag = FALSE ; /* set by SMT */ + memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ; + reset_lem_struct(phy) ; + memset((char *)&phy->plc,0,sizeof(struct s_plc)) ; + phy->plc.p_state = PS_OFF ; + for (i = 0 ; i < NUMBITS ; i++) { + phy->t_next[i] = 0 ; + } + } + real_init_plc(smc) ; +} + +void init_plc(smc) +struct s_smc *smc ; +{ + SK_UNUSED(smc) ; + + /* + * dummy + * this is an obsolete public entry point that has to remain + * for compat. It is used by various drivers. + * the work is now done in real_init_plc() + * which is called from pcm_init() ; + */ +} + +static void real_init_plc(smc) +struct s_smc *smc ; +{ + int p ; + + for (p = 0 ; p < NUMPHYS ; p++) + plc_init(smc,p) ; +} + +static void plc_init(smc,p) +struct s_smc *smc ; +int p; +{ + int i ; +#ifndef MOT_ELM + int rev ; /* Revision of PLC-x */ +#endif /* MOT_ELM */ + + /* transit PCM state machine to MAINT state */ + outpw(PLC(p,PL_CNTRL_B),0) ; + outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ; + outpw(PLC(p,PL_CNTRL_A),0) ; + + /* + * if PLC-S then set control register C + */ +#ifndef MOT_ELM + rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ; + if (rev != PLC_REVISION_A) +#endif /* MOT_ELM */ + { + if (smc->y[p].pmd_scramble) { + outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ; +#ifdef MOT_ELM + outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ; + outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ; +#endif /* MOT_ELM */ + } + else { + outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ; +#ifdef MOT_ELM + outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ; + outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ; +#endif /* MOT_ELM */ + } + } + + /* + * set timer register + */ + for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */ + outpw(PLC(p,pltm[i].timer),pltm[i].para) ; + + (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */ + plc_clear_irq(smc,p) ; + outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */ + + /* + * if PCM is configured for class s, it will NOT go to the + * REMOVE state if offline (page 3-36;) + * in the concentrator, all inactive PHYS always must be in + * the remove state + * there's no real need to use this feature at all .. + */ +#ifndef CONCENTRATOR + if ((smc->s.sas == SMT_SAS) && (p == PS)) { + outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ; + } +#endif +} + +/* + * control PCM state machine + */ +static void plc_go_state(smc,p,state) +struct s_smc *smc ; +int p; +int state; +{ + HW_PTR port ; + int val ; + + SK_UNUSED(smc) ; + + port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ; + val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ; + outpw(port,val) ; + outpw(port,val | state) ; +} + +/* + * read current line state (called by ECM & PCM) + */ +int sm_pm_get_ls(smc,phy) +struct s_smc *smc ; +int phy; +{ + int state ; + +#ifdef CONCENTRATOR + if (!plc_is_installed(smc,phy)) + return(PC_QLS) ; +#endif + + state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ; + switch(state) { + case PL_L_QLS: + state = PC_QLS ; + break ; + case PL_L_MLS: + state = PC_MLS ; + break ; + case PL_L_HLS: + state = PC_HLS ; + break ; + case PL_L_ILS4: + case PL_L_ILS16: + state = PC_ILS ; + break ; + case PL_L_ALS: + state = PC_LS_PDR ; + break ; + default : + state = PC_LS_NONE ; + } + return(state) ; +} + +static int plc_send_bits(smc,phy,len) +struct s_smc *smc ; +struct s_phy *phy; +int len; +{ + int np = phy->np ; /* PHY index */ + int n ; + int i ; + + SK_UNUSED(smc) ; + + /* create bit vector */ + for (i = len-1,n = 0 ; i >= 0 ; i--) { + n = (n<<1) | phy->t_val[phy->bitn+i] ; + } + if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { +#if 0 + printf("PL_PCM_SIGNAL is set\n") ; +#endif + return(1) ; + } + /* write bit[n] & length = 1 to regs */ + outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */ + outpw(PLC(np,PL_XMIT_VECTOR),n) ; +#ifdef DEBUG +#if 1 +#ifdef DEBUG_BRD + if (smc->debug.d_plc & 0x80) +#else + if (debug.d_plc & 0x80) +#endif + printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ; +#endif +#endif + return(0) ; +} + +/* + * config plc muxes + */ +void plc_config_mux(smc,mux) +struct s_smc *smc ; +int mux ; +{ + if (smc->s.sas != SMT_DAS) + return ; + if (mux == MUX_WRAPB) { + SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; + SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; + } + else { + CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ; + CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ; + } + CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ; + CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ; +} + +/* + PCM state machine + called by dispatcher & fddi_init() (driver) + do + display state change + process event + until SM is stable +*/ +void pcm(smc,np,event) +struct s_smc *smc ; +const int np; +int event; +{ + int state ; + int oldstate ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + +#ifndef CONCENTRATOR + /* + * ignore 2nd PHY if SAS + */ + if ((np != PS) && (smc->s.sas == SMT_SAS)) + return ; +#endif + phy = &smc->y[np] ; + mib = phy->mib ; + oldstate = mib->fddiPORTPCMState ; + do { + DB_PCM("PCM %c: state %s", + phy->phy_name, + (mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ; + DB_PCM("%s, event %s\n", + pcm_states[mib->fddiPORTPCMState & ~AFLAG], + pcm_events[event]) ; + state = mib->fddiPORTPCMState ; + pcm_fsm(smc,phy,event) ; + event = 0 ; + } while (state != mib->fddiPORTPCMState) ; + /* + * because the PLC does the bit signaling for us, + * we're always in SIGNAL state + * the MIB want's to see CONNECT + * we therefore fake an entry in the MIB + */ + if (state == PC5_SIGNAL) + mib->fddiPORTPCMStateX = PC3_CONNECT ; + else + mib->fddiPORTPCMStateX = state ; + +#ifndef SLIM_SMT + /* + * path change + */ + if ( mib->fddiPORTPCMState != oldstate && + ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) { + smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE, + (int) (INDEX_PORT+ phy->np),0) ; + } +#endif + +#ifdef FDDI_MIB + /* check whether a snmp-trap has to be sent */ + + if ( mib->fddiPORTPCMState != oldstate ) { + /* a real state change took place */ + DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState); + if ( mib->fddiPORTPCMState == PC0_OFF ) { + /* send first trap */ + snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex ); + } else if ( oldstate == PC0_OFF ) { + /* send second trap */ + snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex ); + } else if ( mib->fddiPORTPCMState != PC2_TRACE && + oldstate == PC8_ACTIVE ) { + /* send third trap */ + snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex ); + } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) { + /* send fourth trap */ + snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex ); + } + } +#endif + + pcm_state_change(smc,np,state) ; +} + +/* + * PCM state machine + */ +static void pcm_fsm(smc,phy,cmd) +struct s_smc *smc ; +struct s_phy *phy; +int cmd; +{ + int i ; + int np = phy->np ; /* PHY index */ + struct s_plc *plc ; + struct fddi_mib_p *mib ; +#ifndef MOT_ELM + u_short plc_rev ; /* Revision of the plc */ +#endif /* nMOT_ELM */ + + plc = &phy->plc ; + mib = phy->mib ; + + /* + * general transitions independant of state + */ + switch (cmd) { + case PC_STOP : + /*PC00-PC80*/ + if (mib->fddiPORTPCMState != PC9_MAINT) { + GO_STATE(PC0_OFF) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP, + smt_get_port_event_word(smc)); + } + return ; + case PC_START : + /*PC01-PC81*/ + if (mib->fddiPORTPCMState != PC9_MAINT) + GO_STATE(PC1_BREAK) ; + return ; + case PC_DISABLE : + /* PC09-PC99 */ + GO_STATE(PC9_MAINT) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED, + smt_get_port_event_word(smc)); + return ; + case PC_TIMEOUT_LCT : + /* if long or extended LCT */ + stop_pcm_timer0(smc,phy) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + /* end of LCT is indicate by PCM_CODE (initiate PCM event) */ + return ; + } + + switch(mib->fddiPORTPCMState) { + case ACTIONS(PC0_OFF) : + stop_pcm_timer0(smc,phy) ; + outpw(PLC(np,PL_CNTRL_A),0) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + plc_go_state(smc,np,PL_PCM_STOP) ; + mib->fddiPORTConnectState = PCM_DISABLED ; + ACTIONS_DONE() ; + break ; + case PC0_OFF: + /*PC09*/ + if (cmd == PC_MAINT) { + GO_STATE(PC9_MAINT) ; + break ; + } + break ; + case ACTIONS(PC1_BREAK) : + /* Stop the LCT timer if we came from Signal state */ + stop_pcm_timer0(smc,phy) ; + ACTIONS_DONE() ; + plc_go_state(smc,np,0) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + /* + * if vector is already loaded, go to OFF to clear PCM_SIGNAL + */ +#if 0 + if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { + plc_go_state(smc,np,PL_PCM_STOP) ; + /* TB_MIN ? */ + } +#endif + /* + * Go to OFF state in any case. + */ + plc_go_state(smc,np,PL_PCM_STOP) ; + + if (mib->fddiPORTPC_Withhold == PC_WH_NONE) + mib->fddiPORTConnectState = PCM_CONNECTING ; + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + phy->ls_flag = FALSE ; + phy->pc_mode = PM_NONE ; /* needed by CFM */ + phy->bitn = 0 ; /* bit signaling start bit */ + for (i = 0 ; i < 3 ; i++) + pc_tcode_actions(smc,i,phy) ; + + /* Set the non-active interrupt mask register */ + outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ; + + /* + * If the LCT was stopped. There might be a + * PCM_CODE interrupt event present. + * This must be cleared. + */ + (void)inpw(PLC(np,PL_INTR_EVENT)) ; +#ifndef MOT_ELM + /* Get the plc revision for revision dependent code */ + plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ; + + if (plc_rev != PLC_REV_SN3) +#endif /* MOT_ELM */ + { + /* + * No supernet III PLC, so set Xmit verctor and + * length BEFORE starting the state machine. + */ + if (plc_send_bits(smc,phy,3)) { + return ; + } + } + + /* + * Now give the Start command. + * - The start command shall be done before setting the bits + * to be signaled. (In PLC-S description and PLCS in SN3. + * - The start command shall be issued AFTER setting the + * XMIT vector and the XMIT length register. + * + * We do it exactly according this specs for the old PLC and + * the new PLCS inside the SN3. + * For the usual PLCS we try it the way it is done for the + * old PLC and set the XMIT registers again, if the PLC is + * not in SIGNAL state. This is done according to an PLCS + * errata workaround. + */ + + plc_go_state(smc,np,PL_PCM_START) ; + + /* + * workaround for PLC-S eng. sample errata + */ +#ifdef MOT_ELM + if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) +#else /* nMOT_ELM */ + if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) != + PLC_REVISION_A) && + !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) +#endif /* nMOT_ELM */ + { + /* + * Set register again (PLCS errata) or the first time + * (new SN3 PLCS). + */ + (void) plc_send_bits(smc,phy,3) ; + } + /* + * end of workaround + */ + + GO_STATE(PC5_SIGNAL) ; + plc->p_state = PS_BIT3 ; + plc->p_bits = 3 ; + plc->p_start = 0 ; + + break ; + case PC1_BREAK : + break ; + case ACTIONS(PC2_TRACE) : + plc_go_state(smc,np,PL_PCM_TRACE) ; + ACTIONS_DONE() ; + break ; + case PC2_TRACE : + break ; + + case PC3_CONNECT : /* these states are done by hardware */ + case PC4_NEXT : + break ; + + case ACTIONS(PC5_SIGNAL) : + ACTIONS_DONE() ; + case PC5_SIGNAL : + if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT)) + break ; + switch (plc->p_state) { + case PS_BIT3 : + for (i = 0 ; i <= 2 ; i++) + pc_rcode_actions(smc,i,phy) ; + pc_tcode_actions(smc,3,phy) ; + plc->p_state = PS_BIT4 ; + plc->p_bits = 1 ; + plc->p_start = 3 ; + phy->bitn = 3 ; + if (plc_send_bits(smc,phy,1)) { + return ; + } + break ; + case PS_BIT4 : + pc_rcode_actions(smc,3,phy) ; + for (i = 4 ; i <= 6 ; i++) + pc_tcode_actions(smc,i,phy) ; + plc->p_state = PS_BIT7 ; + plc->p_bits = 3 ; + plc->p_start = 4 ; + phy->bitn = 4 ; + if (plc_send_bits(smc,phy,3)) { + return ; + } + break ; + case PS_BIT7 : + for (i = 3 ; i <= 6 ; i++) + pc_rcode_actions(smc,i,phy) ; + plc->p_state = PS_LCT ; + plc->p_bits = 0 ; + plc->p_start = 7 ; + phy->bitn = 7 ; + sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */ + /* start LCT */ + i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ; + outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */ + outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ; + break ; + case PS_LCT : + /* check for local LCT failure */ + pc_tcode_actions(smc,7,phy) ; + /* + * set tval[7] + */ + plc->p_state = PS_BIT8 ; + plc->p_bits = 1 ; + plc->p_start = 7 ; + phy->bitn = 7 ; + if (plc_send_bits(smc,phy,1)) { + return ; + } + break ; + case PS_BIT8 : + /* check for remote LCT failure */ + pc_rcode_actions(smc,7,phy) ; + if (phy->t_val[7] || phy->r_val[7]) { + plc_go_state(smc,np,PL_PCM_STOP) ; + GO_STATE(PC1_BREAK) ; + break ; + } + for (i = 8 ; i <= 9 ; i++) + pc_tcode_actions(smc,i,phy) ; + plc->p_state = PS_JOIN ; + plc->p_bits = 2 ; + plc->p_start = 8 ; + phy->bitn = 8 ; + if (plc_send_bits(smc,phy,2)) { + return ; + } + break ; + case PS_JOIN : + for (i = 8 ; i <= 9 ; i++) + pc_rcode_actions(smc,i,phy) ; + plc->p_state = PS_ACTIVE ; + GO_STATE(PC6_JOIN) ; + break ; + } + break ; + + case ACTIONS(PC6_JOIN) : + /* + * prevent mux error when going from WRAP_A to WRAP_B + */ + if (smc->s.sas == SMT_DAS && np == PB && + (smc->y[PA].pc_mode == PM_TREE || + smc->y[PB].pc_mode == PM_TREE)) { + SETMASK(PLC(np,PL_CNTRL_A), + PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; + SETMASK(PLC(np,PL_CNTRL_B), + PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; + } + SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; + SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; + ACTIONS_DONE() ; + cmd = 0 ; + /* fall thru */ + case PC6_JOIN : + switch (plc->p_state) { + case PS_ACTIVE: + /*PC88b*/ + if (!phy->cf_join) { + phy->cf_join = TRUE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; ; + } + if (cmd == PC_JOIN) + GO_STATE(PC8_ACTIVE) ; + /*PC82*/ + if (cmd == PC_TRACE) { + GO_STATE(PC2_TRACE) ; + break ; + } + break ; + } + break ; + + case PC7_VERIFY : + break ; + + case ACTIONS(PC8_ACTIVE) : + /* + * start LEM for SMT + */ + sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ; + + phy->tr_flag = FALSE ; + mib->fddiPORTConnectState = PCM_ACTIVE ; + + /* Set the active interrupt mask register */ + outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ; + + ACTIONS_DONE() ; + break ; + case PC8_ACTIVE : + /*PC81 is done by PL_TNE_EXPIRED irq */ + /*PC82*/ + if (cmd == PC_TRACE) { + GO_STATE(PC2_TRACE) ; + break ; + } + /*PC88c: is done by TRACE_PROP irq */ + + break ; + case ACTIONS(PC9_MAINT) : + stop_pcm_timer0(smc,phy) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */ + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + plc_go_state(smc,np,PL_PCM_STOP) ; + mib->fddiPORTConnectState = PCM_DISABLED ; + SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ; + sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ; + outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ; + ACTIONS_DONE() ; + break ; + case PC9_MAINT : + DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ; + /*PC90*/ + if (cmd == PC_ENABLE) { + GO_STATE(PC0_OFF) ; + break ; + } + break ; + + default: + SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ; + break ; + } +} + +/* + * force line state on a PHY output (only in MAINT state) + */ +static void sm_ph_linestate(smc,phy,ls) +struct s_smc *smc ; +int phy; +int ls; +{ + int cntrl ; + + SK_UNUSED(smc) ; + + cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) | + PL_PCM_STOP | PL_MAINT ; + switch(ls) { + case PC_QLS: /* Force Quiet */ + cntrl |= PL_M_QUI0 ; + break ; + case PC_MLS: /* Force Master */ + cntrl |= PL_M_MASTR ; + break ; + case PC_HLS: /* Force Halt */ + cntrl |= PL_M_HALT ; + break ; + default : + case PC_ILS: /* Force Idle */ + cntrl |= PL_M_IDLE ; + break ; + case PC_LS_PDR: /* Enable repeat filter */ + cntrl |= PL_M_TPDR ; + break ; + } + outpw(PLC(phy,PL_CNTRL_B),cntrl) ; +} + + +static void reset_lem_struct(phy) +struct s_phy *phy; +{ + struct lem_counter *lem = &phy->lem ; + + phy->mib->fddiPORTLer_Estimate = 15 ; + lem->lem_float_ber = 15 * 100 ; +} + +/* + * link error monitor + */ +static void lem_evaluate(smc,phy) +struct s_smc *smc ; +struct s_phy *phy; +{ + int ber ; + u_long errors ; + struct lem_counter *lem = &phy->lem ; + struct fddi_mib_p *mib ; + int cond ; + + mib = phy->mib ; + + if (!lem->lem_on) + return ; + + errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ; + lem->lem_errors += errors ; + mib->fddiPORTLem_Ct += errors ; + + errors = lem->lem_errors ; + /* + * calculation is called on a intervall of 8 seconds + * -> this means, that one error in 8 sec. is one of 8*125*10E6 + * the same as BER = 10E-9 + * Please note: + * -> 9 errors in 8 seconds mean: + * BER = 9 * 10E-9 and this is + * < 10E-8, so the limit of 10E-8 is not reached! + */ + + if (!errors) ber = 15 ; + else if (errors <= 9) ber = 9 ; + else if (errors <= 99) ber = 8 ; + else if (errors <= 999) ber = 7 ; + else if (errors <= 9999) ber = 6 ; + else if (errors <= 99999) ber = 5 ; + else if (errors <= 999999) ber = 4 ; + else if (errors <= 9999999) ber = 3 ; + else if (errors <= 99999999) ber = 2 ; + else if (errors <= 999999999) ber = 1 ; + else ber = 0 ; + + /* + * weighted average + */ + ber *= 100 ; + lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ; + lem->lem_float_ber /= 10 ; + mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ; + if (mib->fddiPORTLer_Estimate < 4) { + mib->fddiPORTLer_Estimate = 4 ; + } + + if (lem->lem_errors) { + DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ; + DB_PCMN(1,"errors : %ld\n",lem->lem_errors,0) ; + DB_PCMN(1,"sum_errors : %ld\n",mib->fddiPORTLem_Ct,0) ; + DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ; + DB_PCMN(1,"float BER : 10E-(%d/100)\n",lem->lem_float_ber,0) ; + DB_PCMN(1,"avg. BER : 10E-%d\n", + mib->fddiPORTLer_Estimate,0) ; + } + + lem->lem_errors = 0L ; + +#ifndef SLIM_SMT + cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ? + TRUE : FALSE ; +#ifdef SMT_EXT_CUTOFF + smt_ler_alarm_check(smc,phy,cond) ; +#endif /* nSMT_EXT_CUTOFF */ + if (cond != mib->fddiPORTLerFlag) { + smt_srf_event(smc,SMT_COND_PORT_LER, + (int) (INDEX_PORT+ phy->np) ,cond) ; + } +#endif + + if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) { + phy->pc_lem_fail = TRUE ; /* flag */ + mib->fddiPORTLem_Reject_Ct++ ; + /* + * "forgive 10e-2" if we cutoff so we can come + * up again .. + */ + lem->lem_float_ber += 2*100 ; + + /*PC81b*/ +#ifdef CONCENTRATOR + DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n", + phy->np, mib->fddiPORTLer_Cutoff) ; +#endif +#ifdef SMT_EXT_CUTOFF + smt_port_off_event(smc,phy->np); +#else /* nSMT_EXT_CUTOFF */ + queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; +#endif /* nSMT_EXT_CUTOFF */ + } +} + +/* + * called by SMT to calculate LEM bit error rate + */ +void sm_lem_evaluate(smc) +struct s_smc *smc ; +{ + int np ; + + for (np = 0 ; np < NUMPHYS ; np++) + lem_evaluate(smc,&smc->y[np]) ; +} + +static void lem_check_lct(smc,phy) +struct s_smc *smc ; +struct s_phy *phy ; +{ + struct lem_counter *lem = &phy->lem ; + struct fddi_mib_p *mib ; + int errors ; + + mib = phy->mib ; + + phy->pc_lem_fail = FALSE ; /* flag */ + errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ; + lem->lem_errors += errors ; + mib->fddiPORTLem_Ct += errors ; + if (lem->lem_errors) { + switch(phy->lc_test) { + case LC_SHORT: + if (lem->lem_errors >= smc->s.lct_short) + phy->pc_lem_fail = TRUE ; + break ; + case LC_MEDIUM: + if (lem->lem_errors >= smc->s.lct_medium) + phy->pc_lem_fail = TRUE ; + break ; + case LC_LONG: + if (lem->lem_errors >= smc->s.lct_long) + phy->pc_lem_fail = TRUE ; + break ; + case LC_EXTENDED: + if (lem->lem_errors >= smc->s.lct_extended) + phy->pc_lem_fail = TRUE ; + break ; + } + DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ; + } + if (phy->pc_lem_fail) { + mib->fddiPORTLCTFail_Ct++ ; + mib->fddiPORTLem_Reject_Ct++ ; + } + else + mib->fddiPORTLCTFail_Ct = 0 ; +} + +/* + * LEM functions + */ +static void sm_ph_lem_start(smc,np,threshold) +struct s_smc *smc ; +int np; +int threshold; +{ + struct lem_counter *lem = &smc->y[np].lem ; + + lem->lem_on = 1 ; + lem->lem_errors = 0L ; + + /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too + * often. + */ + + outpw(PLC(np,PL_LE_THRESHOLD),threshold) ; + (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */ + + /* enable LE INT */ + SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ; +} + +static void sm_ph_lem_stop(smc,np) +struct s_smc *smc ; +int np; +{ + struct lem_counter *lem = &smc->y[np].lem ; + + lem->lem_on = 0 ; + CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; +} + +/* ARGSUSED */ +void sm_pm_ls_latch(smc,phy,on_off) +struct s_smc *smc ; +int phy; +int on_off; /* en- or disable ident. ls */ +{ + SK_UNUSED(smc) ; + + phy = phy ; on_off = on_off ; +} + + +/* + * PCM pseudo code + * receive actions are called AFTER the bit n is received, + * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received + */ + +/* + * PCM pseudo code 5.1 .. 6.1 + */ +static void pc_rcode_actions(smc,bit,phy) +struct s_smc *smc ; +int bit; +struct s_phy *phy; +{ + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + DB_PCMN(1,"SIG rec %x %x: \n", bit,phy->r_val[bit] ) ; + bit++ ; + + switch(bit) { + case 0: + case 1: + case 2: + break ; + case 3 : + if (phy->r_val[1] == 0 && phy->r_val[2] == 0) + mib->fddiPORTNeighborType = TA ; + else if (phy->r_val[1] == 0 && phy->r_val[2] == 1) + mib->fddiPORTNeighborType = TB ; + else if (phy->r_val[1] == 1 && phy->r_val[2] == 0) + mib->fddiPORTNeighborType = TS ; + else if (phy->r_val[1] == 1 && phy->r_val[2] == 1) + mib->fddiPORTNeighborType = TM ; + break ; + case 4: + if (mib->fddiPORTMy_Type == TM && + mib->fddiPORTNeighborType == TM) { + DB_PCMN(1,"PCM %c : E100 withhold M-M\n", + phy->phy_name,0) ; + mib->fddiPORTPC_Withhold = PC_WH_M_M ; + RS_SET(smc,RS_EVENT) ; + } + else if (phy->t_val[3] || phy->r_val[3]) { + mib->fddiPORTPC_Withhold = PC_WH_NONE ; + if (mib->fddiPORTMy_Type == TM || + mib->fddiPORTNeighborType == TM) + phy->pc_mode = PM_TREE ; + else + phy->pc_mode = PM_PEER ; + + /* reevaluate the selection criteria (wc_flag) */ + all_selection_criteria (smc); + + if (phy->wc_flag) { + mib->fddiPORTPC_Withhold = PC_WH_PATH ; + } + } + else { + mib->fddiPORTPC_Withhold = PC_WH_OTHER ; + RS_SET(smc,RS_EVENT) ; + DB_PCMN(1,"PCM %c : E101 withhold other\n", + phy->phy_name,0) ; + } + phy->twisted = ((mib->fddiPORTMy_Type != TS) && + (mib->fddiPORTMy_Type != TM) && + (mib->fddiPORTNeighborType == + mib->fddiPORTMy_Type)) ; + if (phy->twisted) { + DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n", + phy->phy_name,0) ; + } + break ; + case 5 : + break ; + case 6: + if (phy->t_val[4] || phy->r_val[4]) { + if ((phy->t_val[4] && phy->t_val[5]) || + (phy->r_val[4] && phy->r_val[5]) ) + phy->lc_test = LC_EXTENDED ; + else + phy->lc_test = LC_LONG ; + } + else if (phy->t_val[5] || phy->r_val[5]) + phy->lc_test = LC_MEDIUM ; + else + phy->lc_test = LC_SHORT ; + switch (phy->lc_test) { + case LC_SHORT : /* 50ms */ + outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ; + phy->t_next[7] = smc->s.pcm_lc_short ; + break ; + case LC_MEDIUM : /* 500ms */ + outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ; + phy->t_next[7] = smc->s.pcm_lc_medium ; + break ; + case LC_LONG : + SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; + phy->t_next[7] = smc->s.pcm_lc_long ; + break ; + case LC_EXTENDED : + SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; + phy->t_next[7] = smc->s.pcm_lc_extended ; + break ; + } + if (phy->t_next[7] > smc->s.pcm_lc_medium) { + start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy); + } + DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ; + phy->t_next[9] = smc->s.pcm_t_next_9 ; + break ; + case 7: + if (phy->t_val[6]) { + phy->cf_loop = TRUE ; + } + phy->td_flag = TRUE ; + break ; + case 8: + if (phy->t_val[7] || phy->r_val[7]) { + DB_PCMN(1,"PCM %c : E103 LCT fail %s\n", + phy->phy_name,phy->t_val[7]? "local":"remote") ; + queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; + } + break ; + case 9: + if (phy->t_val[8] || phy->r_val[8]) { + if (phy->t_val[8]) + phy->cf_loop = TRUE ; + phy->td_flag = TRUE ; + } + break ; + case 10: + if (phy->r_val[9]) { + /* neighbor intends to have MAC on output */ ; + mib->fddiPORTMacIndicated.R_val = TRUE ; + } + else { + /* neighbor does not intend to have MAC on output */ ; + mib->fddiPORTMacIndicated.R_val = FALSE ; + } + break ; + } +} + +/* + * PCM pseudo code 5.1 .. 6.1 + */ +static void pc_tcode_actions(smc,bit,phy) +struct s_smc *smc ; +const int bit; +struct s_phy *phy; +{ + int np = phy->np ; + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + switch(bit) { + case 0: + phy->t_val[0] = 0 ; /* no escape used */ + break ; + case 1: + if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM) + phy->t_val[1] = 1 ; + else + phy->t_val[1] = 0 ; + break ; + case 2 : + if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM) + phy->t_val[2] = 1 ; + else + phy->t_val[2] = 0 ; + break ; + case 3: + { + int type,ne ; + int policy ; + + type = mib->fddiPORTMy_Type ; + ne = mib->fddiPORTNeighborType ; + policy = smc->mib.fddiSMTConnectionPolicy ; + + phy->t_val[3] = 1 ; /* Accept connection */ + switch (type) { + case TA : + if ( + ((policy & POLICY_AA) && ne == TA) || + ((policy & POLICY_AB) && ne == TB) || + ((policy & POLICY_AS) && ne == TS) || + ((policy & POLICY_AM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TB : + if ( + ((policy & POLICY_BA) && ne == TA) || + ((policy & POLICY_BB) && ne == TB) || + ((policy & POLICY_BS) && ne == TS) || + ((policy & POLICY_BM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TS : + if ( + ((policy & POLICY_SA) && ne == TA) || + ((policy & POLICY_SB) && ne == TB) || + ((policy & POLICY_SS) && ne == TS) || + ((policy & POLICY_SM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TM : + if ( ne == TM || + ((policy & POLICY_MA) && ne == TA) || + ((policy & POLICY_MB) && ne == TB) || + ((policy & POLICY_MS) && ne == TS) || + ((policy & POLICY_MM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + } +#ifndef SLIM_SMT + /* + * detect undesirable connection attempt event + */ + if ( (type == TA && ne == TA ) || + (type == TA && ne == TS ) || + (type == TB && ne == TB ) || + (type == TB && ne == TS ) || + (type == TS && ne == TA ) || + (type == TS && ne == TB ) ) { + smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION, + (int) (INDEX_PORT+ phy->np) ,0) ; + } +#endif + } + break ; + case 4: + if (mib->fddiPORTPC_Withhold == PC_WH_NONE) { + if (phy->pc_lem_fail) { + phy->t_val[4] = 1 ; /* long */ + phy->t_val[5] = 0 ; + } + else { + phy->t_val[4] = 0 ; + if (mib->fddiPORTLCTFail_Ct > 0) + phy->t_val[5] = 1 ; /* medium */ + else + phy->t_val[5] = 0 ; /* short */ + + /* + * Implementers choice: use medium + * instead of short when undesired + * connection attempt is made. + */ + if (phy->wc_flag) + phy->t_val[5] = 1 ; /* medium */ + } + mib->fddiPORTConnectState = PCM_CONNECTING ; + } + else { + mib->fddiPORTConnectState = PCM_STANDBY ; + phy->t_val[4] = 1 ; /* extended */ + phy->t_val[5] = 1 ; + } + break ; + case 5: + break ; + case 6: + /* we do NOT have a MAC for LCT */ + phy->t_val[6] = 0 ; + break ; + case 7: + phy->cf_loop = FALSE ; + lem_check_lct(smc,phy) ; + if (phy->pc_lem_fail) { + DB_PCMN(1,"PCM %c : E104 LCT failed\n", + phy->phy_name,0) ; + phy->t_val[7] = 1 ; + } + else + phy->t_val[7] = 0 ; + break ; + case 8: + phy->t_val[8] = 0 ; /* Don't request MAC loopback */ + break ; + case 9: + phy->cf_loop = 0 ; + if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) || + ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) { + queue_event(smc,EVENT_PCM+np,PC_START) ; + break ; + } + phy->t_val[9] = FALSE ; + switch (smc->s.sas) { + case SMT_DAS : + /* + * MAC intended on output + */ + if (phy->pc_mode == PM_TREE) { + if ((np == PB) || ((np == PA) && + (smc->y[PB].mib->fddiPORTConnectState != + PCM_ACTIVE))) + phy->t_val[9] = TRUE ; + } + else { + if (np == PB) + phy->t_val[9] = TRUE ; + } + break ; + case SMT_SAS : + if (np == PS) + phy->t_val[9] = TRUE ; + break ; +#ifdef CONCENTRATOR + case SMT_NAC : + /* + * MAC intended on output + */ + if (np == PB) + phy->t_val[9] = TRUE ; + break ; +#endif + } + mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ; + break ; + } + DB_PCMN(1,"SIG snd %x %x: \n", bit,phy->t_val[bit] ) ; +} + +/* + * return status twisted (called by SMT) + */ +int pcm_status_twisted(smc) +struct s_smc *smc ; +{ + int twist = 0 ; + if (smc->s.sas != SMT_DAS) + return(0) ; + if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE)) + twist |= 1 ; + if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE)) + twist |= 2 ; + return(twist) ; +} + +/* + * return status (called by SMT) + * type + * state + * remote phy type + * remote mac yes/no + */ +void pcm_status_state(smc,np,type,state,remote,mac) +struct s_smc *smc ; +int np; +int *type; +int *state; +int *remote; +int *mac; +{ + struct s_phy *phy = &smc->y[np] ; + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + /* remote PHY type and MAC - set only if active */ + *mac = 0 ; + *type = mib->fddiPORTMy_Type ; /* our PHY type */ + *state = mib->fddiPORTConnectState ; + *remote = mib->fddiPORTNeighborType ; + + switch(mib->fddiPORTPCMState) { + case PC8_ACTIVE : + *mac = mib->fddiPORTMacIndicated.R_val ; + break ; + } +} + +/* + * return rooted station status (called by SMT) + */ +int pcm_rooted_station(smc) +struct s_smc *smc ; +{ + int n ; + + for (n = 0 ; n < NUMPHYS ; n++) { + if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE && + smc->y[n].mib->fddiPORTNeighborType == TM) + return(0) ; + } + return(1) ; +} + +/* + * Interrupt actions for PLC & PCM events + */ +void plc_irq(smc,np,cmd) +struct s_smc *smc ; +int np; /* PHY index */ +unsigned int cmd; +{ + struct s_phy *phy = &smc->y[np] ; + struct s_plc *plc = &phy->plc ; + int n ; +#ifdef SUPERNET_3 + int corr_mask ; +#endif /* SUPERNET_3 */ + int i ; + + if (np >= smc->s.numphys) { + plc->soft_err++ ; + return ; + } + if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ + /* + * Check whether the SRF Condition occured. + */ + if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ + /* + * This is the real Elasticity Error. + * More than one in a row are treated as a + * single one. + * Only count this in the active state. + */ + phy->mib->fddiPORTEBError_Ct ++ ; + + } + + plc->ebuf_err++ ; + if (plc->ebuf_cont <= 1000) { + /* + * Prevent counter from being wrapped after + * hanging years in that interrupt. + */ + plc->ebuf_cont++ ; /* Ebuf continous error */ + } + +#ifdef SUPERNET_3 + if (plc->ebuf_cont == 1000 && + ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) == + PLC_REV_SN3)) { + /* + * This interrupt remeained high for at least + * 1000 consecutive interrupt calls. + * + * This is caused by a hardware error of the + * ORION part of the Supernet III chipset. + * + * Disable this bit from the mask. + */ + corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ; + outpw(PLC(np,PL_INTR_MASK),corr_mask); + + /* + * Disconnect from the ring. + * Call the driver with the reset indication. + */ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + + /* + * Make an error log entry. + */ + SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ; + + /* + * Indicate the Reset. + */ + drv_reset_indication(smc) ; + } +#endif /* SUPERNET_3 */ + } else { + /* Reset the continous error variable */ + plc->ebuf_cont = 0 ; /* reset Ebuf continous error */ + } + if (cmd & PL_PHYINV) { /* physical layer invalid signal */ + plc->phyinv++ ; + } + if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/ + plc->vsym_ctr++ ; + } + if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ + plc->mini_ctr++ ; + } + if (cmd & PL_LE_CTR) { /* link error event counter */ + int j ; + + /* + * note: PL_LINK_ERR_CTR MUST be read to clear it + */ + j = inpw(PLC(np,PL_LE_THRESHOLD)) ; + i = inpw(PLC(np,PL_LINK_ERR_CTR)) ; + + if (i < j) { + /* wrapped around */ + i += 256 ; + } + + if (phy->lem.lem_on) { + /* Note: Lem errors shall only be counted when + * link is ACTIVE or LCT is active. + */ + phy->lem.lem_errors += i ; + phy->mib->fddiPORTLem_Ct += i ; + } + } + if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */ + if (plc->p_state == PS_LCT) { + /* + * end of LCT + */ + ; + } + plc->tpc_exp++ ; + } + if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/ + switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) { + case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ; + case PL_I_HALT : phy->curr_ls = PC_HLS ; break ; + case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ; + case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ; + } + } + if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */ + int reason; + + reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ; + + switch (reason) { + case PL_B_PCS : plc->b_pcs++ ; break ; + case PL_B_TPC : plc->b_tpc++ ; break ; + case PL_B_TNE : plc->b_tne++ ; break ; + case PL_B_QLS : plc->b_qls++ ; break ; + case PL_B_ILS : plc->b_ils++ ; break ; + case PL_B_HLS : plc->b_hls++ ; break ; + } + + /*jd 05-Aug-1999 changed: Bug #10419 */ + DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag); + if (smc->e.DisconnectFlag == FALSE) { + DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason); + queue_event(smc,EVENT_PCM+np,PC_START) ; + } + else { + DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason); + } + return ; + } + /* + * If both CODE & ENABLE are set ignore enable + */ + if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */ + queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ; + n = inpw(PLC(np,PL_RCV_VECTOR)) ; + for (i = 0 ; i < plc->p_bits ; i++) { + phy->r_val[plc->p_start+i] = n & 1 ; + n >>= 1 ; + } + } + else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/ + queue_event(smc,EVENT_PCM+np,PC_JOIN) ; + } + if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */ + /*PC22b*/ + if (!phy->tr_flag) { + DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n", + np,smc->mib.fddiSMTECMState) ; + phy->tr_flag = TRUE ; + smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ; + queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; + } + } + /* + * filter PLC glitch ??? + * QLS || HLS only while in PC2_TRACE state + */ + if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) { + /*PC22a*/ + if (smc->e.path_test == PT_PASSED) { + DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np), + phy->mib->fddiPORTPCMState) ; + + smc->e.path_test = PT_PENDING ; + queue_event(smc,EVENT_ECM,EC_PATH_TEST) ; + } + } + if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */ + /* break_required (TNE > NS_Max) */ + if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) { + if (!phy->tr_flag) { + DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE"); + queue_event(smc,EVENT_PCM+np,PC_START) ; + return ; + } + } + } +#if 0 + if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/ + /* + * It's a bug by AMD + */ + plc->np_err++ ; + } + /* pin inactiv (GND) */ + if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */ + plc->parity_err++ ; + } + if (cmd & PL_LSDO) { /* carrier detected */ + ; + } +#endif +} + +void pcm_set_lct_short(smc,n) +struct s_smc *smc ; +int n ; +{ + if (n <= 0 || n > 1000) + return ; + smc->s.lct_short = n ; +} + +#ifdef DEBUG +/* + * fill state struct + */ +void pcm_get_state(smc,state) +struct s_smc *smc ; +struct smt_state *state ; +{ + struct s_phy *phy ; + struct pcm_state *pcs ; + int i ; + int ii ; + short rbits ; + short tbits ; + struct fddi_mib_p *mib ; + + for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ; + i++ , phy++, pcs++ ) { + mib = phy->mib ; + pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ; + pcs->pcm_state = (u_char) mib->fddiPORTPCMState ; + pcs->pcm_mode = phy->pc_mode ; + pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ; + pcs->pcm_bsf = mib->fddiPORTBS_Flag ; + pcs->pcm_lsf = phy->ls_flag ; + pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ; + pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ; + for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) { + rbits <<= 1 ; + tbits <<= 1 ; + if (phy->r_val[NUMBITS-1-ii]) + rbits |= 1 ; + if (phy->t_val[NUMBITS-1-ii]) + tbits |= 1 ; + } + pcs->pcm_r_val = rbits ; + pcs->pcm_t_val = tbits ; + } +} + +int get_pcm_state(smc,np) +struct s_smc *smc ; +int np; +{ + int pcs ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { + case PL_PC0 : pcs = PC_STOP ; break ; + case PL_PC1 : pcs = PC_START ; break ; + case PL_PC2 : pcs = PC_TRACE ; break ; + case PL_PC3 : pcs = PC_SIGNAL ; break ; + case PL_PC4 : pcs = PC_SIGNAL ; break ; + case PL_PC5 : pcs = PC_SIGNAL ; break ; + case PL_PC6 : pcs = PC_JOIN ; break ; + case PL_PC7 : pcs = PC_JOIN ; break ; + case PL_PC8 : pcs = PC_ENABLE ; break ; + case PL_PC9 : pcs = PC_MAINT ; break ; + default : pcs = PC_DISABLE ; break ; + } + return(pcs) ; +} + +char *get_linestate(smc,np) +struct s_smc *smc ; +int np; +{ + char *ls = "" ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) { + case PL_L_NLS : ls = "NOISE" ; break ; + case PL_L_ALS : ls = "ACTIV" ; break ; + case PL_L_UND : ls = "UNDEF" ; break ; + case PL_L_ILS4: ls = "ILS 4" ; break ; + case PL_L_QLS : ls = "QLS" ; break ; + case PL_L_MLS : ls = "MLS" ; break ; + case PL_L_HLS : ls = "HLS" ; break ; + case PL_L_ILS16:ls = "ILS16" ; break ; +#ifdef lint + default: ls = "unknown" ; break ; +#endif + } + return(ls) ; +} + +char *get_pcmstate(smc,np) +struct s_smc *smc ; +int np; +{ + char *pcs ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { + case PL_PC0 : pcs = "OFF" ; break ; + case PL_PC1 : pcs = "BREAK" ; break ; + case PL_PC2 : pcs = "TRACE" ; break ; + case PL_PC3 : pcs = "CONNECT"; break ; + case PL_PC4 : pcs = "NEXT" ; break ; + case PL_PC5 : pcs = "SIGNAL" ; break ; + case PL_PC6 : pcs = "JOIN" ; break ; + case PL_PC7 : pcs = "VERIFY" ; break ; + case PL_PC8 : pcs = "ACTIV" ; break ; + case PL_PC9 : pcs = "MAINT" ; break ; + default : pcs = "UNKNOWN" ; break ; + } + return(pcs) ; +} + +void list_phy(smc) +struct s_smc *smc ; +{ + struct s_plc *plc ; + int np ; + + for (np = 0 ; np < NUMPHYS ; np++) { + plc = &smc->y[np].plc ; + printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ; + printf("\tsoft_error: %ld \t\tPC_Start : %ld\n", + plc->soft_err,plc->b_pcs); + printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n", + plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ; + printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n", + plc->ebuf_err,plc->b_tne) ; + printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n", + plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ; + printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n", + plc->vsym_ctr,plc->b_ils) ; + printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n", + plc->mini_ctr,plc->b_hls) ; + printf("\tnodepr_err: %ld\n",plc->np_err) ; + printf("\tTPC_exp : %ld\n",plc->tpc_exp) ; + printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ; + } +} + + +#ifdef CONCENTRATOR +void pcm_lem_dump(smc) +struct s_smc *smc ; +{ + int i ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + + char *entostring() ; + + printf("PHY errors BER\n") ; + printf("----------------------\n") ; + for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) { + if (!plc_is_installed(smc,i)) + continue ; + mib = phy->mib ; + printf("%s\t%ld\t10E-%d\n", + entostring(smc,ENTITY_PHY(i)), + mib->fddiPORTLem_Ct, + mib->fddiPORTLer_Estimate) ; + } +} +#endif +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/pmf.c linux/drivers/net/skfp/pmf.c --- v2.2.17/drivers/net/skfp/pmf.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/pmf.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,1701 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + Parameter Management Frame processing for SMT 7.2 +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef SLIM_SMT + +#ifndef lint +static const char ID_sccs[] = "@(#)pmf.c 1.37 97/08/04 (C) SK " ; +#endif + +static int smt_authorize() ; +static int smt_check_set_count() ; +static const struct s_p_tab *smt_get_ptab() ; +static int smt_mib_phys() ; +int smt_set_para() ; +void smt_add_para() ; + +#define MOFFSS(e) ((int)&(((struct fddi_mib *)0)->e)) +#define MOFFSA(e) ((int) (((struct fddi_mib *)0)->e)) + +#define MOFFMS(e) ((int)&(((struct fddi_mib_m *)0)->e)) +#define MOFFMA(e) ((int) (((struct fddi_mib_m *)0)->e)) + +#define MOFFAS(e) ((int)&(((struct fddi_mib_a *)0)->e)) +#define MOFFAA(e) ((int) (((struct fddi_mib_a *)0)->e)) + +#define MOFFPS(e) ((int)&(((struct fddi_mib_p *)0)->e)) +#define MOFFPA(e) ((int) (((struct fddi_mib_p *)0)->e)) + + +#define AC_G 0x01 /* Get */ +#define AC_GR 0x02 /* Get/Set */ +#define AC_S 0x04 /* Set */ +#define AC_NA 0x08 +#define AC_GROUP 0x10 /* Group */ +#define MS2BCLK(x) ((x)*12500L) +/* + F LFag (byte) + B byte + S u_short 16 bit + C Counter 32 bit + L Long 32 bit + T Timer_2 32 bit + P TimeStamp ; + A LongAddress (6 byte) + E Enum 16 bit + R ResId 16 Bit +*/ +static const struct s_p_tab { + u_short p_num ; /* parameter code */ + u_char p_access ; /* access rights */ + u_short p_offset ; /* offset in mib */ + char p_swap[3] ; /* format string */ +} p_tab[] = { + /* StationIdGrp */ + { SMT_P100A,AC_GROUP } , + { SMT_P100B,AC_G, MOFFSS(fddiSMTStationId), "8" } , + { SMT_P100D,AC_G, MOFFSS(fddiSMTOpVersionId), "S" } , + { SMT_P100E,AC_G, MOFFSS(fddiSMTHiVersionId), "S" } , + { SMT_P100F,AC_G, MOFFSS(fddiSMTLoVersionId), "S" } , + { SMT_P1010,AC_G, MOFFSA(fddiSMTManufacturerData), "D" } , + { SMT_P1011,AC_GR, MOFFSA(fddiSMTUserData), "D" } , + { SMT_P1012,AC_G, MOFFSS(fddiSMTMIBVersionId), "S" } , + + /* StationConfigGrp */ + { SMT_P1014,AC_GROUP } , + { SMT_P1015,AC_G, MOFFSS(fddiSMTMac_Ct), "B" } , + { SMT_P1016,AC_G, MOFFSS(fddiSMTNonMaster_Ct), "B" } , + { SMT_P1017,AC_G, MOFFSS(fddiSMTMaster_Ct), "B" } , + { SMT_P1018,AC_G, MOFFSS(fddiSMTAvailablePaths), "B" } , + { SMT_P1019,AC_G, MOFFSS(fddiSMTConfigCapabilities),"S" } , + { SMT_P101A,AC_GR, MOFFSS(fddiSMTConfigPolicy), "wS" } , + { SMT_P101B,AC_GR, MOFFSS(fddiSMTConnectionPolicy),"wS" } , + { SMT_P101D,AC_GR, MOFFSS(fddiSMTTT_Notify), "wS" } , + { SMT_P101E,AC_GR, MOFFSS(fddiSMTStatRptPolicy), "bB" } , + { SMT_P101F,AC_GR, MOFFSS(fddiSMTTrace_MaxExpiration),"lL" } , + { SMT_P1020,AC_G, MOFFSA(fddiSMTPORTIndexes), "II" } , + { SMT_P1021,AC_G, MOFFSS(fddiSMTMACIndexes), "I" } , + { SMT_P1022,AC_G, MOFFSS(fddiSMTBypassPresent), "F" } , + + /* StatusGrp */ + { SMT_P1028,AC_GROUP } , + { SMT_P1029,AC_G, MOFFSS(fddiSMTECMState), "E" } , + { SMT_P102A,AC_G, MOFFSS(fddiSMTCF_State), "E" } , + { SMT_P102C,AC_G, MOFFSS(fddiSMTRemoteDisconnectFlag),"F" } , + { SMT_P102D,AC_G, MOFFSS(fddiSMTStationStatus), "E" } , + { SMT_P102E,AC_G, MOFFSS(fddiSMTPeerWrapFlag), "F" } , + + /* MIBOperationGrp */ + { SMT_P1032,AC_GROUP } , + { SMT_P1033,AC_G, MOFFSA(fddiSMTTimeStamp),"P" } , + { SMT_P1034,AC_G, MOFFSA(fddiSMTTransitionTimeStamp),"P" } , + /* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */ + { SMT_P1035,AC_G, MOFFSS(fddiSMTSetCount),"4P" } , + { SMT_P1036,AC_G, MOFFSS(fddiSMTLastSetStationId),"8" } , + + { SMT_P103C,AC_S, 0, "wS" } , + + /* + * PRIVATE EXTENSIONS + * only accessable locally to get/set passwd + */ + { SMT_P10F0,AC_GR, MOFFSA(fddiPRPMFPasswd), "8" } , + { SMT_P10F1,AC_GR, MOFFSS(fddiPRPMFStation), "8" } , +#ifdef ESS + { SMT_P10F2,AC_GR, MOFFSS(fddiESSPayload), "lL" } , + { SMT_P10F3,AC_GR, MOFFSS(fddiESSOverhead), "lL" } , + { SMT_P10F4,AC_GR, MOFFSS(fddiESSMaxTNeg), "lL" } , + { SMT_P10F5,AC_GR, MOFFSS(fddiESSMinSegmentSize), "lL" } , + { SMT_P10F6,AC_GR, MOFFSS(fddiESSCategory), "lL" } , + { SMT_P10F7,AC_GR, MOFFSS(fddiESSSynchTxMode), "wS" } , +#endif +#ifdef SBA + { SMT_P10F8,AC_GR, MOFFSS(fddiSBACommand), "bF" } , + { SMT_P10F9,AC_GR, MOFFSS(fddiSBAAvailable), "bF" } , +#endif + /* MAC Attributes */ + { SMT_P200A,AC_GROUP } , + { SMT_P200B,AC_G, MOFFMS(fddiMACFrameStatusFunctions),"S" } , + { SMT_P200D,AC_G, MOFFMS(fddiMACT_MaxCapabilitiy),"T" } , + { SMT_P200E,AC_G, MOFFMS(fddiMACTVXCapabilitiy),"T" } , + + /* ConfigGrp */ + { SMT_P2014,AC_GROUP } , + { SMT_P2016,AC_G, MOFFMS(fddiMACAvailablePaths), "B" } , + { SMT_P2017,AC_G, MOFFMS(fddiMACCurrentPath), "S" } , + { SMT_P2018,AC_G, MOFFMS(fddiMACUpstreamNbr), "A" } , + { SMT_P2019,AC_G, MOFFMS(fddiMACDownstreamNbr), "A" } , + { SMT_P201A,AC_G, MOFFMS(fddiMACOldUpstreamNbr), "A" } , + { SMT_P201B,AC_G, MOFFMS(fddiMACOldDownstreamNbr),"A" } , + { SMT_P201D,AC_G, MOFFMS(fddiMACDupAddressTest), "E" } , + { SMT_P2020,AC_GR, MOFFMS(fddiMACRequestedPaths), "wS" } , + { SMT_P2021,AC_G, MOFFMS(fddiMACDownstreamPORTType),"E" } , + { SMT_P2022,AC_G, MOFFMS(fddiMACIndex), "S" } , + + /* AddressGrp */ + { SMT_P2028,AC_GROUP } , + { SMT_P2029,AC_G, MOFFMS(fddiMACSMTAddress), "A" } , + + /* OperationGrp */ + { SMT_P2032,AC_GROUP } , + { SMT_P2033,AC_G, MOFFMS(fddiMACT_Req), "T" } , + { SMT_P2034,AC_G, MOFFMS(fddiMACT_Neg), "T" } , + { SMT_P2035,AC_G, MOFFMS(fddiMACT_Max), "T" } , + { SMT_P2036,AC_G, MOFFMS(fddiMACTvxValue), "T" } , + { SMT_P2038,AC_G, MOFFMS(fddiMACT_Pri0), "T" } , + { SMT_P2039,AC_G, MOFFMS(fddiMACT_Pri1), "T" } , + { SMT_P203A,AC_G, MOFFMS(fddiMACT_Pri2), "T" } , + { SMT_P203B,AC_G, MOFFMS(fddiMACT_Pri3), "T" } , + { SMT_P203C,AC_G, MOFFMS(fddiMACT_Pri4), "T" } , + { SMT_P203D,AC_G, MOFFMS(fddiMACT_Pri5), "T" } , + { SMT_P203E,AC_G, MOFFMS(fddiMACT_Pri6), "T" } , + + + /* CountersGrp */ + { SMT_P2046,AC_GROUP } , + { SMT_P2047,AC_G, MOFFMS(fddiMACFrame_Ct), "C" } , + { SMT_P2048,AC_G, MOFFMS(fddiMACCopied_Ct), "C" } , + { SMT_P2049,AC_G, MOFFMS(fddiMACTransmit_Ct), "C" } , + { SMT_P204A,AC_G, MOFFMS(fddiMACToken_Ct), "C" } , + { SMT_P2051,AC_G, MOFFMS(fddiMACError_Ct), "C" } , + { SMT_P2052,AC_G, MOFFMS(fddiMACLost_Ct), "C" } , + { SMT_P2053,AC_G, MOFFMS(fddiMACTvxExpired_Ct), "C" } , + { SMT_P2054,AC_G, MOFFMS(fddiMACNotCopied_Ct), "C" } , + { SMT_P2056,AC_G, MOFFMS(fddiMACRingOp_Ct), "C" } , + + /* FrameErrorConditionGrp */ + { SMT_P205A,AC_GROUP } , + { SMT_P205F,AC_GR, MOFFMS(fddiMACFrameErrorThreshold),"wS" } , + { SMT_P2060,AC_G, MOFFMS(fddiMACFrameErrorRatio), "S" } , + + /* NotCopiedConditionGrp */ + { SMT_P2064,AC_GROUP } , + { SMT_P2067,AC_GR, MOFFMS(fddiMACNotCopiedThreshold),"wS" } , + { SMT_P2069,AC_G, MOFFMS(fddiMACNotCopiedRatio), "S" } , + + /* StatusGrp */ + { SMT_P206E,AC_GROUP } , + { SMT_P206F,AC_G, MOFFMS(fddiMACRMTState), "S" } , + { SMT_P2070,AC_G, MOFFMS(fddiMACDA_Flag), "F" } , + { SMT_P2071,AC_G, MOFFMS(fddiMACUNDA_Flag), "F" } , + { SMT_P2072,AC_G, MOFFMS(fddiMACFrameErrorFlag), "F" } , + { SMT_P2073,AC_G, MOFFMS(fddiMACNotCopiedFlag), "F" } , + { SMT_P2074,AC_G, MOFFMS(fddiMACMA_UnitdataAvailable),"F" } , + { SMT_P2075,AC_G, MOFFMS(fddiMACHardwarePresent), "F" } , + { SMT_P2076,AC_GR, MOFFMS(fddiMACMA_UnitdataEnable),"bF" } , + + /* + * PRIVATE EXTENSIONS + * only accessable locally to get/set TMIN + */ + { SMT_P20F0,AC_NA } , + { SMT_P20F1,AC_GR, MOFFMS(fddiMACT_Min), "lT" } , + + /* Path Attributes */ + /* + * DON't swap 320B,320F,3210: they are already swapped in swap_para() + */ + { SMT_P320A,AC_GROUP } , + { SMT_P320B,AC_G, MOFFAS(fddiPATHIndex), "r" } , + { SMT_P320F,AC_GR, MOFFAS(fddiPATHSbaPayload), "l4" } , + { SMT_P3210,AC_GR, MOFFAS(fddiPATHSbaOverhead), "l4" } , + /* fddiPATHConfiguration */ + { SMT_P3212,AC_G, 0, "" } , + { SMT_P3213,AC_GR, MOFFAS(fddiPATHT_Rmode), "lT" } , + { SMT_P3214,AC_GR, MOFFAS(fddiPATHSbaAvailable), "lL" } , + { SMT_P3215,AC_GR, MOFFAS(fddiPATHTVXLowerBound), "lT" } , + { SMT_P3216,AC_GR, MOFFAS(fddiPATHT_MaxLowerBound),"lT" } , + { SMT_P3217,AC_GR, MOFFAS(fddiPATHMaxT_Req), "lT" } , + + /* Port Attributes */ + /* ConfigGrp */ + { SMT_P400A,AC_GROUP } , + { SMT_P400C,AC_G, MOFFPS(fddiPORTMy_Type), "E" } , + { SMT_P400D,AC_G, MOFFPS(fddiPORTNeighborType), "E" } , + { SMT_P400E,AC_GR, MOFFPS(fddiPORTConnectionPolicies),"bB" } , + { SMT_P400F,AC_G, MOFFPS(fddiPORTMacIndicated), "2" } , + { SMT_P4010,AC_G, MOFFPS(fddiPORTCurrentPath), "E" } , + { SMT_P4011,AC_GR, MOFFPA(fddiPORTRequestedPaths), "l4" } , + { SMT_P4012,AC_G, MOFFPS(fddiPORTMACPlacement), "S" } , + { SMT_P4013,AC_G, MOFFPS(fddiPORTAvailablePaths), "B" } , + { SMT_P4016,AC_G, MOFFPS(fddiPORTPMDClass), "E" } , + { SMT_P4017,AC_G, MOFFPS(fddiPORTConnectionCapabilities), "B"} , + { SMT_P401D,AC_G, MOFFPS(fddiPORTIndex), "R" } , + + /* OperationGrp */ + { SMT_P401E,AC_GROUP } , + { SMT_P401F,AC_GR, MOFFPS(fddiPORTMaint_LS), "wE" } , + { SMT_P4021,AC_G, MOFFPS(fddiPORTBS_Flag), "F" } , + { SMT_P4022,AC_G, MOFFPS(fddiPORTPC_LS), "E" } , + + /* ErrorCtrsGrp */ + { SMT_P4028,AC_GROUP } , + { SMT_P4029,AC_G, MOFFPS(fddiPORTEBError_Ct), "C" } , + { SMT_P402A,AC_G, MOFFPS(fddiPORTLCTFail_Ct), "C" } , + + /* LerGrp */ + { SMT_P4032,AC_GROUP } , + { SMT_P4033,AC_G, MOFFPS(fddiPORTLer_Estimate), "F" } , + { SMT_P4034,AC_G, MOFFPS(fddiPORTLem_Reject_Ct), "C" } , + { SMT_P4035,AC_G, MOFFPS(fddiPORTLem_Ct), "C" } , + { SMT_P403A,AC_GR, MOFFPS(fddiPORTLer_Cutoff), "bB" } , + { SMT_P403B,AC_GR, MOFFPS(fddiPORTLer_Alarm), "bB" } , + + /* StatusGrp */ + { SMT_P403C,AC_GROUP } , + { SMT_P403D,AC_G, MOFFPS(fddiPORTConnectState), "E" } , + { SMT_P403E,AC_G, MOFFPS(fddiPORTPCMStateX), "E" } , + { SMT_P403F,AC_G, MOFFPS(fddiPORTPC_Withhold), "E" } , + { SMT_P4040,AC_G, MOFFPS(fddiPORTLerFlag), "F" } , + { SMT_P4041,AC_G, MOFFPS(fddiPORTHardwarePresent),"F" } , + + { SMT_P4046,AC_S, 0, "wS" } , + + { 0, AC_GROUP } , + { 0 } +} ; + + +static SMbuf *smt_build_pmf_response() ; + +void smt_pmf_received_pack(smc,mb,local) +struct s_smc *smc ; +SMbuf *mb ; +int local ; +{ + struct smt_header *sm ; + SMbuf *reply ; + + sm = smtod(mb,struct smt_header *) ; + DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ; +#ifdef DEBUG + dump_smt(smc,sm,"PMF Received") ; +#endif + /* + * Start the watchdog: It may be a long, long packet and + * maybe the watchdog occurs ... + */ + smt_start_watchdog(smc) ; + + if (sm->smt_class == SMT_PMF_GET || + sm->smt_class == SMT_PMF_SET) { + reply = smt_build_pmf_response(smc,sm, + sm->smt_class == SMT_PMF_SET,local) ; + if (reply) { + sm = smtod(reply,struct smt_header *) ; +#ifdef DEBUG + dump_smt(smc,sm,"PMF Reply") ; +#endif + smt_send_frame(smc,reply,FC_SMT_INFO,local) ; + } + } +} + +extern SMbuf *smt_get_mbuf() ; + +static SMbuf *smt_build_pmf_response(smc,req,set,local) +struct s_smc *smc ; +struct smt_header *req ; +int set ; +int local ; +{ + SMbuf *mb ; + struct smt_header *smt ; + struct smt_para *pa ; + struct smt_p_reason *res ; + const struct s_p_tab *pt ; + int len ; + int index ; + int idx_end ; + int error ; + int range ; + SK_LOC_DECL(struct s_pcon,pcon) ; + SK_LOC_DECL(struct s_pcon,set_pcon) ; + + /* + * build SMT header + */ + if (!(mb = smt_get_mbuf(smc))) + return(mb) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = req->smt_source ; /* DA == source of request */ + smt->smt_class = req->smt_class ; /* same class (GET/SET) */ + smt->smt_type = SMT_REPLY ; + smt->smt_version = SMT_VID_2 ; + smt->smt_tid = req->smt_tid ; /* same TID */ + smt->smt_pad = 0 ; + smt->smt_len = 0 ; + + /* + * setup parameter status + */ + pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ + pcon.pc_err = 0 ; /* no error */ + pcon.pc_badset = 0 ; /* no bad set count */ + pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ + + /* + * check authoriziation and set count + */ + error = 0 ; + if (set) { + if (!local && smt_authorize(smc,req)) + error = SMT_RDF_AUTHOR ; + else if (smt_check_set_count(smc,req)) + pcon.pc_badset = SMT_RDF_BADSET ; + } + /* + * add reason code and all mandatory parameters + */ + res = (struct smt_p_reason *) pcon.pc_p ; + smt_add_para(smc,&pcon,(u_short) SMT_P_REASON,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; + /* update 1035 and 1036 later if set */ + set_pcon = pcon ; + smt_add_para(smc,&pcon,(u_short) SMT_P1035,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1036,0,0) ; + + pcon.pc_err = error ; + len = req->smt_len ; + pa = (struct smt_para *) (req + 1) ; + /* + * process list of paras + */ + while (!pcon.pc_err && len > 0 ) { + if (((u_short)len < pa->p_len + PARA_LEN) || (pa->p_len & 3)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + + if (((range = (pa->p_type & 0xf000)) == 0x2000) || + range == 0x3000 || range == 0x4000) { + /* + * get index for PART,MAC ad PATH group + */ + index = *((u_char *)pa + PARA_LEN + 3) ;/* index */ + idx_end = index ; + if (!set && (pa->p_len != 4)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + if (!index && !set) { + switch (range) { + case 0x2000 : + index = INDEX_MAC ; + idx_end = index - 1 + NUMMACS ; + break ; + case 0x3000 : + index = INDEX_PATH ; + idx_end = index - 1 + NUMPATHS ; + break ; + case 0x4000 : + index = INDEX_PORT ; + idx_end = index - 1 + NUMPHYS ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + idx_end = INDEX_PORT ; +#endif + break ; + } + } + } + else { + /* + * smt group has no index + */ + if (!set && (pa->p_len != 0)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + index = 0 ; + idx_end = 0 ; + } + while (index <= idx_end) { + /* + * if group + * add all paras of group + */ + pt = smt_get_ptab(pa->p_type) ; + if (pt && pt->p_access == AC_GROUP && !set) { + pt++ ; + while (pt->p_access == AC_G || + pt->p_access == AC_GR) { + smt_add_para(smc,&pcon,pt->p_num, + index,local); + pt++ ; + } + } + /* + * ignore + * AUTHORIZATION in get/set + * SET COUNT in set + */ + else if (pa->p_type != SMT_P_AUTHOR && + (!set || (pa->p_type != SMT_P1035))) { + int st ; + if (pcon.pc_badset) { + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + } + else if (set) { + st = smt_set_para(smc,pa,index,local,1); + /* + * return para even if error + */ + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + pcon.pc_err = st ; + } + else { + if (pt && pt->p_access == AC_S) { + pcon.pc_err = + SMT_RDF_ILLEGAL ; + } + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + } + } + if (pcon.pc_err) + break ; + index++ ; + } + len -= pa->p_len + PARA_LEN ; + pa = (struct smt_para *) ((char *)pa + pa->p_len + PARA_LEN) ; + } + smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; + mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; + + /* update reason code */ + res->rdf_reason = pcon.pc_badset ? pcon.pc_badset : + pcon.pc_err ? pcon.pc_err : SMT_RDF_SUCCESS ; + if (set && (res->rdf_reason == SMT_RDF_SUCCESS)) { + /* + * increment set count + * set time stamp + * store station id of last set + */ + smc->mib.fddiSMTSetCount.count++ ; + smt_set_timestamp(smc,smc->mib.fddiSMTSetCount.timestamp) ; + smc->mib.fddiSMTLastSetStationId = req->smt_sid ; + smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ; + smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ; + } + return(mb) ; +} + +extern void *sm_to_para() ; + +static int smt_authorize(smc,sm) +struct s_smc *smc ; +struct smt_header *sm ; +{ + struct smt_para *pa ; + int i ; + char *p ; + + /* + * check source station id if not zero + */ + p = (char *) &smc->mib.fddiPRPMFStation ; + for (i = 0 ; i < 8 && !p[i] ; i++) + ; + if (i != 8) { + if (memcmp((char *) &sm->smt_sid, + (char *) &smc->mib.fddiPRPMFStation,8)) + return(1) ; + } + /* + * check authoriziation parameter if passwd not zero + */ + p = (char *) smc->mib.fddiPRPMFPasswd ; + for (i = 0 ; i < 8 && !p[i] ; i++) + ; + if (i != 8) { + pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ; + if (!pa) + return(1) ; + if (pa->p_len != 8) + return(1) ; + if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8)) + return(1) ; + } + return(0) ; +} + +static int smt_check_set_count(smc,sm) +struct s_smc *smc ; +struct smt_header *sm ; +{ + struct smt_para *pa ; + struct smt_p_setcount *sc ; + + pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P1035) ; + if (pa) { + sc = (struct smt_p_setcount *) pa ; + if ((smc->mib.fddiSMTSetCount.count != sc->count) || + memcmp((char *) smc->mib.fddiSMTSetCount.timestamp, + (char *)sc->timestamp,8)) + return(1) ; + } + return(0) ; +} + +void smt_add_para(smc,pcon,para,index,local) +struct s_smc *smc ; +struct s_pcon *pcon ; +u_short para ; +int index ; +int local ; +{ + struct smt_para *pa ; + const struct s_p_tab *pt ; + struct fddi_mib_m *mib_m = 0 ; + struct fddi_mib_p *mib_p = 0 ; + int len ; + int plen ; + char *from ; + char *to ; + const char *swap ; + char c ; + int range ; + char *mib_addr ; + int mac ; + int path ; + int port ; + int sp_len ; + + /* + * skip if errror + */ + if (pcon->pc_err) + return ; + + /* + * actions don't have a value + */ + pt = smt_get_ptab(para) ; + if (pt && pt->p_access == AC_S) + return ; + + to = (char *) (pcon->pc_p) ; /* destination pointer */ + len = pcon->pc_len ; /* free space */ + plen = len ; /* remember start length */ + pa = (struct smt_para *) to ; /* type/length pointer */ + to += PARA_LEN ; /* skip smt_para */ + len -= PARA_LEN ; + /* + * set index if required + */ + if (((range = (para & 0xf000)) == 0x2000) || + range == 0x3000 || range == 0x4000) { + if (len < 4) + goto wrong_error ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = 0 ; + to[3] = index ; + len -= 4 ; + to += 4 ; + } + mac = index - INDEX_MAC ; + path = index - INDEX_PATH ; + port = index - INDEX_PORT ; + /* + * get pointer to mib + */ + switch (range) { + case 0x1000 : + default : + mib_addr = (char *) (&smc->mib) ; + break ; + case 0x2000 : + if (mac < 0 || mac >= NUMMACS) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.m[mac]) ; + mib_m = (struct fddi_mib_m *) mib_addr ; + break ; + case 0x3000 : + if (path < 0 || path >= NUMPATHS) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.a[path]) ; + break ; + case 0x4000 : + if (port < 0 || port >= smt_mib_phys(smc)) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ; + mib_p = (struct fddi_mib_p *) mib_addr ; + break ; + } + /* + * check special paras + */ + swap = 0 ; + switch (para) { + case SMT_P10F0 : + case SMT_P10F1 : +#ifdef ESS + case SMT_P10F2 : + case SMT_P10F3 : + case SMT_P10F4 : + case SMT_P10F5 : + case SMT_P10F6 : + case SMT_P10F7 : +#endif +#ifdef SBA + case SMT_P10F8 : + case SMT_P10F9 : +#endif + case SMT_P20F1 : + if (!local) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + break ; + case SMT_P2034 : + case SMT_P2046 : + case SMT_P2047 : + case SMT_P204A : + case SMT_P2051 : + case SMT_P2052 : + mac_update_counter(smc) ; + break ; + case SMT_P4022: + mib_p->fddiPORTPC_LS = LS2MIB( + sm_pm_get_ls(smc,port_to_mib(smc,port))) ; + break ; + case SMT_P_REASON : + * (u_long *) to = 0 ; + sp_len = 4 ; + goto sp_done ; + case SMT_P1033 : /* time stamp */ + smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ; + break ; + + case SMT_P1020: /* port indexes */ +#if NUMPHYS == 12 + swap = "IIIIIIIIIIII" ; +#else +#if NUMPHYS == 2 + if (smc->s.sas == SMT_SAS) + swap = "I" ; + else + swap = "II" ; +#else +#if NUMPHYS == 24 + swap = "IIIIIIIIIIIIIIIIIIIIIIII" ; +#else + ???? +#endif +#endif +#endif + break ; + case SMT_P3212 : + { + sp_len = cem_build_path(smc,to,path) ; + goto sp_done ; + } + case SMT_P1048 : /* peer wrap condition */ + { + struct smt_p_1048 *sp ; + sp = (struct smt_p_1048 *) to ; + sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ; + sp->p1048_cf_state = smc->mib.fddiSMTCF_State ; + sp_len = sizeof(struct smt_p_1048) ; + goto sp_done ; + } + case SMT_P208C : + { + struct smt_p_208c *sp ; + sp = (struct smt_p_208c *) to ; + sp->p208c_flag = + smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; + sp->p208c_dupcondition = + (mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) | + (mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0); + sp->p208c_fddilong = + mib_m->fddiMACSMTAddress ; + sp->p208c_fddiunalong = + mib_m->fddiMACUpstreamNbr ; + sp->p208c_pad = 0 ; + sp_len = sizeof(struct smt_p_208c) ; + goto sp_done ; + } + case SMT_P208D : /* frame error condition */ + { + struct smt_p_208d *sp ; + sp = (struct smt_p_208d *) to ; + sp->p208d_flag = + mib_m->fddiMACFrameErrorFlag ; + sp->p208d_frame_ct = + mib_m->fddiMACFrame_Ct ; + sp->p208d_error_ct = + mib_m->fddiMACError_Ct ; + sp->p208d_lost_ct = + mib_m->fddiMACLost_Ct ; + sp->p208d_ratio = + mib_m->fddiMACFrameErrorRatio ; + sp_len = sizeof(struct smt_p_208d) ; + goto sp_done ; + } + case SMT_P208E : /* not copied condition */ + { + struct smt_p_208e *sp ; + sp = (struct smt_p_208e *) to ; + sp->p208e_flag = + mib_m->fddiMACNotCopiedFlag ; + sp->p208e_not_copied = + mib_m->fddiMACNotCopied_Ct ; + sp->p208e_copied = + mib_m->fddiMACCopied_Ct ; + sp->p208e_not_copied_ratio = + mib_m->fddiMACNotCopiedRatio ; + sp_len = sizeof(struct smt_p_208e) ; + goto sp_done ; + } + case SMT_P208F : /* neighbor change event */ + { + struct smt_p_208f *sp ; + sp = (struct smt_p_208f *) to ; + sp->p208f_multiple = + mib_m->fddiMACMultiple_N ; + sp->p208f_nacondition = + mib_m->fddiMACDuplicateAddressCond ; + sp->p208f_old_una = + mib_m->fddiMACOldUpstreamNbr ; + sp->p208f_new_una = + mib_m->fddiMACUpstreamNbr ; + sp->p208f_old_dna = + mib_m->fddiMACOldDownstreamNbr ; + sp->p208f_new_dna = + mib_m->fddiMACDownstreamNbr ; + sp->p208f_curren_path = + mib_m->fddiMACCurrentPath ; + sp->p208f_smt_address = + mib_m->fddiMACSMTAddress ; + sp_len = sizeof(struct smt_p_208f) ; + goto sp_done ; + } + case SMT_P2090 : + { + struct smt_p_2090 *sp ; + sp = (struct smt_p_2090 *) to ; + sp->p2090_multiple = + mib_m->fddiMACMultiple_P ; + sp->p2090_availablepaths = + mib_m->fddiMACAvailablePaths ; + sp->p2090_currentpath = + mib_m->fddiMACCurrentPath ; + sp->p2090_requestedpaths = + mib_m->fddiMACRequestedPaths ; + sp_len = sizeof(struct smt_p_2090) ; + goto sp_done ; + } + case SMT_P4050 : + { + struct smt_p_4050 *sp ; + sp = (struct smt_p_4050 *) to ; + sp->p4050_flag = + mib_p->fddiPORTLerFlag ; + sp->p4050_pad = 0 ; + sp->p4050_cutoff = + mib_p->fddiPORTLer_Cutoff ; ; + sp->p4050_alarm = + mib_p->fddiPORTLer_Alarm ; ; + sp->p4050_estimate = + mib_p->fddiPORTLer_Estimate ; + sp->p4050_reject_ct = + mib_p->fddiPORTLem_Reject_Ct ; + sp->p4050_ct = + mib_p->fddiPORTLem_Ct ; + sp_len = sizeof(struct smt_p_4050) ; + goto sp_done ; + } + + case SMT_P4051 : + { + struct smt_p_4051 *sp ; + sp = (struct smt_p_4051 *) to ; + sp->p4051_multiple = + mib_p->fddiPORTMultiple_U ; + sp->p4051_porttype = + mib_p->fddiPORTMy_Type ; + sp->p4051_connectstate = + mib_p->fddiPORTConnectState ; ; + sp->p4051_pc_neighbor = + mib_p->fddiPORTNeighborType ; + sp->p4051_pc_withhold = + mib_p->fddiPORTPC_Withhold ; + sp_len = sizeof(struct smt_p_4051) ; + goto sp_done ; + } + case SMT_P4052 : + { + struct smt_p_4052 *sp ; + sp = (struct smt_p_4052 *) to ; + sp->p4052_flag = + mib_p->fddiPORTEB_Condition ; + sp->p4052_eberrorcount = + mib_p->fddiPORTEBError_Ct ; + sp_len = sizeof(struct smt_p_4052) ; + goto sp_done ; + } + case SMT_P4053 : + { + struct smt_p_4053 *sp ; + sp = (struct smt_p_4053 *) to ; + sp->p4053_multiple = + mib_p->fddiPORTMultiple_P ; ; + sp->p4053_availablepaths = + mib_p->fddiPORTAvailablePaths ; + sp->p4053_currentpath = + mib_p->fddiPORTCurrentPath ; + memcpy( (char *) &sp->p4053_requestedpaths, + (char *) mib_p->fddiPORTRequestedPaths,4) ; + sp->p4053_mytype = + mib_p->fddiPORTMy_Type ; + sp->p4053_neighbortype = + mib_p->fddiPORTNeighborType ; + sp_len = sizeof(struct smt_p_4053) ; + goto sp_done ; + } + default : + break ; + } + /* + * in table ? + */ + if (!pt) { + pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM : + SMT_RDF_ILLEGAL ; + return ; + } + /* + * check access rights + */ + switch (pt->p_access) { + case AC_G : + case AC_GR : + break ; + default : + pcon->pc_err = SMT_RDF_ILLEGAL ; + return ; + } + from = mib_addr + pt->p_offset ; + if (!swap) + swap = pt->p_swap ; /* pointer to swap string */ + + /* + * copy values + */ + while ((c = *swap++)) { + switch(c) { + case 'b' : + case 'w' : + case 'l' : + break ; + case 'S' : + case 'E' : + case 'R' : + case 'r' : + if (len < 4) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; +#ifdef LITTLE_ENDIAN + if (c == 'r') { + to[2] = *from++ ; + to[3] = *from++ ; + } + else { + to[3] = *from++ ; + to[2] = *from++ ; + } +#else + to[2] = *from++ ; + to[3] = *from++ ; +#endif + to += 4 ; + len -= 4 ; + break ; + case 'I' : /* for SET of port indexes */ + if (len < 2) + goto len_error ; +#ifdef LITTLE_ENDIAN + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; +#endif + to += 2 ; + len -= 2 ; + break ; + case 'F' : + case 'B' : + if (len < 4) + goto len_error ; + len -= 4 ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = 0 ; + to[3] = *from++ ; + to += 4 ; + break ; + case 'C' : + case 'T' : + case 'L' : + if (len < 4) + goto len_error ; +#ifdef LITTLE_ENDIAN + to[3] = *from++ ; + to[2] = *from++ ; + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; +#endif + len -= 4 ; + to += 4 ; + break ; + case '2' : /* PortMacIndicated */ + if (len < 4) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = *from++ ; + to[3] = *from++ ; + len -= 4 ; + to += 4 ; + break ; + case '4' : + if (len < 4) + goto len_error ; + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + len -= 4 ; + to += 4 ; + break ; + case 'A' : + if (len < 8) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; + memcpy((char *) to+2,(char *) from,6) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case '8' : + if (len < 8) + goto len_error ; + memcpy((char *) to,(char *) from,8) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case 'D' : + if (len < 32) + goto len_error ; + memcpy((char *) to,(char *) from,32) ; + to += 32 ; + from += 32 ; + len -= 32 ; + break ; + case 'P' : /* timestamp is NOT swapped */ + if (len < 8) + goto len_error ; + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + to[4] = *from++ ; + to[5] = *from++ ; + to[6] = *from++ ; + to[7] = *from++ ; + to += 8 ; + len -= 8 ; + break ; + default : + SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ; + break ; + } + } + +done: + /* + * make it even (in case of 'I' encoding) + * note: len is DECREMENTED + */ + if (len & 3) { + to[0] = 0 ; + to[1] = 0 ; + to += 4 - (len & 3 ) ; + len = len & ~ 3 ; + } + + /* set type and length */ + pa->p_type = para ; + pa->p_len = plen - len - PARA_LEN ; + /* return values */ + pcon->pc_p = (void *) to ; + pcon->pc_len = len ; + return ; + +sp_done: + len -= sp_len ; + to += sp_len ; + goto done ; + +len_error: + /* parameter does not fit in frame */ + pcon->pc_err = SMT_RDF_TOOLONG ; + return ; + +wrong_error: + pcon->pc_err = SMT_RDF_LENGTH ; +} + +/* + * set parameter + */ +int smt_set_para(smc,pa,index,local,set) +struct s_smc *smc ; +struct smt_para *pa ; +int index ; +int local ; +int set ; +{ +#define IFSET(x) if (set) (x) + + const struct s_p_tab *pt ; + int len ; + char *from ; + char *to ; + const char *swap ; + char c ; + char *mib_addr ; + struct fddi_mib *mib ; + struct fddi_mib_m *mib_m = 0 ; + struct fddi_mib_a *mib_a = 0 ; + struct fddi_mib_p *mib_p = 0 ; + int mac ; + int path ; + int port ; + SK_LOC_DECL(u_char,byte_val) ; + SK_LOC_DECL(u_short,word_val) ; + SK_LOC_DECL(u_long,long_val) ; + + mac = index - INDEX_MAC ; + path = index - INDEX_PATH ; + port = index - INDEX_PORT ; + len = pa->p_len ; + from = (char *) (pa + 1 ) ; + + mib = &smc->mib ; + switch (pa->p_type & 0xf000) { + case 0x1000 : + default : + mib_addr = (char *) mib ; + break ; + case 0x2000 : + if (mac < 0 || mac >= NUMMACS) { + return(SMT_RDF_NOPARAM) ; + } + mib_m = &smc->mib.m[mac] ; + mib_addr = (char *) mib_m ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + case 0x3000 : + if (path < 0 || path >= NUMPATHS) { + return(SMT_RDF_NOPARAM) ; + } + mib_a = &smc->mib.a[path] ; + mib_addr = (char *) mib_a ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + case 0x4000 : + if (port < 0 || port >= smt_mib_phys(smc)) { + return(SMT_RDF_NOPARAM) ; + } + mib_p = &smc->mib.p[port_to_mib(smc,port)] ; + mib_addr = (char *) mib_p ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + } + switch (pa->p_type) { + case SMT_P10F0 : + case SMT_P10F1 : +#ifdef ESS + case SMT_P10F2 : + case SMT_P10F3 : + case SMT_P10F4 : + case SMT_P10F5 : + case SMT_P10F6 : + case SMT_P10F7 : +#endif +#ifdef SBA + case SMT_P10F8 : + case SMT_P10F9 : +#endif + case SMT_P20F1 : + if (!local) { + return(SMT_RDF_NOPARAM) ; + } + break ; + } + pt = smt_get_ptab(pa->p_type) ; + if (!pt) { + return( (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM : + SMT_RDF_ILLEGAL ) ; + } + switch (pt->p_access) { + case AC_GR : + case AC_S : + break ; + default : + return(SMT_RDF_ILLEGAL) ; + } + to = mib_addr + pt->p_offset ; + swap = pt->p_swap ; /* pointer to swap string */ + + while (swap && (c = *swap++)) { + switch(c) { + case 'b' : + to = (char *) &byte_val ; + break ; + case 'w' : + to = (char *) &word_val ; + break ; + case 'l' : + to = (char *) &long_val ; + break ; + case 'S' : + case 'E' : + case 'R' : + case 'r' : + if (len < 4) { + goto len_error ; + } + if (from[0] | from[1]) + goto val_error ; +#ifdef LITTLE_ENDIAN + if (c == 'r') { + to[0] = from[2] ; + to[1] = from[3] ; + } + else { + to[1] = from[2] ; + to[0] = from[3] ; + } +#else + to[0] = from[2] ; + to[1] = from[3] ; +#endif + from += 4 ; + to += 2 ; + len -= 4 ; + break ; + case 'F' : + case 'B' : + if (len < 4) { + goto len_error ; + } + if (from[0] | from[1] | from[2]) + goto val_error ; + to[0] = from[3] ; + len -= 4 ; + from += 4 ; + to += 4 ; + break ; + case 'C' : + case 'T' : + case 'L' : + if (len < 4) { + goto len_error ; + } +#ifdef LITTLE_ENDIAN + to[3] = *from++ ; + to[2] = *from++ ; + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; +#endif + len -= 4 ; + to += 4 ; + break ; + case 'A' : + if (len < 8) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from+2,6) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case '4' : + if (len < 4) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,4) ; + to += 4 ; + from += 4 ; + len -= 4 ; + break ; + case '8' : + if (len < 8) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,8) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case 'D' : + if (len < 32) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,32) ; + to += 32 ; + from += 32 ; + len -= 32 ; + break ; + case 'P' : /* timestamp is NOT swapped */ + if (set) { + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + to[4] = *from++ ; + to[5] = *from++ ; + to[6] = *from++ ; + to[7] = *from++ ; + } + to += 8 ; + len -= 8 ; + break ; + default : + SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ; + return(SMT_RDF_ILLEGAL) ; + } + } + /* + * actions and internal updates + */ + switch (pa->p_type) { + case SMT_P101A: /* fddiSMTConfigPolicy */ + if (word_val & ~1) + goto val_error ; + IFSET(mib->fddiSMTConfigPolicy = word_val) ; + break ; + case SMT_P101B : /* fddiSMTConnectionPolicy */ + if (!(word_val & POLICY_MM)) + goto val_error ; + IFSET(mib->fddiSMTConnectionPolicy = word_val) ; + break ; + case SMT_P101D : /* fddiSMTTT_Notify */ + if (word_val < 2 || word_val > 30) + goto val_error ; + IFSET(mib->fddiSMTTT_Notify = word_val) ; + break ; + case SMT_P101E : /* fddiSMTStatRptPolicy */ + if (byte_val & ~1) + goto val_error ; + IFSET(mib->fddiSMTStatRptPolicy = byte_val) ; + break ; + case SMT_P101F : /* fddiSMTTrace_MaxExpiration */ + /* + * note: lower limit trace_max = 6.001773... s + * NO upper limit + */ + if (long_val < (long)0x478bf51L) + goto val_error ; + IFSET(mib->fddiSMTTrace_MaxExpiration = long_val) ; + break ; +#ifdef ESS + case SMT_P10F2 : /* fddiESSPayload */ + if (long_val > 1562) + goto val_error ; + if (set && smc->mib.fddiESSPayload != long_val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSPayload = long_val ; + } + break ; + case SMT_P10F3 : /* fddiESSOverhead */ + if (long_val < 50 || long_val > 5000) + goto val_error ; + if (set && smc->mib.fddiESSPayload && + smc->mib.fddiESSOverhead != long_val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSOverhead = long_val ; + } + break ; + case SMT_P10F4 : /* fddiESSMaxTNeg */ + if (long_val > -MS2BCLK(5) || long_val < -MS2BCLK(165)) + goto val_error ; + IFSET(mib->fddiESSMaxTNeg = long_val) ; + break ; + case SMT_P10F5 : /* fddiESSMinSegmentSize */ + if (long_val < 1 || long_val > 4478) + goto val_error ; + IFSET(mib->fddiESSMinSegmentSize = long_val) ; + break ; + case SMT_P10F6 : /* fddiESSCategory */ + if ((long_val & 0xffff) != 1) + goto val_error ; + IFSET(mib->fddiESSCategory = long_val) ; + break ; + case SMT_P10F7 : /* fddiESSSyncTxMode */ + if (word_val > 1) + goto val_error ; + IFSET(mib->fddiESSSynchTxMode = word_val) ; + break ; +#endif +#ifdef SBA + case SMT_P10F8 : /* fddiSBACommand */ + if (byte_val != SB_STOP && byte_val != SB_START) + goto val_error ; + IFSET(mib->fddiSBACommand = byte_val) ; + break ; + case SMT_P10F9 : /* fddiSBAAvailable */ + if (byte_val > 100) + goto val_error ; + IFSET(mib->fddiSBAAvailable = byte_val) ; + break ; +#endif + case SMT_P2020 : /* fddiMACRequestedPaths */ + if ((word_val & (MIB_P_PATH_PRIM_PREFER | + MIB_P_PATH_PRIM_ALTER)) == 0 ) + goto val_error ; + IFSET(mib_m->fddiMACRequestedPaths = word_val) ; + break ; + case SMT_P205F : /* fddiMACFrameErrorThreshold */ + /* 0 .. ffff acceptable */ + IFSET(mib_m->fddiMACFrameErrorThreshold = word_val) ; + break ; + case SMT_P2067 : /* fddiMACNotCopiedThreshold */ + /* 0 .. ffff acceptable */ + IFSET(mib_m->fddiMACNotCopiedThreshold = word_val) ; + break ; + case SMT_P2076: /* fddiMACMA_UnitdataEnable */ + if (byte_val & ~1) + goto val_error ; + if (set) { + mib_m->fddiMACMA_UnitdataEnable = byte_val ; + queue_event(smc,EVENT_RMT,RM_ENABLE_FLAG) ; + } + break ; + case SMT_P20F1 : /* fddiMACT_Min */ + IFSET(mib_m->fddiMACT_Min = long_val) ; + break ; + case SMT_P320F : + if (long_val > 1562) + goto val_error ; + IFSET(mib_a->fddiPATHSbaPayload = long_val) ; +#ifdef ESS + if (set) + ess_para_change(smc) ; +#endif + break ; + case SMT_P3210 : + if (long_val > 5000) + goto val_error ; + + if (long_val != 0 && mib_a->fddiPATHSbaPayload == 0) + goto val_error ; + + IFSET(mib_a->fddiPATHSbaOverhead = long_val) ; +#ifdef ESS + if (set) + ess_para_change(smc) ; +#endif + break ; + case SMT_P3213: /* fddiPATHT_Rmode */ + /* no limit : + * 0 .. 343.597 => 0 .. 2e32 * 80nS + */ + if (set) { + mib_a->fddiPATHT_Rmode = long_val ; + rtm_set_timer(smc) ; + } + break ; + case SMT_P3214 : /* fddiPATHSbaAvailable */ + if (long_val > 0x00BEBC20L) + goto val_error ; +#ifdef SBA + if (set && mib->fddiSBACommand == SB_STOP) + goto val_error ; +#endif + IFSET(mib_a->fddiPATHSbaAvailable = long_val) ; + break ; + case SMT_P3215 : /* fddiPATHTVXLowerBound */ + IFSET(mib_a->fddiPATHTVXLowerBound = long_val) ; + goto change_mac_para ; + case SMT_P3216 : /* fddiPATHT_MaxLowerBound */ + IFSET(mib_a->fddiPATHT_MaxLowerBound = long_val) ; + goto change_mac_para ; + case SMT_P3217 : /* fddiPATHMaxT_Req */ + IFSET(mib_a->fddiPATHMaxT_Req = long_val) ; + +change_mac_para: + if (set && smt_set_mac_opvalues(smc)) { + RS_SET(smc,RS_EVENT) ; + smc->sm.please_reconnect = 1 ; + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + } + break ; + case SMT_P400E : /* fddiPORTConnectionPolicies */ + if (byte_val > 1) + goto val_error ; + IFSET(mib_p->fddiPORTConnectionPolicies = byte_val) ; + break ; + case SMT_P4011 : /* fddiPORTRequestedPaths */ + /* all 3*8 bits allowed */ + IFSET(memcpy((char *)mib_p->fddiPORTRequestedPaths, + (char *)&long_val,4)) ; + break ; + case SMT_P401F: /* fddiPORTMaint_LS */ + if (word_val > 4) + goto val_error ; + IFSET(mib_p->fddiPORTMaint_LS = word_val) ; + break ; + case SMT_P403A : /* fddiPORTLer_Cutoff */ + if (byte_val < 4 || byte_val > 15) + goto val_error ; + IFSET(mib_p->fddiPORTLer_Cutoff = byte_val) ; + break ; + case SMT_P403B : /* fddiPORTLer_Alarm */ + if (byte_val < 4 || byte_val > 15) + goto val_error ; + IFSET(mib_p->fddiPORTLer_Alarm = byte_val) ; + break ; + + /* + * Actions + */ + case SMT_P103C : /* fddiSMTStationAction */ + if (smt_action(smc,SMT_STATION_ACTION, (int) word_val, 0)) + goto val_error ; + break ; + case SMT_P4046: /* fddiPORTAction */ + if (smt_action(smc,SMT_PORT_ACTION, (int) word_val, + port_to_mib(smc,port))) + goto val_error ; + break ; + default : + break ; + } + return(0) ; + +val_error: + /* parameter value in frame is out of range */ + return(SMT_RDF_RANGE) ; + +len_error: + /* parameter value in frame is too short */ + return(SMT_RDF_LENGTH) ; + +#if 0 +no_author_error: + /* parameter not setable, because the SBA is not active + * Please note: we give the return code 'not authorizeed + * because SBA denied is not a valid return code in the + * PMF protocol. + */ + return(SMT_RDF_AUTHOR) ; +#endif +} + +static const struct s_p_tab *smt_get_ptab(para) +u_short para ; +{ + const struct s_p_tab *pt ; + for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++) + ; + return(pt->p_num ? pt : 0) ; +} + +static int smt_mib_phys(smc) +struct s_smc *smc ; +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + + return(NUMPHYS) ; +#else + if (smc->s.sas == SMT_SAS) + return(1) ; + return(NUMPHYS) ; +#endif +} + +int port_to_mib(smc,p) +struct s_smc *smc ; +int p ; +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + + return(p) ; +#else + if (smc->s.sas == SMT_SAS) + return(PS) ; + return(p) ; +#endif +} + + +#ifdef DEBUG +#ifndef BOOT +void dump_smt(smc,sm,text) +struct s_smc *smc ; +struct smt_header *sm ; +char *text ; +{ + int len ; + struct smt_para *pa ; + char *c ; + int n ; + int nn ; +#ifdef LITTLE_ENDIAN + int smtlen ; +#endif + + SK_UNUSED(smc) ; + +#ifdef DEBUG_BRD + if (smc->debug.d_smtf < 2) +#else + if (debug.d_smtf < 2) +#endif + return ; +#ifdef LITTLE_ENDIAN + smtlen = sm->smt_len + sizeof(struct smt_header) ; +#endif + printf("SMT Frame [%s]:\nDA ",text) ; + dump_hex((char *) &sm->smt_dest,6) ; + printf("\tSA ") ; + dump_hex((char *) &sm->smt_source,6) ; + printf(" Class %x Type %x Version %x\n", + sm->smt_class,sm->smt_type,sm->smt_version) ; + printf("TID %lx\t\tSID ",sm->smt_tid) ; + dump_hex((char *) &sm->smt_sid,8) ; + printf(" LEN %x\n",sm->smt_len) ; + + len = sm->smt_len ; + pa = (struct smt_para *) (sm + 1) ; + while (len > 0 ) { + int plen ; +#ifdef UNIX + printf("TYPE %x LEN %x VALUE\t",pa->p_type,pa->p_len) ; +#else + printf("TYPE %04x LEN %2x VALUE\t",pa->p_type,pa->p_len) ; +#endif + n = pa->p_len ; + if ( (n < 0 ) || (n > (int)(len - PARA_LEN))) { + n = len - PARA_LEN ; + printf(" BAD LENGTH\n") ; + break ; + } +#ifdef LITTLE_ENDIAN + smt_swap_para(sm,smtlen,0) ; +#endif + if (n < 24) { + dump_hex((char *)(pa+1),(int) n) ; + printf("\n") ; + } + else { + int first = 0 ; + c = (char *)(pa+1) ; + dump_hex(c,16) ; + printf("\n") ; + n -= 16 ; + c += 16 ; + while (n > 0) { + nn = (n > 16) ? 16 : n ; + if (n > 64) { + if (first == 0) + printf("\t\t\t...\n") ; + first = 1 ; + } + else { + printf("\t\t\t") ; + dump_hex(c,nn) ; + printf("\n") ; + } + n -= nn ; + c += 16 ; + } + } +#ifdef LITTLE_ENDIAN + smt_swap_para(sm,smtlen,1) ; +#endif + plen = (pa->p_len + PARA_LEN + 3) & ~3 ; + len -= plen ; + pa = (struct smt_para *)((char *)pa + plen) ; + } + printf("-------------------------------------------------\n\n") ; +} + +void dump_hex(p,len) +char *p ; +int len ; +{ + int n = 0 ; + while (len--) { + n++ ; +#ifdef UNIX + printf("%x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; +#else + printf("%02x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; +#endif + } +} +#endif /* no BOOT */ +#endif /* DEBUG */ + + +#endif /* no SLIM_SMT */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/queue.c linux/drivers/net/skfp/queue.c --- v2.2.17/drivers/net/skfp/queue.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/queue.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,185 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + SMT Event Queue Management +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)queue.c 2.9 97/08/04 (C) SK " ; +#endif + +#define PRINTF(a,b,c) + +/* + * init event queue management + */ +void ev_init(smc) +struct s_smc *smc ; +{ + smc->q.ev_put = smc->q.ev_get = smc->q.ev_queue ; +} + +/* + * add event to queue + */ +void queue_event(smc,class,event) +struct s_smc *smc ; +int class ; +int event ; +{ + PRINTF("queue class %d event %d\n",class,event) ; + smc->q.ev_put->class = class ; + smc->q.ev_put->event = event ; + if (++smc->q.ev_put == &smc->q.ev_queue[MAX_EVENT]) + smc->q.ev_put = smc->q.ev_queue ; + + if (smc->q.ev_put == smc->q.ev_get) { + SMT_ERR_LOG(smc,SMT_E0137, SMT_E0137_MSG) ; + } +} + +/* + * timer_event is called from HW timer package. + */ +void timer_event(smc,token) +struct s_smc *smc ; +u_long token ; +{ + PRINTF("timer event class %d token %d\n", + EV_T_CLASS(token), + EV_T_EVENT(token)) ; + queue_event(smc,EV_T_CLASS(token),EV_T_EVENT(token)); +} + +/* + * event dispatcher + * while event queue is not empty + * get event from queue + * send command to state machine + * end + */ +void ev_dispatcher(smc) +struct s_smc *smc ; +{ + struct event_queue *ev ; /* pointer into queue */ + int class ; + + ev = smc->q.ev_get ; + PRINTF("dispatch get %x put %x\n",ev,smc->q.ev_put) ; + while (ev != smc->q.ev_put) { + PRINTF("dispatch class %d event %d\n",ev->class,ev->event) ; + switch(class = ev->class) { + case EVENT_ECM : /* Entity Corordination Man. */ + ecm(smc,(int)ev->event) ; + break ; + case EVENT_CFM : /* Configuration Man. */ + cfm(smc,(int)ev->event) ; + break ; + case EVENT_RMT : /* Ring Man. */ + rmt(smc,(int)ev->event) ; + break ; + case EVENT_SMT : + smt_event(smc,(int)ev->event) ; + break ; +#ifdef CONCENTRATOR + case 99 : + timer_test_event(smc,(int)ev->event) ; + break ; +#endif + case EVENT_PCMA : /* PHY A */ + case EVENT_PCMB : /* PHY B */ + default : + if (class >= EVENT_PCMA && + class < EVENT_PCMA + NUMPHYS) { + pcm(smc,class - EVENT_PCMA,(int)ev->event) ; + break ; + } + SMT_PANIC(smc,SMT_E0121, SMT_E0121_MSG) ; + return ; + } + + if (++ev == &smc->q.ev_queue[MAX_EVENT]) + ev = smc->q.ev_queue ; + + /* Renew get: it is used in queue_events to detect overruns */ + smc->q.ev_get = ev; + } +} + +/* + * smt_online connects to or disconnects from the ring + * MUST be called to initiate connection establishment + * + * on 0 disconnect + * on 1 connect + */ +u_short smt_online(smc,on) +struct s_smc *smc ; +int on ; +{ + queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ; + ev_dispatcher(smc) ; + return(smc->mib.fddiSMTCF_State) ; +} + +/* + * set SMT flag to value + * flag flag name + * value flag value + * dump current flag setting + */ +#ifdef CONCENTRATOR +void do_smt_flag(smc,flag,value) +struct s_smc *smc ; +char *flag ; +int value ; +{ +#ifdef DEBUG + struct smt_debug *deb; + + SK_UNUSED(smc) ; + +#ifdef DEBUG_BRD + deb = &smc->debug; +#else + deb = &debug; +#endif + if (!strcmp(flag,"smt")) + deb->d_smt = value ; + else if (!strcmp(flag,"smtf")) + deb->d_smtf = value ; + else if (!strcmp(flag,"pcm")) + deb->d_pcm = value ; + else if (!strcmp(flag,"rmt")) + deb->d_rmt = value ; + else if (!strcmp(flag,"cfm")) + deb->d_cfm = value ; + else if (!strcmp(flag,"ecm")) + deb->d_ecm = value ; + printf("smt %d\n",deb->d_smt) ; + printf("smtf %d\n",deb->d_smtf) ; + printf("pcm %d\n",deb->d_pcm) ; + printf("rmt %d\n",deb->d_rmt) ; + printf("cfm %d\n",deb->d_cfm) ; + printf("ecm %d\n",deb->d_ecm) ; +#endif /* DEBUG */ +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/rmt.c linux/drivers/net/skfp/rmt.c --- v2.2.17/drivers/net/skfp/rmt.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/rmt.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,674 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + SMT RMT + Ring Management +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependant functions are referenced : + * sm_ma_control() + * sm_mac_check_beacon_claim() + * + * The following HW dependant events are required : + * RM_RING_OP + * RM_RING_NON_OP + * RM_MY_BEACON + * RM_OTHER_BEACON + * RM_MY_CLAIM + * RM_TRT_EXP + * RM_VALID_CLAIM + * + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)rmt.c 2.13 99/07/02 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#define RM0_ISOLATED 0 +#define RM1_NON_OP 1 /* not operational */ +#define RM2_RING_OP 2 /* ring operational */ +#define RM3_DETECT 3 /* detect dupl addresses */ +#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ +#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ +#define RM6_DIRECTED 6 /* sending directed beacons */ +#define RM7_TRACE 7 /* trace initiated */ + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const rmt_states[] = { + "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT", + "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED", + "RM7_TRACE" +} ; + +/* + * symbolic event names + */ +static const char * const rmt_events[] = { + "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON", + "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM", + "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG", + "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK", + "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT", + "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE" +} ; +#endif + +/* + * Globals + * in struct s_rmt + */ + + +/* + * function declarations + */ +static void rmt_fsm() ; +static void start_rmt_timer0() ; +static void start_rmt_timer1() ; +static void start_rmt_timer2() ; +static void stop_rmt_timer0() ; +static void stop_rmt_timer1() ; +static void stop_rmt_timer2() ; +static void rmt_dup_actions() ; +static void rmt_reinsert_actions() ; +static void rmt_leave_actions() ; +static void rmt_new_dup_actions() ; + +#ifndef SUPERNET_3 +extern void restart_trt_for_dbcn() ; +#endif /*SUPERNET_3*/ + +/* + init RMT state machine + clear all RMT vars and flags +*/ +void rmt_init(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ; + smc->r.dup_addr_test = DA_NONE ; + smc->r.da_flag = 0 ; + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.sm_ma_avail = FALSE ; + smc->r.loop_avail = 0 ; + smc->r.bn_flag = 0 ; + smc->r.jm_flag = 0 ; + smc->r.no_flag = TRUE ; +} + +/* + RMT state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void rmt(smc,event) +struct s_smc *smc ; +int event ; +{ + int state ; + + do { + DB_RMT("RMT : state %s%s", + (smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "", + rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ; + DB_RMT(" event %s\n",rmt_events[event],0) ; + state = smc->mib.m[MAC0].fddiMACRMTState ; + rmt_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.m[MAC0].fddiMACRMTState) ; + rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ; +} + +/* + process RMT event +*/ +static void rmt_fsm(smc,cmd) +struct s_smc *smc ; +int cmd ; +{ + /* + * RM00-RM70 : from all states + */ + if (!smc->r.rm_join && !smc->r.rm_loop && + smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) && + smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) { + RS_SET(smc,RS_NORINGOP) ; + rmt_indication(smc,0) ; + GO_STATE(RM0_ISOLATED) ; + return ; + } + + switch(smc->mib.m[MAC0].fddiMACRMTState) { + case ACTIONS(RM0_ISOLATED) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + + /* + * Disable MAC. + */ + sm_ma_control(smc,MA_OFFLINE) ; + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + smc->r.sm_ma_avail = FALSE ; + smc->r.no_flag = TRUE ; + DB_RMTN(1,"RMT : ISOLATED\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM0_ISOLATED : + /*RM01*/ + if (smc->r.rm_join || smc->r.rm_loop) { + /* + * According to the standard the MAC must be reset + * here. The FORMAC will be initialized and Claim + * and Beacon Frames will be uploaded to the MAC. + * So any change of Treq will take effect NOW. + */ + sm_ma_control(smc,MA_RESET) ; + GO_STATE(RM1_NON_OP) ; + break ; + } + break ; + case ACTIONS(RM1_NON_OP) : + start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + sm_ma_control(smc,MA_BEACON) ; + DB_RMTN(1,"RMT : RING DOWN\n",0,0) ; + RS_SET(smc,RS_NORINGOP) ; + smc->r.sm_ma_avail = FALSE ; + rmt_indication(smc,0) ; + ACTIONS_DONE() ; + break ; + case RM1_NON_OP : + /*RM12*/ + if (cmd == RM_RING_OP) { + RS_SET(smc,RS_RINGOPCHANGE) ; + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM13*/ + else if (cmd == RM_TIMEOUT_NON_OP) { + smc->r.bn_flag = FALSE ; + smc->r.no_flag = TRUE ; + GO_STATE(RM3_DETECT) ; + break ; + } + break ; + case ACTIONS(RM2_RING_OP) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + smc->r.no_flag = FALSE ; + if (smc->r.rm_loop) + smc->r.loop_avail = TRUE ; + if (smc->r.rm_join) { + smc->r.sm_ma_avail = TRUE ; + if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; + else + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + } + DB_RMTN(1,"RMT : RING UP\n",0,0) ; + RS_CLEAR(smc,RS_NORINGOP) ; + RS_SET(smc,RS_RINGOPCHANGE) ; + rmt_indication(smc,1) ; + smt_stat_counter(smc,0) ; + ACTIONS_DONE() ; + break ; + case RM2_RING_OP : + /*RM21*/ + if (cmd == RM_RING_NON_OP) { + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + RS_SET(smc,RS_RINGOPCHANGE) ; + GO_STATE(RM1_NON_OP) ; + break ; + } + /*RM22a*/ + else if (cmd == RM_ENABLE_FLAG) { + if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; + else + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + } + /*RM25*/ + else if (smc->r.dup_addr_test == DA_FAILED) { + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + smc->r.da_flag = TRUE ; + GO_STATE(RM5_RING_OP_DUP) ; + break ; + } + break ; + case ACTIONS(RM3_DETECT) : + start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ; + start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_mac_check_beacon_claim(smc) ; + DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM3_DETECT : + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; + break ; + } + if (cmd == RM_TIMEOUT_D_MAX) { + smc->r.timer0_exp = TRUE ; + } + /* + *jd(22-Feb-1999) + * We need a time ">= 2*mac_d_max" since we had finished + * Claim or Beacon state. So we will restart timer0 at + * every state change. + */ + if (cmd == RM_TX_STATE_CHANGE) { + start_rmt_timer0(smc, + smc->s.mac_d_max*2, + RM_TIMEOUT_D_MAX) ; + } + /*RM32*/ + if (cmd == RM_RING_OP) { + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM33a*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) + && smc->r.bn_flag) { + smc->r.bn_flag = FALSE ; + } + /*RM33b*/ + else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { + int tx ; + /* + * set bn_flag only if in state T4 or T5: + * only if we're the beaconer should we start the + * trace ! + */ + if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { + DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0); + smc->r.bn_flag = TRUE ; + /* + * If one of the upstream stations beaconed + * and the link to the upstream neighbor is + * lost we need to restart the stuck timer to + * check the "stuck beacon" condition. + */ + start_rmt_timer1(smc,smc->s.rmt_t_stuck, + RM_TIMEOUT_T_STUCK) ; + } + /* + * We do NOT need to clear smc->r.bn_flag in case of + * not being in state T4 or T5, because the flag + * must be cleared in order to get in this condition. + */ + + DB_RMTN(2, + "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", + tx,smc->r.bn_flag) ; + } + /*RM34a*/ + else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM34b*/ + else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM34c*/ + else if (cmd == RM_VALID_CLAIM) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM36*/ + else if (cmd == RM_TIMEOUT_T_STUCK && + smc->r.rm_join && smc->r.bn_flag) { + GO_STATE(RM6_DIRECTED) ; + break ; + } + break ; + case ACTIONS(RM4_NON_OP_DUP) : + start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE); + start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_mac_check_beacon_claim(smc) ; + DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM4_NON_OP_DUP : + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; + break ; + } + /*RM41*/ + if (!smc->r.da_flag) { + GO_STATE(RM1_NON_OP) ; + break ; + } + /*RM44a*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + smc->r.bn_flag) { + smc->r.bn_flag = FALSE ; + } + /*RM44b*/ + else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { + int tx ; + /* + * set bn_flag only if in state T4 or T5: + * only if we're the beaconer should we start the + * trace ! + */ + if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { + DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0); + smc->r.bn_flag = TRUE ; + /* + * If one of the upstream stations beaconed + * and the link to the upstream neighbor is + * lost we need to restart the stuck timer to + * check the "stuck beacon" condition. + */ + start_rmt_timer1(smc,smc->s.rmt_t_stuck, + RM_TIMEOUT_T_STUCK) ; + } + /* + * We do NOT need to clear smc->r.bn_flag in case of + * not being in state T4 or T5, because the flag + * must be cleared in order to get in this condition. + */ + + DB_RMTN(2, + "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", + tx,smc->r.bn_flag) ; + } + /*RM44c*/ + else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) { + rmt_dup_actions(smc) ; + } + /*RM45*/ + else if (cmd == RM_RING_OP) { + smc->r.no_flag = FALSE ; + GO_STATE(RM5_RING_OP_DUP) ; + break ; + } + /*RM46*/ + else if (cmd == RM_TIMEOUT_T_STUCK && + smc->r.rm_join && smc->r.bn_flag) { + GO_STATE(RM6_DIRECTED) ; + break ; + } + break ; + case ACTIONS(RM5_RING_OP_DUP) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ; + ACTIONS_DONE() ; + break; + case RM5_RING_OP_DUP : + /*RM52*/ + if (smc->r.dup_addr_test == DA_PASSED) { + smc->r.da_flag = FALSE ; + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM54*/ + else if (cmd == RM_RING_NON_OP) { + smc->r.jm_flag = FALSE ; + smc->r.bn_flag = FALSE ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + break ; + case ACTIONS(RM6_DIRECTED) : + start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ; + stop_rmt_timer1(smc) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_ma_control(smc,MA_DIRECTED) ; + RS_SET(smc,RS_BEACON) ; + DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM6_DIRECTED : + /*RM63*/ + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; +#ifndef SUPERNET_3 + /* Because of problems with the Supernet II chip set + * sending of Directed Beacon will stop after 165ms + * therefore restart_trt_for_dbcn(smc) will be called + * to prevent this. + */ + restart_trt_for_dbcn(smc) ; +#endif /*SUPERNET_3*/ + break ; + } + if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + !smc->r.da_flag) { + smc->r.bn_flag = FALSE ; + GO_STATE(RM3_DETECT) ; + break ; + } + /*RM64*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + smc->r.da_flag) { + smc->r.bn_flag = FALSE ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM67*/ + else if (cmd == RM_TIMEOUT_T_DIRECT) { + GO_STATE(RM7_TRACE) ; + break ; + } + break ; + case ACTIONS(RM7_TRACE) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ; + queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; + DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM7_TRACE : + break ; + default: + SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ; + break; + } +} + +/* + * (jd) RMT duplicate address actions + * leave the ring or reinsert just as configured + */ +static void rmt_dup_actions(smc) +struct s_smc *smc ; +{ + if (smc->r.jm_flag) { + } + else { + if (smc->s.rmt_dup_mac_behavior) { + SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; + rmt_reinsert_actions(smc) ; + } + else { + SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; + rmt_leave_actions(smc) ; + } + } +} + +/* + * Reconnect to the Ring + */ +static void rmt_reinsert_actions(smc) +struct s_smc *smc ; +{ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + queue_event(smc,EVENT_ECM,EC_CONNECT) ; +} + +/* + * duplicate address detected + */ +static void rmt_new_dup_actions(smc) +struct s_smc *smc ; +{ + smc->r.da_flag = TRUE ; + smc->r.bn_flag = FALSE ; + smc->r.jm_flag = FALSE ; + /* + * we have three options : change address, jam or leave + * we leave the ring as default + * Optionally it's possible to reinsert after leaving the Ring + * but this will not conform with SMT Spec. + */ + if (smc->s.rmt_dup_mac_behavior) { + SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; + rmt_reinsert_actions(smc) ; + } + else { + SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; + rmt_leave_actions(smc) ; + } +} + + +/* + * leave the ring + */ +static void rmt_leave_actions(smc) +struct s_smc *smc ; +{ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + /* + * Note: Do NOT try again later. (with please reconnect) + * The station must be left from the ring! + */ +} + +/* + * SMT timer interface + * start RMT timer 0 + */ +static void start_rmt_timer0(smc,value,event) +struct s_smc *smc ; +u_long value ; +int event ; +{ + smc->r.timer0_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * start RMT timer 1 + */ +static void start_rmt_timer1(smc,value,event) +struct s_smc *smc ; +u_long value ; +int event ; +{ + smc->r.timer1_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * start RMT timer 2 + */ +static void start_rmt_timer2(smc,value,event) +struct s_smc *smc ; +u_long value ; +int event ; +{ + smc->r.timer2_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * stop RMT timer 0 + */ +static void stop_rmt_timer0(smc) +struct s_smc *smc ; +{ + if (smc->r.rmt_timer0.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer0) ; +} + +/* + * SMT timer interface + * stop RMT timer 1 + */ +static void stop_rmt_timer1(smc) +struct s_smc *smc ; +{ + if (smc->r.rmt_timer1.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer1) ; +} + +/* + * SMT timer interface + * stop RMT timer 2 + */ +static void stop_rmt_timer2(smc) +struct s_smc *smc ; +{ + if (smc->r.rmt_timer2.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer2) ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c --- v2.2.17/drivers/net/skfp/skfddi.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/skfddi.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,2614 @@ +/* + * File Name: + * skfddi.c + * + * Copyright Information: + * Copyright SysKonnect 1998,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. + * + * The information in this file is provided "AS IS" without warranty. + * + * Abstract: + * A Linux device driver supporting the SysKonnect FDDI PCI controller + * familie. + * + * Maintainers: + * CG Christoph Goos (cgoos@syskonnect.de) + * + * Contributors: + * DM David S. Miller + * OT Oliver Teuber + * + * Address all questions to: + * linux@syskonnect.de + * + * The technical manual for the adapters is available from SysKonnect's + * web pages: www.syskonnect.com + * Goto "Support" and search Knowledge Base for "manual". + * + * Driver Architecture: + * The driver architecture is based on the DEC FDDI driver by + * Lawrence V. Stefani and several ethernet drivers. + * I also used an existing Windows NT miniport driver. + * All hardware dependant fuctions are handled by the SysKonnect + * Hardware Module. + * The only headerfiles that are directly related to this source + * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. + * The others belong to the SysKonnect FDDI Hardware Module and + * should better not be changed. + * NOTE: + * Compiling this driver produces some warnings, but I did not fix + * this, because the Hardware Module source is used for different + * drivers, and fixing it for Linux might bring problems on other + * projects. To keep the source common for all those drivers (and + * thus simplify fixes to it), please do not clean it up! + * + * Modification History: + * Date Name Description + * 02-Mar-98 CG Created. + * + * 10-Mar-99 CG Support for 2.2.x added. + * 25-Mar-99 CG Corrected IRQ routing for SMP (APIC) + * 26-Oct-99 CG Fixed compilation error on 2.2.13 + * 12-Nov-99 CG Source code release + * 15-Dec-99 CG Removed some printk statements + * 11-Jan-2000 CG Fixed printk statements + * 21-Jan-2000 OT Added byte counter + * 07-May-2000 DM 64 bit fixes, new dma interface + * 18-Jul-2000 CG Submitted to 2.2.17 kernel source tree. + * + * Compilation options (-Dxxx): + * DRIVERDEBUG print lots of messages to log file + * DUMPPACKETS print received/transmitted packets to logfile + * + * Tested cpu architectures: + * - i386 + * - sparc64 + */ + +/* Version information string - should be updated prior to */ +/* each new release!!! */ +#define VERSION "2.07" + +static const char *boot_msg = + "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" + " SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)"; + +/* Include files */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // isdigit + +#include +#include +#include + +#include "h/types.h" +#undef ADDR // undo Linux definition +#include "h/skfbi.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smtstate.h" + + +// Define global routines +int skfp_probe(struct device *dev); + + +// Define module-wide (static) routines +static struct device *alloc_device(struct device *dev, u_long iobase); +static struct device *insert_device(struct device *dev, + int (*init) (struct device *)); +static int fddi_dev_index(unsigned char *s); +static void init_dev(struct device *dev, u_long iobase); +static void link_modules(struct device *dev, struct device *tmp); +static int skfp_driver_init(struct device *dev); +static int skfp_open(struct device *dev); +static int skfp_close(struct device *dev); +static void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct enet_statistics *skfp_ctl_get_stats(struct device *dev); +static void skfp_ctl_set_multicast_list(struct device *dev); +static void skfp_ctl_set_multicast_list_wo_lock(struct device *dev); +static int skfp_ctl_set_mac_address(struct device *dev, void *addr); +static int skfp_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static int skfp_send_pkt(struct sk_buff *skb, struct device *dev); +static void send_queued_packets(struct s_smc *smc); +static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr); +static void ResetAdapter(struct s_smc *smc); + + +// Functions needed by the hardware module +void *mac_drv_get_space(struct s_smc *smc, u_int size); +void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size); +unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt); +unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag); +void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, + int flag); +void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd); +void llc_restart_tx(struct s_smc *smc); +void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count, int len); +void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count); +void mac_drv_fill_rxd(struct s_smc *smc); +void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count); +int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead, + int la_len); +void smt_timer_poll(struct s_smc *smc); +void ring_status_indication(struct s_smc *smc, u_long status); +unsigned long smt_get_time(void); +void smt_stat_counter(struct s_smc *smc, int stat); +void cfm_state_change(struct s_smc *smc, int c_state); +void ecm_state_change(struct s_smc *smc, int e_state); +void pcm_state_change(struct s_smc *smc, int plc, int p_state); +void rmt_state_change(struct s_smc *smc, int r_state); +void drv_reset_indication(struct s_smc *smc); +void dump_data(unsigned char *Data, int length); + + +// External functions from the hardware module +extern u_int mac_drv_check_space(); +extern void read_address(struct s_smc *smc, u_char * mac_addr); +extern void card_stop(struct s_smc *smc); +extern int mac_drv_init(struct s_smc *smc); +extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys, + int len, int frame_status); +extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, + int frame_len, int frame_status); +extern int init_smt(struct s_smc *smc, u_char * mac_addr); +extern void fddi_isr(struct s_smc *smc); +extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys, + int len, int frame_status); +extern void mac_drv_rx_mode(struct s_smc *smc, int mode); +extern void mac_drv_clear_tx_queue(struct s_smc *smc); +extern void mac_drv_clear_rx_queue(struct s_smc *smc); +extern void mac_clear_multicast(struct s_smc *smc); +extern void enable_tx_irq(struct s_smc *smc, u_short queue); +extern void mac_drv_clear_txd(struct s_smc *smc); + + +// Define module-wide (static) variables + +static int num_boards = 0; /* total number of adapters configured */ +static int num_fddi = 0; +static int autoprobed = 0; + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +static struct device *unlink_modules(struct device *p); +static int loading_module = 1; +#else +static int loading_module = 0; +#endif // MODULE + +#ifdef DRIVERDEBUG +#define PRINTK(s, args...) printk(s, ## args) +#else +#define PRINTK(s, args...) +#endif // DRIVERDEBUG + +#define PRIV(dev) (&(((struct s_smc *)dev->priv)->os)) + +/* + * ============== + * = skfp_probe = + * ============== + * + * Overview: + * Probes for supported FDDI PCI controllers + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine is called by the OS for each FDDI device name (fddi0, + * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. + * If loaded as a module, it will detect and initialize all + * adapters the first time it is called. + * + * Let's say that skfp_probe() is getting called to initialize fddi0. + * Furthermore, let's say there are three supported controllers in the + * system. Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2 + * will be initialized and a global flag will be set to indicate that + * skfp_probe() has already been called. + * + * However...the OS doesn't know that we've already initialized + * devices fddi1 and fddi2 so skfp_probe() gets called again and again + * until it reaches the end of the device list for FDDI (presently, + * fddi7). It's important that the driver "pretend" to probe for + * devices fddi1 and fddi2 and return success. Devices fddi3 + * through fddi7 will return failure since they weren't initialized. + * + * This algorithm seems to work for the time being. As other FDDI + * drivers are written for Linux, a more generic approach (perhaps + * similar to the Ethernet card approach) may need to be implemented. + * + * Return Codes: + * 0 - This device (fddi0, fddi1, etc) configured successfully + * -ENODEV - No devices present, or no SysKonnect FDDI PCI device + * present for this device name + * + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * initialized and the board resources are read and stored in + * the device structure. + */ +int skfp_probe(struct device *dev) +{ + int i; /* used in for loops */ + struct pci_dev *pdev = NULL; /* PCI device structure */ +#ifndef MEM_MAPPED_IO + u16 port; /* temporary I/O (port) address */ + int port_len; /* length of port address range (in bytes) */ +#else + unsigned long port; +#endif + u16 command; /* PCI Configuration space Command register val */ + struct s_smc *smc; /* board pointer */ + struct device *tmp = dev; + u8 first_dev_used = 0; + u16 SubSysId; +#ifdef __sparc_v9__ + unsigned short pci_tmp; +#endif + + PRINTK(KERN_INFO "entering skfp_probe\n"); + + /* + * Verify whether we're going through skfp_probe() again + * + * If so, see if we're going through for a subsequent fddi device that + * we've already initialized. If we are, return success (0). If not, + * return failure (-ENODEV). + */ + + if (autoprobed) { + PRINTK(KERN_INFO "Already entered skfp_probe\n"); + if (dev != NULL) { + if ((strncmp(dev->name, "fddi", 4) == 0) && + (dev->base_addr != 0)) { + return (0); + } + return (-ENODEV); + } + } + autoprobed = 1; /* set global flag */ + + printk("%s\n", boot_msg); + + /* Scan for Syskonnect FDDI PCI controllers */ + if (!pci_present()) { /* is PCI BIOS even present? */ + printk("no PCI BIOS present\n"); + return (-ENODEV); + } + for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) { // scan for PCI cards + PRINTK(KERN_INFO "Check device %d\n", i); + if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, + pdev)) == 0) { + break; + } + +#ifndef MEM_MAPPED_IO + /* Verify that I/O enable bit is set (PCI slot is enabled) */ + pci_read_config_word(pdev, PCI_COMMAND, &command); + if ((command & PCI_COMMAND_IO) == 0) { + PRINTK("I/O enable bit not set!"); + PRINTK(" Verify that slot is enabled\n"); + continue; + } + + /* Turn off memory mapped space and enable mastering */ + + PRINTK(KERN_INFO "Command Reg: %04x\n", command); + command |= PCI_COMMAND_MASTER; + command &= ~PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, command); + + /* Read I/O base address from PCI Configuration Space */ + + pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port); + port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0) + + /* Verify port address range is not already being used */ + + port_len = FP_IO_LEN; + if (check_region(port, port_len) != 0) { + printk("I/O range allocated to adapter"); + printk(" (0x%X-0x%X) is already being used!\n", port, + (port + port_len - 1)); + continue; + } +#else + /* Verify that MEM enable bit is set (PCI slot is enabled) */ + pci_read_config_word(pdev, PCI_COMMAND, &command); + if ((command & PCI_COMMAND_MEMORY) == 0) { + PRINTK("MEMORY-I/O enable bit not set!"); + PRINTK(" Verify that slot is enabled\n"); + continue; + } + + pci_set_master(pdev); + +#ifdef __sparc_v9__ + /* SPARC machines do not initialize the cache line size */ + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64); + /* SPARC machines do not set "Memory write and invalidate" */ + pci_read_config_word(pdev, PCI_COMMAND, &pci_tmp); + pci_tmp |= PCI_COMMAND_INVALIDATE; + pci_write_config_word(pdev, PCI_COMMAND, pci_tmp); +#endif + + port = pdev->base_address[0]; + port &= PCI_BASE_ADDRESS_MEM_MASK; + +#ifndef __sparc_v9__ + port = (unsigned long)ioremap(port, 0x4000); +#else + /* workaround for bug in 2.2 kernel for sparcv9 */ + /* use port as is */ +#endif + if (!port){ + printk("skfp: Unable to map MEMORY register, " + "FDDI adapter will be disabled.\n"); + break; + } +#endif + + if ((!loading_module) || first_dev_used) { + /* Allocate a device structure for this adapter */ + tmp = alloc_device(dev, port); + } + first_dev_used = 1; // only significant first time + + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId); + + if (tmp != NULL) { + if (loading_module) + link_modules(dev, tmp); + dev = tmp; + init_dev(dev, port); + dev->irq = pdev->irq; + + /* Initialize board structure with bus-specific info */ + + smc = (struct s_smc *) dev->priv; + smc->os.dev = dev; + smc->os.bus_type = SK_BUS_TYPE_PCI; + smc->os.pdev = *pdev; + smc->os.QueueSkb = MAX_TX_QUEUE_LEN; + smc->os.MaxFrameSize = MAX_FRAME_SIZE; + smc->os.dev = dev; + smc->hw.slot = -1; + smc->os.ResetRequested = FALSE; + skb_queue_head_init(&smc->os.SendSkbQueue); + + if (skfp_driver_init(dev) == 0) { + // only increment global board + // count on success + num_boards++; + request_region(dev->base_addr, + FP_IO_LEN, dev->name); + if ((SubSysId & 0xff00) == 0x5500 || + (SubSysId & 0xff00) == 0x5800) { + printk("%s: SysKonnect FDDI PCI adapter" + " found (SK-%04X)\n", dev->name, + SubSysId); + } else { + printk("%s: FDDI PCI adapter found\n", + dev->name); + } + } else { + kfree(dev); + i = SKFP_MAX_NUM_BOARDS; // stop search + + } + + } // if (dev != NULL) + + } // for SKFP_MAX_NUM_BOARDS + + /* + * If we're at this point we're going through skfp_probe() for the + * first time. Return success (0) if we've initialized 1 or more + * boards. Otherwise, return failure (-ENODEV). + */ + + if (num_boards > 0) + return (0); + else { + printk("no SysKonnect FDDI adapter found\n"); + return (-ENODEV); + } +} // skfp_probe + + +/************************ + * + * Search the entire 'fddi' device list for a fixed probe. If a match isn't + * found then check for an autoprobe or unused device location. If they + * are not available then insert a new device structure at the end of + * the current list. + * + ************************/ +static struct device *alloc_device(struct device *dev, u_long iobase) +{ + struct device *adev = NULL; + int fixed = 0, new_dev = 0; + + PRINTK(KERN_INFO "entering alloc_device\n"); + if (!dev) + return dev; + + num_fddi = fddi_dev_index(dev->name); + if (loading_module) { + num_fddi++; + dev = insert_device(dev, skfp_probe); + return dev; + } + while (1) { + if (((dev->base_addr == NO_ADDRESS) || + (dev->base_addr == 0)) && !adev) { + adev = dev; + } else if ((dev->priv == NULL) && (dev->base_addr == iobase)) { + fixed = 1; + } else { + if (dev->next == NULL) { + new_dev = 1; + } else if (strncmp(dev->next->name, "fddi", 4) != 0) { + new_dev = 1; + } + } + if ((dev->next == NULL) || new_dev || fixed) + break; + dev = dev->next; + num_fddi++; + } // while (1) + + if (adev && !fixed) { + dev = adev; + num_fddi = fddi_dev_index(dev->name); + new_dev = 0; + } + if (((dev->next == NULL) && ((dev->base_addr != NO_ADDRESS) && + (dev->base_addr != 0)) && !fixed) || + new_dev) { + num_fddi++; /* New device */ + dev = insert_device(dev, skfp_probe); + } + if (dev) { + if (!dev->priv) { + /* Allocate space for private board structure */ + dev->priv = (void *) kmalloc(sizeof(struct s_smc), + GFP_KERNEL); + if (dev->priv == NULL) { + printk("%s: Could not allocate memory for", + dev->name); + printk(" private board structure!\n"); + return (NULL); + } + /* clear structure */ + memset(dev->priv, 0, sizeof(struct s_smc)); + } + } + return dev; +} // alloc_device + + + +/************************ + * + * Initialize device structure + * + ************************/ +static void init_dev(struct device *dev, u_long iobase) +{ + /* Initialize new device structure */ + + dev->rmem_end = 0; /* shared memory isn't used */ + dev->rmem_start = 0; /* shared memory isn't used */ + dev->mem_end = 0; /* shared memory isn't used */ + dev->mem_start = 0; /* shared memory isn't used */ + dev->base_addr = iobase; /* save port (I/O) base address */ + dev->irq = 0; /* set in skfp_driver_init() */ + dev->if_port = 0; /* not applicable to FDDI adapters */ + dev->dma = 0; /* Bus Master DMA doesn't require channel */ + dev->interrupt = 0; + + dev->get_stats = &skfp_ctl_get_stats; + dev->open = &skfp_open; + dev->stop = &skfp_close; + dev->hard_start_xmit = &skfp_send_pkt; + dev->hard_header = NULL; /* set in fddi_setup() */ + dev->rebuild_header = NULL; /* set in fddi_setup() */ + dev->set_multicast_list = &skfp_ctl_set_multicast_list; + dev->set_mac_address = &skfp_ctl_set_mac_address; + dev->do_ioctl = &skfp_ioctl; + dev->set_config = NULL; /* not supported for now &&& */ + dev->header_cache_update = NULL; /* not supported */ + dev->change_mtu = NULL; /* set in fddi_setup() */ + + /* Initialize remaining device structure information */ + fddi_setup(dev); +} // init_device + + +/************************ + * + * If at end of fddi device list and can't use current entry, malloc + * one up. If memory could not be allocated, print an error message. + * +************************/ +static struct device *insert_device(struct device *dev, + int (*init) (struct device *)) +{ + struct device *new; + int len; + + PRINTK(KERN_INFO "entering insert_device\n"); + len = sizeof(struct device) + sizeof(struct s_smc); + new = (struct device *) kmalloc(len, GFP_KERNEL); + if (new == NULL) { + printk("fddi%d: Device not initialised, insufficient memory\n", + num_fddi); + return NULL; + } else { + memset((char *) new, 0, len); + new->name = (char *) (new + 1); + new->priv = (struct s_smc *) (new->name + 8); + new->init = init; /* initialisation routine */ + if (!loading_module) { + new->next = dev->next; + dev->next = new; + } + /* create new device name */ + if (num_fddi > 999) { + sprintf(new->name, "fddi????"); + } else { + sprintf(new->name, "fddi%d", num_fddi); + } + } + return new; +} // insert_device + + +/************************ + * + * Get the number of a "fddiX" string + * + ************************/ +static int fddi_dev_index(unsigned char *s) +{ + int i = 0, j = 0; + + for (; *s; s++) { + if (isdigit(*s)) { + j = 1; + i = (i * 10) + (*s - '0'); + } else if (j) + break; + } + return i; +} // fddi_dev_index + + +/************************ + * + * Used if loaded as module only. Link the device structures + * together. Needed to release them all at unload. + * +************************/ +static void link_modules(struct device *dev, struct device *tmp) +{ + struct device *p = dev; + + if (p) { + while (((struct s_smc *) (p->priv))->os.next_module) { + p = ((struct s_smc *) (p->priv))->os.next_module; + } + + if (dev != tmp) { + ((struct s_smc *) (p->priv))->os.next_module = tmp; + } else { + ((struct s_smc *) (p->priv))->os.next_module = NULL; + } + } + return; +} // link_modules + + + +/* + * ==================== + * = skfp_driver_init = + * ==================== + * + * Overview: + * Initializes remaining adapter board structure information + * and makes sure adapter is in a safe state prior to skfp_open(). + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function allocates additional resources such as the host memory + * blocks needed by the adapter. + * The adapter is also reset. The OS must call skfp_open() to open + * the adapter and bring it on-line. + * + * Return Codes: + * 0 - initialization succeeded + * -1 - initialization failed + */ +static int skfp_driver_init(struct device *dev) +{ + struct s_smc *smc = (struct s_smc *) dev->priv; + skfddi_priv *bp = PRIV(dev); + u8 val; /* used for I/O read/writes */ + + PRINTK(KERN_INFO "entering skfp_driver_init\n"); + + // set the io address in private structures + bp->base_addr = dev->base_addr; + smc->hw.iop = dev->base_addr; + + // Get the interrupt level from the PCI Configuration Table + val = dev->irq; + + smc->hw.irq = val; + + spin_lock_init(&bp->DriverLock); + + // Determine the required size of the 'shared' memory area. + bp->SharedMemSize = mac_drv_check_space(); + PRINTK(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize); + if (bp->SharedMemSize > 0) { + bp->SharedMemSize += 16; // for descriptor alignment + + bp->SharedMemAddr = kmalloc(bp->SharedMemSize, GFP_KERNEL); + if (!bp->SharedMemSize) { + printk("could not allocate mem for "); + printk("hardware module: %ld byte\n", + bp->SharedMemSize); + return (-1); + } + bp->SharedMemHeap = 0; // Nothing used yet. + + } else { + bp->SharedMemAddr = NULL; + bp->SharedMemHeap = 0; + } // SharedMemSize > 0 + + memset(bp->SharedMemAddr, 0, bp->SharedMemSize); + + card_stop(smc); // Reset adapter. + + PRINTK(KERN_INFO "mac_drv_init()..\n"); + if (mac_drv_init(smc) != 0) { + PRINTK(KERN_INFO "mac_drv_init() failed.\n"); + return (-1); + } + read_address(smc, NULL); + PRINTK(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n", + smc->hw.fddi_canon_addr.a[0], + smc->hw.fddi_canon_addr.a[1], + smc->hw.fddi_canon_addr.a[2], + smc->hw.fddi_canon_addr.a[3], + smc->hw.fddi_canon_addr.a[4], + smc->hw.fddi_canon_addr.a[5]); + memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6); + + smt_reset_defaults(smc, 0); + + return (0); +} // skfp_driver_init + + +/* + * ============= + * = skfp_open = + * ============= + * + * Overview: + * Opens the adapter + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function brings the adapter to an operational state. + * + * Return Codes: + * 0 - Adapter was successfully opened + * -EAGAIN - Could not register IRQ + */ +static int skfp_open(struct device *dev) +{ + struct s_smc *smc = (struct s_smc *) dev->priv; + + PRINTK(KERN_INFO "entering skfp_open\n"); + /* Register IRQ - support shared interrupts by passing device ptr */ + if (request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ, + dev->name, dev)) { + printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq); + return (-EAGAIN); + } + /* + * Set current address to factory MAC address + * + * Note: We've already done this step in skfp_driver_init. + * However, it's possible that a user has set a node + * address override, then closed and reopened the + * adapter. Unless we reset the device address field + * now, we'll continue to use the existing modified + * address. + */ + read_address(smc, NULL); + memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6); + + init_smt(smc, NULL); + smt_online(smc, 1); + STI_FBI(); + + MOD_INC_USE_COUNT; + + /* Set device structure info */ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* Clear local multicast address tables */ + mac_clear_multicast(smc); + + /* Disable promiscuous filter settings */ + mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); + + return (0); +} // skfp_open + + +/* + * ============== + * = skfp_close = + * ============== + * + * Overview: + * Closes the device/module. + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine closes the adapter and brings it to a safe state. + * The interrupt service routine is deregistered with the OS. + * The adapter can be opened again with another call to skfp_open(). + * + * Return Codes: + * Always return 0. + * + * Assumptions: + * No further requests for this adapter are made after this routine is + * called. skfp_open() can be called to reset and reinitialize the + * adapter. + */ +static int skfp_close(struct device *dev) +{ + struct s_smc *smc = (struct s_smc *) dev->priv; + struct sk_buff *skb; + skfddi_priv *bp = PRIV(dev); + + CLI_FBI(); + smt_reset_defaults(smc, 1); + card_stop(smc); + mac_drv_clear_tx_queue(smc); + mac_drv_clear_rx_queue(smc); + + /* Clear device structure flags */ + dev->start = 0; + dev->tbusy = 1; + + /* Deregister (free) IRQ */ + free_irq(dev->irq, dev); + + for (;;) { + skb = skb_dequeue(&bp->SendSkbQueue); + if (skb == NULL) + break; + bp->QueueSkb++; + dev_kfree_skb(skb); + } + + MOD_DEC_USE_COUNT; + + return (0); +} // skfp_close + + +/* + * ================== + * = skfp_interrupt = + * ================== + * + * Overview: + * Interrupt processing routine + * + * Returns: + * None + * + * Arguments: + * irq - interrupt vector + * dev_id - pointer to device information + * regs - pointer to registers structure + * + * Functional Description: + * This routine calls the interrupt processing routine for this adapter. It + * disables and reenables adapter interrupts, as appropriate. We can support + * shared interrupts since the incoming dev_id pointer provides our device + * structure context. All the real work is done in the hardware module. + * + * Return Codes: + * None + * + * Assumptions: + * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC + * on Intel-based systems) is done by the operating system outside this + * routine. + * + * System interrupts are enabled through this call. + * + * Side Effects: + * Interrupts are disabled, then reenabled at the adapter. + */ + +void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct s_smc *smc; /* private board structure pointer */ + skfddi_priv *bp = PRIV(dev); + + + if (dev == NULL) { + printk("%s: ERROR: irq %d for unknown device\n", dev->name, irq); + return; + } + if (dev->interrupt) { + printk("%s: ERROR: reentering interrupt handler\n", dev->name); + } + dev->interrupt = 1; + + smc = (struct s_smc *) dev->priv; + + // IRQs enabled or disabled ? + if (inpd(ADDR(B0_IMSK)) == 0) { + // IRQs are disabled. + // printk(KERN_INFO "Foreign IRQ (B).\n"); + dev->interrupt = 0; + return; + } + // Note: At this point, IRQs are enabled. + if ((inpd(ISR_A) & smc->hw.is_imask) == 0) { // IRQ? + // Adapter did not issue an IRQ. + // printk(KERN_INFO "Foreign IRQ (C).\n"); + dev->interrupt = 0; + return; + } + CLI_FBI(); // Disable IRQs from our adapter. + spin_lock(&bp->DriverLock); + + // Call interrupt handler in hardware module (HWM). + fddi_isr(smc); + + if (smc->os.ResetRequested) { + ResetAdapter(smc); + smc->os.ResetRequested = FALSE; + } + dev->interrupt = 0; + spin_unlock(&bp->DriverLock); + STI_FBI(); // Enable IRQs from our adapter. + + return; +} // skfp_interrupt + + +/* + * ====================== + * = skfp_ctl_get_stats = + * ====================== + * + * Overview: + * Get statistics for FDDI adapter + * + * Returns: + * Pointer to FDDI statistics structure + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Gets current MIB objects from adapter, then + * returns FDDI statistics structure as defined + * in if_fddi.h. + * + * Note: Since the FDDI statistics structure is + * still new and the device structure doesn't + * have an FDDI-specific get statistics handler, + * we'll return the FDDI statistics structure as + * a pointer to an Ethernet statistics structure. + * That way, at least the first part of the statistics + * structure can be decoded properly. + * We'll have to pay attention to this routine as the + * device structure becomes more mature and LAN media + * independent. + * + */ +struct enet_statistics *skfp_ctl_get_stats(struct device *dev) +{ + struct s_smc *bp = (struct s_smc *) dev->priv; + + /* Fill the bp->stats structure with driver-maintained counters */ + + bp->os.MacStat.port_bs_flag[0] = 0x1234; + bp->os.MacStat.port_bs_flag[1] = 0x5678; +// goos: need to fill out fddi statistic +#if 0 + /* Get FDDI SMT MIB objects */ + +/* Fill the bp->stats structure with the SMT MIB object values */ + + memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); + bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; + bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; + bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; + memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); + bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; + bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; + bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; + bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; + bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; + bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; + bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; + bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; + bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; + bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; + bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; + bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; + bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; + bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; + bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; + bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; + bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; + bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; + bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; + bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; + bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; + bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; + bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; + bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; + memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); + bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; + bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; + bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; + memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); + bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; + bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; + bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; + bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; + bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; + bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; + bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; + bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; + bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; + bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; + bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; + bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; + bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; + bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; + bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; + bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; + memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); + bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; + bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; + bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; + bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; + bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; + bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; + bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; + bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; + bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; + bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; + memcpy(&bp->stats.port_requested_paths[0 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); + memcpy(&bp->stats.port_requested_paths[1 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); + bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; + bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; + bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; + bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; + bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; + bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; + bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; + bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; + bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; + bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; + bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; + bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; + bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; + bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; + bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; + bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; + bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; + bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; + bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; + bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; + bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; + bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; + bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; + bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; + bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; + bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; + + + /* Fill the bp->stats structure with the FDDI counter values */ + + bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; + bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; + bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; + bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; + bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; + bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; + bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; + bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; + bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; + bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; + bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; + +#endif + return ((struct enet_statistics *) &bp->os.MacStat); +} // ctl_get_stat + + +/* + * ============================== + * = skfp_ctl_set_multicast_list = + * ============================== + * + * Overview: + * Enable/Disable LLC frame promiscuous mode reception + * on the adapter and/or update multicast address table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function aquires the driver lock and only calls + * skfp_ctl_set_multicast_list_wo_lock then. + * This routine follows a fairly simple algorithm for setting the + * adapter filters and CAM: + * + * if IFF_PROMISC flag is set + * enable promiscuous mode + * else + * disable promiscuous mode + * if number of multicast addresses <= max. multicast number + * add mc addresses to adapter table + * else + * enable promiscuous mode + * update adapter filters + * + * Assumptions: + * Multicast addresses are presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter filters are updated. + */ +static void skfp_ctl_set_multicast_list(struct device *dev) +{ +#ifdef __SMP__ + skfddi_priv *bp = PRIV(dev); +#endif + unsigned long Flags; + + spin_lock_irqsave(&bp->DriverLock, Flags); + skfp_ctl_set_multicast_list_wo_lock(dev); + spin_unlock_irqrestore(&bp->DriverLock, Flags); + return; +} // skfp_ctl_set_multicast_list + + + +static void skfp_ctl_set_multicast_list_wo_lock(struct device *dev) +{ + struct s_smc *smc = (struct s_smc *) dev->priv; + struct dev_mc_list *dmi; /* ptr to multicast addr entry */ + int i; + + /* Enable promiscuous mode, if necessary */ + if (dev->flags & IFF_PROMISC) { + mac_drv_rx_mode(smc, RX_ENABLE_PROMISC); + PRINTK(KERN_INFO "PROMISCUOUS MODE ENABLED\n"); + } + /* Else, update multicast address table */ + else { + mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); + PRINTK(KERN_INFO "PROMISCUOUS MODE DISABLED\n"); + + // Reset all MC addresses + mac_clear_multicast(smc); + mac_drv_rx_mode(smc, RX_DISABLE_ALLMULTI); + + if (dev->flags & IFF_ALLMULTI) { + mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); + PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); + } else if (dev->mc_count > 0) { + if (dev->mc_count <= FPMAX_MULTICAST) { + /* use exact filtering */ + + // point to first multicast addr + dmi = dev->mc_list; + + for (i = 0; i < dev->mc_count; i++) { + mac_add_multicast(smc, + dmi->dmi_addr, 1); + PRINTK(KERN_INFO "ENABLE MC ADDRESS:"); + PRINTK(" %02x %02x %02x ", + dmi->dmi_addr[0], + dmi->dmi_addr[1], + dmi->dmi_addr[2]); + PRINTK("%02x %02x %02x\n", + dmi->dmi_addr[3], + dmi->dmi_addr[4], + dmi->dmi_addr[5]); + dmi = dmi->next; + } // for + + } else { // more MC addresses than HW supports + + mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); + PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n"); + } + } else { // no MC addresses + + PRINTK(KERN_INFO "DISABLE ALL MC ADDRESSES\n"); + } + + /* Update adapter filters */ + mac_update_multicast(smc); + } + return; +} // skfp_ctl_set_multicast_list_wo_lock + + +/* + * =========================== + * = skfp_ctl_set_mac_address = + * =========================== + * + * Overview: + * set new mac address on adapter and update dev_addr field in device table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * addr - pointer to sockaddr structure containing unicast address to set + * + * Assumptions: + * The address pointed to by addr->sa_data is a valid unicast + * address and is presented in canonical (LSB) format. + */ +static int skfp_ctl_set_mac_address(struct device *dev, void *addr) +{ + struct s_smc *smc = (struct s_smc *) dev->priv; + struct sockaddr *p_sockaddr = (struct sockaddr *) addr; +#ifdef __SMP__ + skfddi_priv *bp = (skfddi_priv *) & smc->os; +#endif + unsigned long Flags; + + + memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); + spin_lock_irqsave(&bp->DriverLock, Flags); + ResetAdapter(smc); + spin_unlock_irqrestore(&bp->DriverLock, Flags); + + return (0); /* always return zero */ +} // skfp_ctl_set_mac_address + + +/* + * ============== + * = skfp_ioctl = + * ============== + * + * Overview: + * + * Perform IOCTL call functions here. Some are privileged operations and the + * effective uid is checked in those cases. + * + * Returns: + * status value + * 0 - success + * other - failure + * + * Arguments: + * dev - pointer to device information + * rq - pointer to ioctl request structure + * cmd - ? + * + */ + + +static int skfp_ioctl(struct device *dev, struct ifreq *rq, int cmd) +{ + skfddi_priv *lp = PRIV(dev); + struct s_skfp_ioctl ioc; + int status = 0; + + copy_from_user(&ioc, rq->ifr_data, sizeof(struct s_skfp_ioctl)); + switch (ioc.cmd) { + case SKFP_GET_STATS: /* Get the driver statistics */ + ioc.len = sizeof(lp->MacStat); + copy_to_user(ioc.data, skfp_ctl_get_stats(dev), ioc.len); + break; + case SKFP_CLR_STATS: /* Zero out the driver statistics */ + if (suser()) { + memset(&lp->MacStat, 0, sizeof(lp->MacStat)); + } else { + status = -EPERM; + } + break; + default: + printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd); + } // switch + + return status; +} // skfp_ioctl + + +/* + * ===================== + * = skfp_send_pkt = + * ===================== + * + * Overview: + * Queues a packet for transmission and try to transmit it. + * + * Returns: + * Condition code + * + * Arguments: + * skb - pointer to sk_buff to queue for transmission + * dev - pointer to device information + * + * Functional Description: + * Here we assume that an incoming skb transmit request + * is contained in a single physically contiguous buffer + * in which the virtual address of the start of packet + * (skb->data) can be converted to a physical address + * by using virt_to_bus(). + * + * We have an internal queue for packets we can not send + * immediately. Packets in this queue can be given to the + * adapter if transmit buffers are freed. + * + * We can't free the skb until after it's been DMA'd + * out by the adapter, so we'll keep it in the driver and + * return it in mac_drv_tx_complete. + * + * Return Codes: + * 0 - driver has queued and/or sent packet + * 1 - caller should requeue the sk_buff for later transmission + * + * Assumptions: + * The entire packet is stored in one physically + * contiguous buffer which is not cached and whose + * 32-bit physical address can be determined. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. skfp_interrupt) for the same board on a + * different thread. + * + * Side Effects: + * None + */ +static int skfp_send_pkt(struct sk_buff *skb, struct device *dev) +{ + skfddi_priv *bp = PRIV(dev); + unsigned long Flags; + + PRINTK(KERN_INFO "skfp_send_pkt\n"); + if (dev->interrupt) + return 1; + + if (skb == NULL) { + mark_bh(NET_BH); + return 0; + } + if (dev->tbusy) { + // printk(KERN_INFO "%s transmit timeout\n", dev->name); + spin_lock_irqsave(&bp->DriverLock, Flags); + ResetAdapter((struct s_smc *) dev->priv); + spin_unlock_irqrestore(&bp->DriverLock, Flags); + return 1; + } + /* + * Verify that incoming transmit request is OK + * + * Note: The packet size check is consistent with other + * Linux device drivers, although the correct packet + * size should be verified before calling the + * transmit routine. + */ + + if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) { + bp->MacStat.tx_errors++; /* bump error counter */ + // dequeue packets from xmt queue and send them + mark_bh(NET_BH); + dev_kfree_skb(skb); + return (0); /* return "success" */ + } + if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { + printk(KERN_INFO "%s: ERROR: Transmitter access conflict.\n", + dev->name); + return 1; + } + if (bp->QueueSkb == 0) { // return with tbusy set: queue full + + // printk(KERN_INFO "%s: queue full\n", dev->name); + return 1; + } + bp->QueueSkb--; + skb_queue_tail(&bp->SendSkbQueue, skb); + send_queued_packets((struct s_smc *) dev->priv); + if (bp->QueueSkb > 0) { + dev->tbusy = 0; + } + dev->trans_start = jiffies; + return 0; + +} // skfp_send_pkt + + +/* + * ======================= + * = send_queued_packets = + * ======================= + * + * Overview: + * Send packets from the driver queue as long as there are some and + * transmit resources are available. + * + * Returns: + * None + * + * Arguments: + * smc - pointer to smc (adapter) structure + * + * Functional Description: + * Take a packet from queue if there is any. If not, then we are done. + * Check if there are resources to send the packet. If not, requeue it + * and exit. + * Set packet descriptor flags and give packet to adapter. + * Check if any send resources can be freed (we do not use the + * transmit complete interrupt). + */ +static void send_queued_packets(struct s_smc *smc) +{ + skfddi_priv *bp = (skfddi_priv *) & smc->os; + struct sk_buff *skb; + unsigned char fc; + int queue; + struct s_smt_fp_txd *txd; // Current TxD. + static int log_counter=0; // to avoid to much logging + unsigned long Flags; + + int frame_status; // HWM tx frame status. + + PRINTK(KERN_INFO "send queued packets\n"); + for (;;) { + // send first buffer from queue + skb = skb_dequeue(&bp->SendSkbQueue); + + if (!skb) { + PRINTK(KERN_INFO "queue empty\n"); + return; + } // queue empty ! + + spin_lock_irqsave(&bp->DriverLock, Flags); + fc = skb->data[0]; + queue = (fc & FC_SYNC_BIT) ? QUEUE_S : QUEUE_A0; +#ifdef ESS + // Check if the frame may/must be sent as a synchronous frame. + + if ((fc & ~(FC_SYNC_BIT | FC_LLC_PRIOR)) == FC_ASYNC_LLC) { + // It's an LLC frame. + if (!smc->ess.sync_bw_available) + fc &= ~FC_SYNC_BIT; // No bandwidth available. + + else { // Bandwidth is available. + + if (smc->mib.fddiESSSynchTxMode) { + // Send as sync. frame. + fc |= FC_SYNC_BIT; + } + } + } +#endif // ESS + frame_status = hwm_tx_init(smc, fc, 1, skb->len, queue); + + if ((frame_status & (LOC_TX | LAN_TX)) == 0) { + // Unable to send the frame. + + if ((frame_status & RING_DOWN) != 0) { + // Ring is down. + PRINTK("Tx attempt while ring down.\n"); + } else if ((frame_status & OUT_OF_TXD) != 0) { + if(log_counter == 0) { + // printk(KERN_INFO "%s: out of TXDs.\n", + // bp->dev->name); + } + log_counter++; + if (log_counter >= 100000) + log_counter = 0; + } else { + if(log_counter == 0) { + // printk(KERN_INFO "%s: out of transmit" + // "resources\n", + // bp->dev->name); + } + log_counter++; + if (log_counter >= 100000) + log_counter = 0; + } + + // Note: We will retry the operation as soon as + // transmit resources become available. + skb_queue_head(&bp->SendSkbQueue, skb); + spin_unlock_irqrestore(&bp->DriverLock, Flags); + return; // Packet has been queued. + + } // if (unable to send frame) + + bp->QueueSkb++; // one packet less in local queue + + // source address in packet ? + CheckSourceAddress(skb->data, smc->hw.fddi_canon_addr.a); + + txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue); + + if (frame_status & LAN_TX) { + txd->txd_os.skb = skb; // save skb + + } + hwm_tx_frag(smc, skb->data, virt_to_bus(skb->data), skb->len, + frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF); + + if (!(frame_status & LAN_TX)) { // local only frame + dev_kfree_skb(skb); + } + spin_unlock_irqrestore(&bp->DriverLock, Flags); + } // for + + return; // never reached + +} // send_queued_packets + + +/************************ + * + * CheckSourceAddress + * + * Verify if the source address is set. Insert it if necessary. + * + ************************/ +void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) +{ + unsigned char SRBit; + + if ((((unsigned long) frame[1 + 6]) & ~0x01) != 0) // source routing bit + + return; + if ((unsigned short) frame[1 + 10] != 0) + return; + SRBit = frame[1 + 6] & 0x01; + memcpy(&frame[1 + 6], hw_addr, 6); + frame[8] |= SRBit; +} // CheckSourceAddress + + +/************************ + * + * ResetAdapter + * + * Reset the adapter and bring it back to operational mode. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +static void ResetAdapter(struct s_smc *smc) +{ + + PRINTK(KERN_INFO "[fddi: ResetAdapter]\n"); + + // Stop the adapter. + + card_stop(smc); // Stop all activity. + + // Clear the transmit and receive descriptor queues. + mac_drv_clear_tx_queue(smc); + mac_drv_clear_rx_queue(smc); + + // Restart the adapter. + + smt_reset_defaults(smc, 1); // Initialize the SMT module. + + init_smt(smc, (smc->os.dev)->dev_addr); // Initialize the hardware. + + smt_online(smc, 1); // Insert into the ring again. + STI_FBI(); + + // Restore original receive mode (multicasts, promiscuous, etc.). + skfp_ctl_set_multicast_list_wo_lock(smc->os.dev); +} // ResetAdapter + + +//--------------- functions called by hardware module ---------------- + +/************************ + * + * llc_restart_tx + * + * The hardware driver calls this routine when the transmit complete + * interrupt bits (end of frame) for the synchronous or asynchronous + * queue is set. + * + * NOTE The hardware driver calls this function also if no packets are queued. + * The routine must be able to handle this case. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void llc_restart_tx(struct s_smc *smc) +{ + skfddi_priv *bp = (skfddi_priv *) & smc->os; + + PRINTK(KERN_INFO "[llc_restart_tx]\n"); + + // Try to send queued packets + spin_unlock(&bp->DriverLock); + send_queued_packets(smc); + spin_lock(&bp->DriverLock); + bp->dev->tbusy = 0; // system may send again if it was blocked + +} // llc_restart_tx + + +/************************ + * + * mac_drv_get_space + * + * The hardware module calls this function to allocate the memory + * for the SMT MBufs if the define MB_OUTSIDE_SMC is specified. + * Args + * smc - A pointer to the SMT context struct. + * + * size - Size of memory in bytes to allocate. + * Out + * != 0 A pointer to the virtual address of the allocated memory. + * == 0 Allocation error. + * + ************************/ +void *mac_drv_get_space(struct s_smc *smc, unsigned int size) +{ + void *virt; + + PRINTK(KERN_INFO "mac_drv_get_space\n"); + virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap); + + if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) { + printk("Unexpected SMT memory size requested: %d\n", size); + return (NULL); + } + smc->os.SharedMemHeap += size; // Move heap pointer. + + PRINTK(KERN_INFO "mac_drv_get_space end\n"); + PRINTK(KERN_INFO "virt addr: %lx\n", (ulong) virt); + PRINTK(KERN_INFO "bus addr: %lx\n", (ulong) virt_to_bus(virt)); + return (virt); +} // mac_drv_get_space + + +/************************ + * + * mac_drv_get_desc_mem + * + * This function is called by the hardware dependent module. + * It allocates the memory for the RxD and TxD descriptors. + * + * This memory must be non-cached, non-movable and non-swapable. + * This memory should start at a physical page boundary. + * Args + * smc - A pointer to the SMT context struct. + * + * size - Size of memory in bytes to allocate. + * Out + * != 0 A pointer to the virtual address of the allocated memory. + * == 0 Allocation error. + * + ************************/ +void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size) +{ + + char *virt; + + PRINTK(KERN_INFO "mac_drv_get_desc_mem\n"); + + // Descriptor memory must be aligned on 16-byte boundary. + + virt = mac_drv_get_space(smc, size); + + size = (u_int) ((0 - (unsigned long) virt) & 15); + + PRINTK("Allocate %u bytes alignment gap ", size); + PRINTK("for descriptor memory.\n"); + + if (!mac_drv_get_space(smc, size)) { + printk("fddi: Unable to align descriptor memory.\n"); + return (NULL); + } + return (virt + size); +} // mac_drv_get_desc_mem + + +/************************ + * + * mac_drv_virt2phys + * + * Get the physical address of a given virtual address. + * Args + * smc - A pointer to the SMT context struct. + * + * virt - A (virtual) pointer into our 'shared' memory area. + * Out + * Physical address of the given virtual address. + * + ************************/ +unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt) +{ + return virt_to_bus(virt); +} // mac_drv_virt2phys + + +/************************ + * + * dma_master + * + * The HWM calls this function, when the driver leads through a DMA + * transfer. If the OS-specific module must prepare the system hardware + * for the DMA transfer, it should do it in this function. + * + * The hardware module calls this dma_master if it wants to send an SMT + * frame. This means that the virt address passed in here is part of + * the 'shared' memory area. + * Args + * smc - A pointer to the SMT context struct. + * + * virt - The virtual address of the data. + * + * len - The length in bytes of the data. + * + * flag - Indicates the transmit direction and the buffer type: + * DMA_RD (0x01) system RAM ==> adapter buffer memory + * DMA_WR (0x02) adapter buffer memory ==> system RAM + * SMT_BUF (0x80) SMT buffer + * + * >> NOTE: SMT_BUF and DMA_RD are always set for PCI. << + * Out + * Returns the pyhsical address for the DMA transfer. + * + ************************/ +u_long dma_master(struct s_smc * smc, void *virt, int len, int flag) +{ + return (virt_to_bus(virt)); +} // dma_master + + +/************************ + * + * dma_complete + * + * The hardware module calls this routine when it has completed a DMA + * transfer. If the operating system dependant module has set up the DMA + * channel via dma_master() (e.g. Windows NT or AIX) it should clean up + * the DMA channel. + * Args + * smc - A pointer to the SMT context struct. + * + * descr - A pointer to a TxD or RxD, respectively. + * + * flag - Indicates the DMA transfer direction / SMT buffer: + * DMA_RD (0x01) system RAM ==> adapter buffer memory + * DMA_WR (0x02) adapter buffer memory ==> system RAM + * SMT_BUF (0x80) SMT buffer (managed by HWM) + * Out + * Nothing. + * + ************************/ +void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag) +{ + return; +} // dma_complete + + +/************************ + * + * mac_drv_tx_complete + * + * Transmit of a packet is complete. Release the tx staging buffer. + * + * Args + * smc - A pointer to the SMT context struct. + * + * txd - A pointer to the last TxD which is used by the frame. + * Out + * Returns nothing. + * + ************************/ +void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) +{ + struct sk_buff *skb; + + PRINTK(KERN_INFO "entering mac_drv_tx_complete\n"); + // Check if this TxD points to a skb + + if (!(skb = txd->txd_os.skb)) { + PRINTK("TXD with no skb assigned.\n"); + return; + } + txd->txd_os.skb = NULL; + + smc->os.MacStat.tx_packets++; // Count transmitted packets. + smc->os.MacStat.tx_bytes+=skb->len; // Count bytes + + // free the skb + dev_kfree_skb(skb); + + PRINTK(KERN_INFO "leaving mac_drv_tx_complete\n"); +} // mac_drv_tx_complete + + +/************************ + * + * dump packets to logfile + * + ************************/ +#ifdef DUMPPACKETS +void dump_data(unsigned char *Data, int length) +{ + int i, j; + unsigned char s[255], sh[10]; + if (length > 64) { + length = 64; + } + printk(KERN_INFO "---Packet start---\n"); + for (i = 0, j = 0; i < length / 8; i++, j += 8) + printk(KERN_INFO "%02x %02x %02x %02x %02x %02x %02x %02x\n", + Data[j + 0], Data[j + 1], Data[j + 2], Data[j + 3], + Data[j + 4], Data[j + 5], Data[j + 6], Data[j + 7]); + strcpy(s, ""); + for (i = 0; i < length % 8; i++) { + sprintf(sh, "%02x ", Data[j + i]); + strcat(s, sh); + } + printk(KERN_INFO "%s\n", s); + printk(KERN_INFO "------------------\n"); +} // dump_data +#else +#define dump_data(data,len) +#endif // DUMPPACKETS + +/************************ + * + * mac_drv_rx_complete + * + * The hardware module calls this function if an LLC frame is received + * in a receive buffer. Also the SMT, NSA, and directed beacon frames + * from the network will be passed to the LLC layer by this function + * if passing is enabled. + * + * mac_drv_rx_complete forwards the frame to the LLC layer if it should + * be received. It also fills the RxD ring with new receive buffers if + * some can be queued. + * Args + * smc - A pointer to the SMT context struct. + * + * rxd - A pointer to the first RxD which is used by the receive frame. + * + * frag_count - Count of RxDs used by the received frame. + * + * len - Frame length. + * Out + * Nothing. + * + ************************/ +void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count, int len) +{ + skfddi_priv *bp = (skfddi_priv *) & smc->os; + struct sk_buff *skb; + unsigned char *virt, *cp; + unsigned short ri; + u_int RifLength; + + PRINTK(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len); + if (frag_count != 1) { // This is not allowed to happen. + + printk("fddi: ERROR: Multi-fragment receive!\n"); + goto RequeueRxd; // Re-use the given RXD(s). + + } + skb = rxd->rxd_os.skb; + if (!skb) { + PRINTK(KERN_INFO "No skb in rxd\n"); + smc->os.MacStat.rx_errors++; + goto RequeueRxd; + } + virt = skb->data; + + dump_data(skb->data, len); + + /* + * FDDI Frame format: + * +-------+-------+-------+------------+--------+------------+ + * | FC[1] | DA[6] | SA[6] | RIF[0..18] | LLC[3] | Data[0..n] | + * +-------+-------+-------+------------+--------+------------+ + * + * FC = Frame Control + * DA = Destination Address + * SA = Source Address + * RIF = Routing Information Field + * LLC = Logical Link Control + */ + + // Remove Routing Information Field (RIF), if present. + + if ((virt[1 + 6] & FDDI_RII) == 0) + RifLength = 0; + else { + int n; +// goos: RIF removal has still to be tested + PRINTK(KERN_INFO "RIF found\n"); + // Get RIF length from Routing Control (RC) field. + cp = virt + FDDI_MAC_HDR_LEN; // Point behind MAC header. + + ri = ntohs(*((unsigned short *) cp)); + RifLength = ri & FDDI_RCF_LEN_MASK; + if (len < (int) (FDDI_MAC_HDR_LEN + RifLength)) { + printk("fddi: Invalid RIF.\n"); + goto RequeueRxd; // Discard the frame. + + } + virt[1 + 6] &= ~FDDI_RII; // Clear RII bit. + // regions overlap + + virt = cp + RifLength; + for (n = FDDI_MAC_HDR_LEN; n; n--) + *--virt = *--cp; + // adjust sbd->data pointer + skb_pull(skb, RifLength); + len -= RifLength; + RifLength = 0; + } + + // Count statistics. + smc->os.MacStat.rx_packets++; // Count indicated receive packets. + smc->os.MacStat.rx_bytes+=len; // Count bytes + + // virt points to header again + if (virt[1] & 0x01) { // Check group (multicast) bit. + + smc->os.MacStat.multicast++; + } + + // deliver frame to system + rxd->rxd_os.skb = NULL; + skb_trim(skb, len); + skb->protocol = fddi_type_trans(skb, bp->dev); + skb->dev = bp->dev; /* pass up device pointer */ + + netif_rx(skb); + + HWM_RX_CHECK(smc, RX_LOW_WATERMARK); + return; + + RequeueRxd: + PRINTK(KERN_INFO "Rx: re-queue RXD.\n"); + mac_drv_requeue_rxd(smc, rxd, frag_count); + smc->os.MacStat.rx_errors++; // Count receive packets not indicated. + +} // mac_drv_rx_complete + + +/************************ + * + * mac_drv_requeue_rxd + * + * The hardware module calls this function to request the OS-specific + * module to queue the receive buffer(s) represented by the pointer + * to the RxD and the frag_count into the receive queue again. This + * buffer was filled with an invalid frame or an SMT frame. + * Args + * smc - A pointer to the SMT context struct. + * + * rxd - A pointer to the first RxD which is used by the receive frame. + * + * frag_count - Count of RxDs used by the received frame. + * Out + * Nothing. + * + ************************/ +void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count) +{ + volatile struct s_smt_fp_rxd *next_rxd; + volatile struct s_smt_fp_rxd *src_rxd; + struct sk_buff *skb; + int MaxFrameSize; + unsigned char *v_addr; + unsigned long b_addr; + + if (frag_count != 1) // This is not allowed to happen. + + printk("fddi: Multi-fragment requeue!\n"); + + MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize; + src_rxd = rxd; + for (; frag_count > 0; frag_count--) { + next_rxd = src_rxd->rxd_next; + rxd = HWM_GET_CURR_RXD(smc); + + skb = src_rxd->rxd_os.skb; + if (skb == NULL) { // this should not happen + + PRINTK("Requeue with no skb in rxd!\n"); + skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); + if (skb) { + // we got a skb + rxd->rxd_os.skb = skb; + skb_reserve(skb, 3); + skb_put(skb, MaxFrameSize); + v_addr = skb->data; + b_addr = virt_to_bus(v_addr); + } else { + // no skb available, use local buffer + PRINTK("Queueing invalid buffer!\n"); + rxd->rxd_os.skb = NULL; + v_addr = smc->os.LocalRxBuffer; + b_addr = virt_to_bus(v_addr); + } + } else { + // we use skb from old rxd + rxd->rxd_os.skb = skb; + v_addr = skb->data; + b_addr = virt_to_bus(v_addr); + } + hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, + FIRST_FRAG | LAST_FRAG); + + src_rxd = next_rxd; + } +} // mac_drv_requeue_rxd + + +/************************ + * + * mac_drv_fill_rxd + * + * The hardware module calls this function at initialization time + * to fill the RxD ring with receive buffers. It is also called by + * mac_drv_rx_complete if rx_free is large enough to queue some new + * receive buffers into the RxD ring. mac_drv_fill_rxd queues new + * receive buffers as long as enough RxDs and receive buffers are + * available. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void mac_drv_fill_rxd(struct s_smc *smc) +{ + int MaxFrameSize; + unsigned char *v_addr; + unsigned long b_addr; + struct sk_buff *skb; + volatile struct s_smt_fp_rxd *rxd; + + PRINTK(KERN_INFO "entering mac_drv_fill_rxd\n"); + + // Walk through the list of free receive buffers, passing receive + // buffers to the HWM as long as RXDs are available. + + MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize; + // Check if there is any RXD left. + while (HWM_GET_RX_FREE(smc) > 0) { + PRINTK(KERN_INFO ".\n"); + + rxd = HWM_GET_CURR_RXD(smc); + skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); + if (skb) { + // we got a skb + skb_reserve(skb, 3); + skb_put(skb, MaxFrameSize); + v_addr = skb->data; + b_addr = virt_to_bus(v_addr); + } else { + // no skb available, use local buffer + // System has run out of buffer memory, but we want to + // keep the receiver running in hope of better times. + // Multiple descriptors may point to this local buffer, + // so data in it must be considered invalid. + PRINTK("Queueing invalid buffer!\n"); + v_addr = smc->os.LocalRxBuffer; + b_addr = virt_to_bus(v_addr); + } + + rxd->rxd_os.skb = skb; + + // Pass receive buffer to HWM. + hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, + FIRST_FRAG | LAST_FRAG); + } + PRINTK(KERN_INFO "leaving mac_drv_fill_rxd\n"); +} // mac_drv_fill_rxd + + +/************************ + * + * mac_drv_clear_rxd + * + * The hardware module calls this function to release unused + * receive buffers. + * Args + * smc - A pointer to the SMT context struct. + * + * rxd - A pointer to the first RxD which is used by the receive buffer. + * + * frag_count - Count of RxDs used by the receive buffer. + * Out + * Nothing. + * + ************************/ +void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count) +{ + + struct sk_buff *skb; + + PRINTK("entering mac_drv_clear_rxd\n"); + + if (frag_count != 1) // This is not allowed to happen. + + printk("fddi: Multi-fragment clear!\n"); + + for (; frag_count > 0; frag_count--) { + skb = rxd->rxd_os.skb; + if (skb != NULL) { + dev_kfree_skb(skb); + rxd->rxd_os.skb = NULL; + } + rxd = rxd->rxd_next; // Next RXD. + + } +} // mac_drv_clear_rxd + + +/************************ + * + * mac_drv_rx_init + * + * The hardware module calls this routine when an SMT or NSA frame of the + * local SMT should be delivered to the LLC layer. + * + * It is necessary to have this function, because there is no other way to + * copy the contents of SMT MBufs into receive buffers. + * + * mac_drv_rx_init allocates the required target memory for this frame, + * and receives the frame fragment by fragment by calling mac_drv_rx_frag. + * Args + * smc - A pointer to the SMT context struct. + * + * len - The length (in bytes) of the received frame (FC, DA, SA, Data). + * + * fc - The Frame Control field of the received frame. + * + * look_ahead - A pointer to the lookahead data buffer (may be NULL). + * + * la_len - The length of the lookahead data stored in the lookahead + * buffer (may be zero). + * Out + * Always returns zero (0). + * + ************************/ +int mac_drv_rx_init(struct s_smc *smc, int len, int fc, + char *look_ahead, int la_len) +{ + struct sk_buff *skb; + + PRINTK("entering mac_drv_rx_init(len=%d)\n", len); + + // "Received" a SMT or NSA frame of the local SMT. + + if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) { + PRINTK("fddi: Discard invalid local SMT frame\n"); + PRINTK(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n", + len, la_len, (unsigned long) look_ahead); + return (0); + } + skb = alloc_skb(len + 3, GFP_ATOMIC); + if (!skb) { + PRINTK("fddi: Local SMT: skb memory exhausted.\n"); + return (0); + } + skb_reserve(skb, 3); + skb_put(skb, len); + memcpy(skb->data, look_ahead, len); + + // deliver frame to system + skb->protocol = fddi_type_trans(skb, ((skfddi_priv *) & smc->os)->dev); + netif_rx(skb); + + return (0); +} // mac_drv_rx_init + + +/************************ + * + * smt_timer_poll + * + * This routine is called periodically by the SMT module to clean up the + * driver. + * + * Return any queued frames back to the upper protocol layers if the ring + * is down. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void smt_timer_poll(struct s_smc *smc) +{ +} // smt_timer_poll + + +/************************ + * + * ring_status_indication + * + * This function indicates a change of the ring state. + * Args + * smc - A pointer to the SMT context struct. + * + * status - The current ring status. + * Out + * Nothing. + * + ************************/ +void ring_status_indication(struct s_smc *smc, u_long status) +{ + PRINTK("ring_status_indication( "); + if (status & RS_RES15) + PRINTK("RS_RES15 "); + if (status & RS_HARDERROR) + PRINTK("RS_HARDERROR "); + if (status & RS_SOFTERROR) + PRINTK("RS_SOFTERROR "); + if (status & RS_BEACON) + PRINTK("RS_BEACON "); + if (status & RS_PATHTEST) + PRINTK("RS_PATHTEST "); + if (status & RS_SELFTEST) + PRINTK("RS_SELFTEST "); + if (status & RS_RES9) + PRINTK("RS_RES9 "); + if (status & RS_DISCONNECT) + PRINTK("RS_DISCONNECT "); + if (status & RS_RES7) + PRINTK("RS_RES7 "); + if (status & RS_DUPADDR) + PRINTK("RS_DUPADDR "); + if (status & RS_NORINGOP) + PRINTK("RS_NORINGOP "); + if (status & RS_VERSION) + PRINTK("RS_VERSION "); + if (status & RS_STUCKBYPASSS) + PRINTK("RS_STUCKBYPASSS "); + if (status & RS_EVENT) + PRINTK("RS_EVENT "); + if (status & RS_RINGOPCHANGE) + PRINTK("RS_RINGOPCHANGE "); + if (status & RS_RES0) + PRINTK("RS_RES0 "); + PRINTK("]\n"); +} // ring_status_indication + + +/************************ + * + * smt_get_time + * + * Gets the current time from the system. + * Args + * None. + * Out + * The current time in TICKS_PER_SECOND. + * + * TICKS_PER_SECOND has the unit 'count of timer ticks per second'. It is + * defined in "targetos.h". The definition of TICKS_PER_SECOND must comply + * to the time returned by smt_get_time(). + * + ************************/ +unsigned long smt_get_time(void) +{ + return jiffies; +} // smt_get_time + + +/************************ + * + * smt_stat_counter + * + * Status counter update (ring_op, fifo full). + * Args + * smc - A pointer to the SMT context struct. + * + * stat - = 0: A ring operational change occurred. + * = 1: The FORMAC FIFO buffer is full / FIFO overflow. + * Out + * Nothing. + * + ************************/ +void smt_stat_counter(struct s_smc *smc, int stat) +{ +// BOOLEAN RingIsUp ; + + PRINTK(KERN_INFO "smt_stat_counter\n"); + switch (stat) { + case 0: + PRINTK(KERN_INFO "Ring operational change.\n"); + break; + case 1: + PRINTK(KERN_INFO "Receive fifo overflow.\n"); + smc->os.MacStat.rx_errors++; + break; + default: + PRINTK(KERN_INFO "Unknown status (%d).\n", stat); + break; + } +} // smt_stat_counter + + +/************************ + * + * cfm_state_change + * + * Sets CFM state in custom statistics. + * Args + * smc - A pointer to the SMT context struct. + * + * c_state - Possible values are: + * + * EC0_OUT, EC1_IN, EC2_TRACE, EC3_LEAVE, EC4_PATH_TEST, + * EC5_INSERT, EC6_CHECK, EC7_DEINSERT + * Out + * Nothing. + * + ************************/ +void cfm_state_change(struct s_smc *smc, int c_state) +{ +#ifdef DRIVERDEBUG + char *s; + + switch (c_state) { + case SC0_ISOLATED: + s = "SC0_ISOLATED"; + break; + case SC1_WRAP_A: + s = "SC1_WRAP_A"; + break; + case SC2_WRAP_B: + s = "SC2_WRAP_B"; + break; + case SC4_THRU_A: + s = "SC4_THRU_A"; + break; + case SC5_THRU_B: + s = "SC5_THRU_B"; + break; + case SC7_WRAP_S: + s = "SC7_WRAP_S"; + break; + case SC9_C_WRAP_A: + s = "SC9_C_WRAP_A"; + break; + case SC10_C_WRAP_B: + s = "SC10_C_WRAP_B"; + break; + case SC11_C_WRAP_S: + s = "SC11_C_WRAP_S"; + break; + default: + PRINTK(KERN_INFO "cfm_state_change: unknown %d\n", c_state); + return; + } + PRINTK(KERN_INFO "cfm_state_change: %s\n", s); +#endif // DRIVERDEBUG +} // cfm_state_change + + +/************************ + * + * ecm_state_change + * + * Sets ECM state in custom statistics. + * Args + * smc - A pointer to the SMT context struct. + * + * e_state - Possible values are: + * + * SC0_ISOLATED, SC1_WRAP_A (5), SC2_WRAP_B (6), SC4_THRU_A (12), + * SC5_THRU_B (7), SC7_WRAP_S (8) + * Out + * Nothing. + * + ************************/ +void ecm_state_change(struct s_smc *smc, int e_state) +{ +#ifdef DRIVERDEBUG + char *s; + + switch (e_state) { + case EC0_OUT: + s = "EC0_OUT"; + break; + case EC1_IN: + s = "EC1_IN"; + break; + case EC2_TRACE: + s = "EC2_TRACE"; + break; + case EC3_LEAVE: + s = "EC3_LEAVE"; + break; + case EC4_PATH_TEST: + s = "EC4_PATH_TEST"; + break; + case EC5_INSERT: + s = "EC5_INSERT"; + break; + case EC6_CHECK: + s = "EC6_CHECK"; + break; + case EC7_DEINSERT: + s = "EC7_DEINSERT"; + break; + default: + s = "unknown"; + break; + } + PRINTK(KERN_INFO "ecm_state_change: %s\n", s); +#endif //DRIVERDEBUG +} // ecm_state_change + + +/************************ + * + * rmt_state_change + * + * Sets RMT state in custom statistics. + * Args + * smc - A pointer to the SMT context struct. + * + * r_state - Possible values are: + * + * RM0_ISOLATED, RM1_NON_OP, RM2_RING_OP, RM3_DETECT, + * RM4_NON_OP_DUP, RM5_RING_OP_DUP, RM6_DIRECTED, RM7_TRACE + * Out + * Nothing. + * + ************************/ +void rmt_state_change(struct s_smc *smc, int r_state) +{ +#ifdef DRIVERDEBUG + char *s; + + switch (r_state) { + case RM0_ISOLATED: + s = "RM0_ISOLATED"; + break; + case RM1_NON_OP: + s = "RM1_NON_OP - not operational"; + break; + case RM2_RING_OP: + s = "RM2_RING_OP - ring operational"; + break; + case RM3_DETECT: + s = "RM3_DETECT - detect dupl addresses"; + break; + case RM4_NON_OP_DUP: + s = "RM4_NON_OP_DUP - dupl. addr detected"; + break; + case RM5_RING_OP_DUP: + s = "RM5_RING_OP_DUP - ring oper. with dupl. addr"; + break; + case RM6_DIRECTED: + s = "RM6_DIRECTED - sending directed beacons"; + break; + case RM7_TRACE: + s = "RM7_TRACE - trace initiated"; + break; + default: + s = "unknown"; + break; + } + PRINTK(KERN_INFO "[rmt_state_change: %s]\n", s); +#endif // DRIVERDEBUG +} // rmt_state_change + + +/************************ + * + * drv_reset_indication + * + * This function is called by the SMT when it has detected a severe + * hardware problem. The driver should perform a reset on the adapter + * as soon as possible, but not from within this function. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void drv_reset_indication(struct s_smc *smc) +{ + PRINTK(KERN_INFO "entering drv_reset_indication\n"); + + smc->os.ResetRequested = TRUE; // Set flag. + +} // drv_reset_indication + + + +//--------------- functions for use as a module ---------------- + +#ifdef MODULE +/************************ + * + * Note now that module autoprobing is allowed under PCI. The + * IRQ lines will not be auto-detected; instead I'll rely on the BIOSes + * to "do the right thing". + * + ************************/ +#define LP(a) ((struct s_smc*)(a)) +static struct device *mdev = NULL; + +/************************ + * + * init_module + * + * If compiled as a module, find + * adapters and initialize them. + * + ************************/ +int init_module(void) +{ + struct device *p; + + PRINTK(KERN_INFO "FDDI init module\n"); + if ((mdev = insert_device(NULL, skfp_probe)) == NULL) + return -ENOMEM; + + for (p = mdev; p != NULL; p = LP(p->priv)->os.next_module) { + PRINTK(KERN_INFO "device to register: %s\n", p->name); + if (register_netdev(p) != 0) { + printk("skfddi init_module failed\n"); + return -EIO; + } + } + + PRINTK(KERN_INFO "+++++ exit with success +++++\n"); + return 0; +} // init_module + +/************************ + * + * cleanup_module + * + * Release all resources claimed by this module. + * + ************************/ +void cleanup_module(void) +{ + PRINTK(KERN_INFO "cleanup_module\n"); + while (mdev != NULL) { + mdev = unlink_modules(mdev); + } + return; +} // cleanup_module + + +/************************ + * + * unlink_modules + * + * Unregister devices and release their memory. + * + ************************/ +static struct device *unlink_modules(struct device *p) +{ + struct device *next = NULL; + + if (p->priv) { /* Private areas allocated? */ + struct s_smc *lp = (struct s_smc *) p->priv; + + next = lp->os.next_module; + + if (lp->os.SharedMemAddr) { + kfree(lp->os.SharedMemAddr); + } + release_region(p->base_addr, + (lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0)); + } + unregister_netdev(p); + printk("%s: unloaded\n", p->name); + kfree(p); /* Free the device structure */ + + return next; +} // unlink_modules + + +#endif /* MODULE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/smt.c linux/drivers/net/skfp/smt.c --- v2.2.17/drivers/net/skfp/smt.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/smt.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,2225 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ; +#endif + +extern const u_char canonical[256] ; + +/* + * FC in SMbuf + */ +#define m_fc(mb) ((mb)->sm_data[0]) + +#define SMT_TID_MAGIC 0x1f0a7b3c + +#ifdef DEBUG +static const char *const smt_type_name[] = { + "SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??", + "SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??", + "SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??", + "SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA" +} ; + +static const char *const smt_class_name[] = { + "UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF", + "SRF","PMF_GET","PMF_SET","ESF" +} ; +#endif +#define LAST_CLASS (SMT_PMF_SET) + +static const struct fddi_addr SMT_Unknown = { + { 0,0,0x1f,0,0,0 } +} ; + +/* + * external variables + */ +extern const struct fddi_addr fddi_broadcast ; + +/* + * external functions + */ +int pcm_status_twisted() ; +void pcm_status_state() ; +int pcm_status_type() ; + +extern SMbuf *smt_get_mbuf() ; + +#define EXPORT_PMF +/* + * function prototypes + */ +u_long smt_get_tid() ; +EXPORT_PMF SMbuf *smt_build_frame() ; +EXPORT_PMF void *sm_to_para() ; +#ifdef LITTLE_ENDIAN +static int smt_swap_short() ; +#endif +static int mac_index() ; +static int phy_index() ; +static int mac_con_resource_index() ; +static int phy_con_resource_index() ; +EXPORT_PMF void smt_send_frame() ; +EXPORT_PMF void smt_set_timestamp() ; +static void smt_send_rdf() ; +static void smt_send_nif() ; +static void smt_send_ecf() ; +static void smt_echo_test() ; +static void smt_send_sif_config() ; +static void smt_send_sif_operation() ; +EXPORT_PMF void smt_swap_para() ; +#ifdef LITTLE_ENDIAN +static void smt_string_swap() ; +#endif +static void smt_add_frame_len() ; +static void smt_fill_una() ; +static void smt_fill_sde() ; +static void smt_fill_state() ; +static void smt_fill_timestamp() ; +static void smt_fill_policy() ; +static void smt_fill_latency() ; +static void smt_fill_neighbor() ; +static int smt_fill_path() ; +static void smt_fill_mac_status() ; +static void smt_fill_lem() ; +static void smt_fill_version() ; +static void smt_fill_fsc() ; +static void smt_fill_mac_counter() ; +static void smt_fill_mac_fnc() ; +static void smt_fill_manufacturer() ; +static void smt_fill_user() ; +static void smt_fill_setcount() ; +static void smt_fill_echo() ; +int smt_check_para() ; + +void smt_clear_una_dna() ; +static void smt_clear_old_una_dna() ; +#ifdef CONCENTRATOR +static int entity_to_index() ; +#endif +static void update_dac() ; +static int div_ratio() ; +#ifdef USE_CAN_ADDR +void hwm_conv_can() ; +#else +#define hwm_conv_can(smc,data,len) +#endif + +/* + * list of mandatory paras in frames + */ +static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ; + +/* + * init SMT agent + */ +void smt_agent_init(smc) +struct s_smc *smc ; +{ + int i ; + + /* + * get MAC address + */ + smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ; + + /* + * get OUI address from driver (bia == built-in-address) + */ + smc->mib.fddiSMTStationId.sid_oem[0] = 0 ; + smc->mib.fddiSMTStationId.sid_oem[1] = 0 ; + driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ; + for (i = 0 ; i < 6 ; i ++) { + smc->mib.fddiSMTStationId.sid_node.a[i] = + canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ; + } + smc->mib.fddiSMTManufacturerData[0] = + smc->mib.fddiSMTStationId.sid_node.a[0] ; + smc->mib.fddiSMTManufacturerData[1] = + smc->mib.fddiSMTStationId.sid_node.a[1] ; + smc->mib.fddiSMTManufacturerData[2] = + smc->mib.fddiSMTStationId.sid_node.a[2] ; + smc->sm.smt_tid = 0 ; + smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ; + smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; +#ifndef SLIM_SMT + smt_clear_una_dna(smc) ; + smt_clear_old_una_dna(smc) ; +#endif + for (i = 0 ; i < SMT_MAX_TEST ; i++) + smc->sm.pend[i] = 0 ; + smc->sm.please_reconnect = 0 ; + smc->sm.uniq_ticks = 0 ; +} + +/* + * SMT task + * forever + * delay 30 seconds + * send NIF + * check tvu & tvd + * end + */ +void smt_agent_task(smc) +struct s_smc *smc ; +{ + smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, + EV_TOKEN(EVENT_SMT,SM_TIMER)) ; + DB_SMT("SMT agent task\n",0,0) ; +} + +void smt_please_reconnect(smc,reconn_time) +struct s_smc *smc ; /* Pointer to SMT context */ +int reconn_time ; /* Wait for reconnect time in seconds */ +{ + /* + * The please reconnect variable is used as a timer. + * It is decremented each time smt_event is called. + * This happens every second or when smt_force_irq is called. + * Note: smt_force_irq () is called on some packet receives and + * when a multicast address is changed. Since nothing + * is received during the disconnect and the multicast + * address changes can be viewed as not very often and + * the timer runs out close to its given value + * (reconn_time). + */ + smc->sm.please_reconnect = reconn_time ; +} + +#ifndef SMT_REAL_TOKEN_CT +void smt_emulate_token_ct(smc, mac_index) +struct s_smc *smc; +int mac_index; +{ + u_long count; + u_long time; + + + time = smt_get_time(); + count = ((time - smc->sm.last_tok_time[mac_index]) * + 100)/TICKS_PER_SECOND; + + /* + * Only when ring is up we will have a token count. The + * flag is unfortunatly a single instance value. This + * doesn't matter now, because we currently have only + * one MAC instance. + */ + if (smc->hw.mac_ring_is_up){ + smc->mib.m[mac_index].fddiMACToken_Ct += count; + } + + /* Remember current time */ + smc->sm.last_tok_time[mac_index] = time; + +} +#endif + +/*ARGSUSED1*/ +void smt_event(smc,event) +struct s_smc *smc ; +int event ; +{ + u_long time ; +#ifndef SMT_REAL_TOKEN_CT + int i ; +#endif + + + if (smc->sm.please_reconnect) { + smc->sm.please_reconnect -- ; + if (smc->sm.please_reconnect == 0) { + /* Counted down */ + queue_event(smc,EVENT_ECM,EC_CONNECT) ; + } + } + + if (event == SM_FAST) + return ; + + /* + * timer for periodic cleanup in driver + * reset and start the watchdog (FM2) + * ESS timer + * SBA timer + */ + smt_timer_poll(smc) ; + smt_start_watchdog(smc) ; +#ifndef SLIM_SMT +#ifndef BOOT +#ifdef ESS + ess_timer_poll(smc) ; +#endif +#endif +#ifdef SBA + sba_timer_poll(smc) ; +#endif + + smt_srf_event(smc,0,0,0) ; + +#endif /* no SLIM_SMT */ + + time = smt_get_time() ; + + if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) { + /* + * Use 8 sec. for the time intervall, it simplifies the + * LER estimation. + */ + struct fddi_mib_m *mib ; + u_long upper ; + u_long lower ; + int cond ; + int port; + struct s_phy *phy ; + /* + * calculate LEM bit error rate + */ + sm_lem_evaluate(smc) ; + smc->sm.smt_last_lem = time ; + + /* + * check conditions + */ +#ifndef SLIM_SMT + mac_update_counter(smc) ; + mib = smc->mib.m ; + upper = + (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) + + (mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ; + lower = + (mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) + + (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ; + mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ; + + cond = + ((!mib->fddiMACFrameErrorThreshold && + mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) || + (mib->fddiMACFrameErrorRatio > + mib->fddiMACFrameErrorThreshold)) ; + + if (cond != mib->fddiMACFrameErrorFlag) + smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR, + INDEX_MAC,cond) ; + + upper = + (mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ; + lower = + upper + + (mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ; + mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ; + + cond = + ((!mib->fddiMACNotCopiedThreshold && + mib->fddiMACNotCopied_Ct != + mib->fddiMACOld_NotCopied_Ct)|| + (mib->fddiMACNotCopiedRatio > + mib->fddiMACNotCopiedThreshold)) ; + + if (cond != mib->fddiMACNotCopiedFlag) + smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED, + INDEX_MAC,cond) ; + + /* + * set old values + */ + mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ; + mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ; + mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ; + mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ; + mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ; + + /* + * Check port EBError Condition + */ + for (port = 0; port < NUMPHYS; port ++) { + phy = &smc->y[port] ; + + if (!phy->mib->fddiPORTHardwarePresent) { + continue; + } + + cond = (phy->mib->fddiPORTEBError_Ct - + phy->mib->fddiPORTOldEBError_Ct > 5) ; + + /* If ratio is more than 5 in 8 seconds + * Set the condition. + */ + smt_srf_event(smc,SMT_COND_PORT_EB_ERROR, + (int) (INDEX_PORT+ phy->np) ,cond) ; + + /* + * set old values + */ + phy->mib->fddiPORTOldEBError_Ct = + phy->mib->fddiPORTEBError_Ct ; + } + +#endif /* no SLIM_SMT */ + } + +#ifndef SLIM_SMT + + if (time - smc->sm.smt_last_notify >= (u_long) + (smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) { + /* + * we can either send an announcement or a request + * a request will trigger a reply so that we can update + * our dna + * note: same tid must be used until reply is received + */ + if (!smc->sm.pend[SMT_TID_NIF]) + smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ; + smt_send_nif(smc,&fddi_broadcast,FC_SMT_NSA, + smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ; + smc->sm.smt_last_notify = time ; + } + + /* + * check timer + */ + if (smc->sm.smt_tvu && + time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) { + DB_SMT("SMT : UNA expired\n",0,0) ; + smc->sm.smt_tvu = 0 ; + + if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr, + &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr= + smc->mib.m[MAC0].fddiMACUpstreamNbr ; + } + smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; + /* + * Make sure the fddiMACUNDA_Flag = FALSE is + * included in the SRF so we don't generate + * a seperate SRF for the deassertion of this + * condition + */ + update_dac(smc,0) ; + smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + } + if (smc->sm.smt_tvd && + time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) { + DB_SMT("SMT : DNA expired\n",0,0) ; + smc->sm.smt_tvd = 0 ; + if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr, + &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldDownstreamNbr= + smc->mib.m[MAC0].fddiMACDownstreamNbr ; + } + smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; + smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + } + +#endif /* no SLIM_SMT */ + +#ifndef SMT_REAL_TOKEN_CT + /* + * Token counter emulation section. If hardware supports the token + * count, the token counter will be updated in mac_update_counter. + */ + for (i = MAC0; i < NUMMACS; i++ ){ + if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){ + smt_emulate_token_ct( smc, i ); + } + } +#endif + + smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, + EV_TOKEN(EVENT_SMT,SM_TIMER)) ; +} + +static int div_ratio(upper,lower) +u_long upper ; +u_long lower ; +{ + if ((upper<<16L) < upper) + upper = 0xffff0000L ; + else + upper <<= 16L ; + if (!lower) + return(0) ; + return((int)(upper/lower)) ; +} + +#ifndef SLIM_SMT + +/* + * receive packet handler + */ +void smt_received_pack(smc,mb,fs) +struct s_smc *smc ; +SMbuf *mb ; +int fs ; /* frame status */ +{ + struct smt_header *sm ; + int local ; + + int illegal = 0 ; + + switch (m_fc(mb)) { + case FC_SMT_INFO : + case FC_SMT_LAN_LOC : + case FC_SMT_LOC : + case FC_SMT_NSA : + break ; + default : + smt_free_mbuf(smc,mb) ; + return ; + } + + smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ; + sm = smtod(mb,struct smt_header *) ; + local = ((fs & L_INDICATOR) != 0) ; + hwm_conv_can(smc,(char *)sm,12) ; + + /* check destination address */ + if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) { + smt_free_mbuf(smc,mb) ; + return ; + } +#if 0 /* for DUP recognition, do NOT filter them */ + /* ignore loop back packets */ + if (is_my_addr(smc,&sm->smt_source) && !local) { + smt_free_mbuf(smc,mb) ; + return ; + } +#endif + + smt_swap_para(sm,(int) mb->sm_len,1) ; + DB_SMT("SMT : received packet [%s] at 0x%x\n", + smt_type_name[m_fc(mb) & 0xf],sm) ; + DB_SMT("SMT : version %d, class %s\n",sm->smt_version, + smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ; + +#ifdef SBA + /* + * check if NSA frame + */ + if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF && + (sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) { + smc->sba.sm = sm ; + sba(smc,NIF) ; + } +#endif + + /* + * ignore any packet with NSA and A-indicator set + */ + if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) { + DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_free_mbuf(smc,mb) ; + return ; + } + + /* + * ignore frames with illegal length + */ + if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) || + ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) { + smt_free_mbuf(smc,mb) ; + return ; + } + + /* + * check SMT version + */ + switch (sm->smt_class) { + case SMT_NIF : + case SMT_SIF_CONFIG : + case SMT_SIF_OPER : + case SMT_ECF : + if (sm->smt_version != SMT_VID) + illegal = 1; + break ; + default : + if (sm->smt_version != SMT_VID_2) + illegal = 1; + break ; + } + if (illegal) { + DB_SMT("SMT : version = %d, dest = %s\n", + sm->smt_version,addr_to_string(&sm->smt_source)) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ; + smt_free_mbuf(smc,mb) ; + return ; + } + if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) || + ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) { + DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ; + smt_free_mbuf(smc,mb) ; + return ; + } + switch (sm->smt_class) { + case SMT_NIF : + if (smt_check_para(smc,sm,plist_nif)) { + DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ; + break ; + } ; + switch (sm->smt_type) { + case SMT_ANNOUNCE : + case SMT_REQUEST : + if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA + && is_broadcast(&sm->smt_dest)) { + struct smt_p_state *st ; + + /* set my UNA */ + if (!is_equal( + &smc->mib.m[MAC0].fddiMACUpstreamNbr, + &sm->smt_source)) { + DB_SMT("SMT : updated my UNA = %s\n", + addr_to_string(&sm->smt_source),0) ; + if (!is_equal(&smc->mib.m[MAC0]. + fddiMACUpstreamNbr,&SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr= + smc->mib.m[MAC0].fddiMACUpstreamNbr ; + } + + smc->mib.m[MAC0].fddiMACUpstreamNbr = + sm->smt_source ; + smt_srf_event(smc, + SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + smt_echo_test(smc,0) ; + } + smc->sm.smt_tvu = smt_get_time() ; + st = (struct smt_p_state *) + sm_to_para(smc,sm,SMT_P_STATE) ; + if (st) { + smc->mib.m[MAC0].fddiMACUNDA_Flag = + (st->st_dupl_addr & SMT_ST_MY_DUPA) ? + TRUE : FALSE ; + update_dac(smc,1) ; + } + } + if ((sm->smt_type == SMT_REQUEST) && + is_individual(&sm->smt_source) && + ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) || + (m_fc(mb) != FC_SMT_NSA))) { + DB_SMT("SMT : replying to NIF request %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_nif(smc,&sm->smt_source, + FC_SMT_INFO, + sm->smt_tid, + SMT_REPLY,local) ; + } + break ; + case SMT_REPLY : + DB_SMT("SMT : received NIF response from %s\n", + addr_to_string(&sm->smt_source),0) ; + if (fs & A_INDICATOR) { + smc->sm.pend[SMT_TID_NIF] = 0 ; + DB_SMT("SMT : duplicate address\n",0,0) ; + smc->mib.m[MAC0].fddiMACDupAddressTest = + DA_FAILED ; + smc->r.dup_addr_test = DA_FAILED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ; + update_dac(smc,1) ; + break ; + } + if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) { + smc->sm.pend[SMT_TID_NIF] = 0 ; + /* set my DNA */ + if (!is_equal( + &smc->mib.m[MAC0].fddiMACDownstreamNbr, + &sm->smt_source)) { + DB_SMT("SMT : updated my DNA\n",0,0) ; + if (!is_equal(&smc->mib.m[MAC0]. + fddiMACDownstreamNbr, &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldDownstreamNbr = + smc->mib.m[MAC0].fddiMACDownstreamNbr ; + } + + smc->mib.m[MAC0].fddiMACDownstreamNbr = + sm->smt_source ; + smt_srf_event(smc, + SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + smt_echo_test(smc,1) ; + } + smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ; + update_dac(smc,1) ; + smc->sm.smt_tvd = smt_get_time() ; + smc->mib.m[MAC0].fddiMACDupAddressTest = + DA_PASSED ; + if (smc->r.dup_addr_test != DA_PASSED) { + smc->r.dup_addr_test = DA_PASSED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + } + } + else if (sm->smt_tid == + smc->sm.pend[SMT_TID_NIF_TEST]) { + DB_SMT("SMT : NIF test TID ok\n",0,0) ; + } + else { + DB_SMT("SMT : expected TID %lx, got %lx\n", + smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ; + } + break ; + default : + illegal = 2 ; + break ; + } + break ; + case SMT_SIF_CONFIG : /* station information */ + if (sm->smt_type != SMT_REQUEST) + break ; + DB_SMT("SMT : replying to SIF Config request from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ; + break ; + case SMT_SIF_OPER : /* station information */ + if (sm->smt_type != SMT_REQUEST) + break ; + DB_SMT("SMT : replying to SIF Operation request from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ; + break ; + case SMT_ECF : /* echo frame */ + switch (sm->smt_type) { + case SMT_REPLY : + smc->mib.priv.fddiPRIVECF_Reply_Rx++ ; + DB_SMT("SMT: received ECF reply from %s\n", + addr_to_string(&sm->smt_source),0) ; + if (sm_to_para(smc,sm,SMT_P_ECHODATA) == 0) { + DB_SMT("SMT: ECHODATA missing\n",0,0) ; + break ; + } + if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) { + DB_SMT("SMT : ECF test TID ok\n",0,0) ; + } + else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) { + DB_SMT("SMT : ECF test UNA ok\n",0,0) ; + } + else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) { + DB_SMT("SMT : ECF test DNA ok\n",0,0) ; + } + else { + DB_SMT("SMT : expected TID %lx, got %lx\n", + smc->sm.pend[SMT_TID_ECF], + sm->smt_tid) ; + } + break ; + case SMT_REQUEST : + smc->mib.priv.fddiPRIVECF_Req_Rx++ ; + { + if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) { + DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH, + local) ; + break ; + } + DB_SMT("SMT - sending ECF reply to %s\n", + addr_to_string(&sm->smt_source),0) ; + + /* set destination addr. & reply */ + sm->smt_dest = sm->smt_source ; + sm->smt_type = SMT_REPLY ; + dump_smt(smc,sm,"ECF REPLY") ; + smc->mib.priv.fddiPRIVECF_Reply_Tx++ ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; + return ; /* DON'T free mbuf */ + } + default : + illegal = 1 ; + break ; + } + break ; +#ifndef BOOT + case SMT_RAF : /* resource allocation */ +#ifdef ESS + DB_ESSN(2,"ESS: RAF frame received\n",0,0) ; + fs = ess_raf_received_pack(smc,mb,sm,fs) ; +#endif + +#ifdef SBA + DB_SBAN(2,"SBA: RAF frame received\n",0,0) ; + sba_raf_received_pack(smc,sm,fs) ; +#endif + break ; + case SMT_RDF : /* request denied */ + smc->mib.priv.fddiPRIVRDF_Rx++ ; + break ; + case SMT_ESF : /* extended service - not supported */ + if (sm->smt_type == SMT_REQUEST) { + DB_SMT("SMT - received ESF, sending RDF\n",0,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; + } + break ; + case SMT_PMF_GET : + case SMT_PMF_SET : + if (sm->smt_type != SMT_REQUEST) + break ; + /* update statistics */ + if (sm->smt_class == SMT_PMF_GET) + smc->mib.priv.fddiPRIVPMF_Get_Rx++ ; + else + smc->mib.priv.fddiPRIVPMF_Set_Rx++ ; + /* + * ignore PMF SET with I/G set + */ + if ((sm->smt_class == SMT_PMF_SET) && + !is_individual(&sm->smt_dest)) { + DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ; + break ; + } + smt_pmf_received_pack(smc,mb, local) ; + break ; + case SMT_SRF : + dump_smt(smc,sm,"SRF received") ; + break ; + default : + if (sm->smt_type != SMT_REQUEST) + break ; + /* + * For frames with unknown class: + * we need to send a RDF frame according to 8.1.3.1.1, + * only if it is a REQUEST. + */ + DB_SMT("SMT : class = %d, send RDF to %s\n", + sm->smt_class, addr_to_string(&sm->smt_source)) ; + + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; + break ; +#endif + } + if (illegal) { + DB_SMT("SMT: discarding illegal frame, reason = %d\n", + illegal,0) ; + } + smt_free_mbuf(smc,mb) ; +} + +static void update_dac(smc,report) +struct s_smc *smc ; +int report ; +{ + int cond ; + + cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag | + smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ; + if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond)) + smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ; + else + smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ; +} + +/* + * send SMT frame + * set source address + * set station ID + * send frame + */ +EXPORT_PMF void smt_send_frame(smc,mb,fc,local) +struct s_smc *smc ; +SMbuf *mb ; /* buffer to send */ +int fc ; /* FC value */ +int local ; +{ + struct smt_header *sm ; + + if (!smc->r.sm_ma_avail && !local) { + smt_free_mbuf(smc,mb) ; + return ; + } + sm = smtod(mb,struct smt_header *) ; + sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; + sm->smt_sid = smc->mib.fddiSMTStationId ; + + smt_swap_para(sm,(int) mb->sm_len,0) ; /* swap para & header */ + hwm_conv_can(smc,(char *)sm,12) ; /* convert SA and DA */ + smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ; + smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ; +} + +/* + * generate and send RDF + */ +static void smt_send_rdf(smc,rej,fc,reason,local) +struct s_smc *smc ; +SMbuf *rej ; /* mbuf of offending frame */ +int fc ; /* FC of denied frame */ +int reason ; /* reason code */ +int local ; +{ + SMbuf *mb ; + struct smt_header *sm ; /* header of offending frame */ + struct smt_rdf *rdf ; + int len ; + int frame_len ; + + sm = smtod(rej,struct smt_header *) ; + if (sm->smt_type != SMT_REQUEST) + return ; + + DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n", + addr_to_string(&sm->smt_source),reason) ; + + + /* + * note: get framelength from MAC length, NOT from SMT header + * smt header length is included in sm_len + */ + frame_len = rej->sm_len ; + + if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf)))) + return ; + rdf = smtod(mb,struct smt_rdf *) ; + rdf->smt.smt_tid = sm->smt_tid ; /* use TID from sm */ + rdf->smt.smt_dest = sm->smt_source ; /* set dest = source */ + + /* set P12 */ + rdf->reason.para.p_type = SMT_P_REASON ; + rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ; + rdf->reason.rdf_reason = reason ; + + /* set P14 */ + rdf->version.para.p_type = SMT_P_VERSION ; + rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ; + rdf->version.v_pad = 0 ; + rdf->version.v_n = 1 ; + rdf->version.v_index = 1 ; + rdf->version.v_version[0] = SMT_VID_2 ; + rdf->version.v_pad2 = 0 ; + + /* set P13 */ + if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) + + 2*sizeof(struct smt_header)) + len = frame_len ; + else + len = SMT_MAX_INFO_LEN - sizeof(*rdf) + + 2*sizeof(struct smt_header) ; + /* make length multiple of 4 */ + len &= ~3 ; + rdf->refused.para.p_type = SMT_P_REFUSED ; + /* length of para is smt_frame + ref_fc */ + rdf->refused.para.p_len = len + 4 ; + rdf->refused.ref_fc = fc ; + + /* swap it back */ + smt_swap_para(sm,frame_len,0) ; + + memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ; + + len -= sizeof(struct smt_header) ; + mb->sm_len += len ; + rdf->smt.smt_len += len ; + + dump_smt(smc,(struct smt_header *)rdf,"RDF") ; + smc->mib.priv.fddiPRIVRDF_Tx++ ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * generate and send NIF + */ +static void smt_send_nif(smc,dest,fc,tid,type,local) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +int fc ; /* frame control */ +u_long tid ; /* transaction id */ +int type ; /* frame type */ +int local ; +{ + struct smt_nif *nif ; + SMbuf *mb ; + + if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif)))) + return ; + nif = smtod(mb, struct smt_nif *) ; + smt_fill_una(smc,&nif->una) ; /* set UNA */ + smt_fill_sde(smc,&nif->sde) ; /* set station descriptor */ + smt_fill_state(smc,&nif->state) ; /* set state information */ +#ifdef SMT6_10 + smt_fill_fsc(smc,&nif->fsc) ; /* set frame status cap. */ +#endif + nif->smt.smt_dest = *dest ; /* destination address */ + nif->smt.smt_tid = tid ; /* transaction ID */ + dump_smt(smc,(struct smt_header *)nif,"NIF") ; + smt_send_frame(smc,mb,fc,local) ; +} + +#ifdef DEBUG +/* + * send NIF request (test purpose) + */ +static void smt_send_nif_request(smc,dest) +struct s_smc *smc ; +struct fddi_addr *dest ; +{ + smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ; + smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST], + SMT_REQUEST,0) ; +} + +/* + * send ECF request (test purpose) + */ +static void smt_send_ecf_request(smc,dest,len) +struct s_smc *smc ; +struct fddi_addr *dest ; +int len ; +{ + smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ; + smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF], + SMT_REQUEST,len) ; +} +#endif + +/* + * echo test + */ +static void smt_echo_test(smc,dna) +struct s_smc *smc ; +int dna ; +{ + u_long tid ; + + smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] = + tid = smt_get_tid(smc) ; + smt_send_ecf(smc, dna ? + &smc->mib.m[MAC0].fddiMACDownstreamNbr : + &smc->mib.m[MAC0].fddiMACUpstreamNbr, + FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ; +} + +/* + * generate and send ECF + */ +static void smt_send_ecf(smc,dest,fc,tid,type,len) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +int fc ; /* frame control */ +u_long tid ; /* transaction id */ +int type ; /* frame type */ +int len ; /* frame length */ +{ + struct smt_ecf *ecf ; + SMbuf *mb ; + + if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len))) + return ; + ecf = smtod(mb, struct smt_ecf *) ; + + smt_fill_echo(smc,&ecf->ec_echo,tid,len) ; /* set ECHO */ + ecf->smt.smt_dest = *dest ; /* destination address */ + ecf->smt.smt_tid = tid ; /* transaction ID */ + smc->mib.priv.fddiPRIVECF_Req_Tx++ ; + smt_send_frame(smc,mb,fc,0) ; +} + +/* + * generate and send SIF config response + */ + +static void smt_send_sif_config(smc,dest,tid,local) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +u_long tid ; /* transaction id */ +int local ; +{ + struct smt_sif_config *sif ; + SMbuf *mb ; + int len ; + if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY, + SIZEOF_SMT_SIF_CONFIG))) + return ; + + sif = smtod(mb, struct smt_sif_config *) ; + smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ + smt_fill_sde(smc,&sif->sde) ; /* set station descriptor */ + smt_fill_version(smc,&sif->version) ; /* set version information */ + smt_fill_state(smc,&sif->state) ; /* set state information */ + smt_fill_policy(smc,&sif->policy) ; /* set station policy */ + smt_fill_latency(smc,&sif->latency); /* set station latency */ + smt_fill_neighbor(smc,&sif->neighbor); /* set station neighbor */ + smt_fill_setcount(smc,&sif->setcount) ; /* set count */ + len = smt_fill_path(smc,&sif->path); /* set station path descriptor*/ + sif->smt.smt_dest = *dest ; /* destination address */ + sif->smt.smt_tid = tid ; /* transaction ID */ + smt_add_frame_len(mb,len) ; /* adjust length fields */ + dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * generate and send SIF operation response + */ + +static void smt_send_sif_operation(smc,dest,tid,local) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +u_long tid ; /* transaction id */ +int local ; +{ + struct smt_sif_operation *sif ; + SMbuf *mb ; + int ports ; + int i ; + + ports = NUMPHYS ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + ports = 1 ; +#endif + + if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY, + SIZEOF_SMT_SIF_OPERATION+ports*sizeof(struct smt_p_lem)))) + return ; + sif = smtod(mb, struct smt_sif_operation *) ; + smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ + smt_fill_mac_status(smc,&sif->status) ; /* set mac status */ + smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */ + smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */ + smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */ + smt_fill_user(smc,&sif->user) ; /* set user field */ + smt_fill_setcount(smc,&sif->setcount) ; /* set count */ + /* + * set link error mon information + */ + if (ports == 1) { + smt_fill_lem(smc,sif->lem,PS) ; + } + else { + for (i = 0 ; i < ports ; i++) { + smt_fill_lem(smc,&sif->lem[i],i) ; + } + } + + sif->smt.smt_dest = *dest ; /* destination address */ + sif->smt.smt_tid = tid ; /* transaction ID */ + dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * get and initialize SMT frame + */ +EXPORT_PMF SMbuf *smt_build_frame(smc,class,type,length) +struct s_smc *smc ; +int class ; +int type ; +int length ; +{ + SMbuf *mb ; + struct smt_header *smt ; + +#if 0 + if (!smc->r.sm_ma_avail) { + return(0) ; + } +#endif + if (!(mb = smt_get_mbuf(smc))) + return(mb) ; + + mb->sm_len = length ; + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */ + smt->smt_class = class ; + smt->smt_type = type ; + switch (class) { + case SMT_NIF : + case SMT_SIF_CONFIG : + case SMT_SIF_OPER : + case SMT_ECF : + smt->smt_version = SMT_VID ; + break ; + default : + smt->smt_version = SMT_VID_2 ; + break ; + } + smt->smt_tid = smt_get_tid(smc) ; /* set transaction ID */ + smt->smt_pad = 0 ; + smt->smt_len = length - sizeof(struct smt_header) ; + return(mb) ; +} + +static void smt_add_frame_len(mb,len) +SMbuf *mb ; +int len ; +{ + struct smt_header *smt ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_len += len ; + mb->sm_len += len ; +} + + + +/* + * fill values in UNA parameter + */ +static void smt_fill_una(smc,una) +struct s_smc *smc ; +struct smt_p_una *una ; +{ + SMTSETPARA(una,SMT_P_UNA) ; + una->una_pad = 0 ; + una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ; +} + +/* + * fill values in SDE parameter + */ +static void smt_fill_sde(smc,sde) +struct s_smc *smc ; +struct smt_p_sde *sde ; +{ + SMTSETPARA(sde,SMT_P_SDE) ; + sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ; + sde->sde_master = smc->mib.fddiSMTMaster_Ct ; + sde->sde_mac_count = NUMMACS ; /* only 1 MAC */ +#ifdef CONCENTRATOR + sde->sde_type = SMT_SDE_CONCENTRATOR ; +#else + sde->sde_type = SMT_SDE_STATION ; +#endif +} + +/* + * fill in values in station state parameter + */ +static void smt_fill_state(smc,state) +struct s_smc *smc ; +struct smt_p_state *state ; +{ + int top ; + int twist ; + + SMTSETPARA(state,SMT_P_STATE) ; + state->st_pad = 0 ; + + /* determine topology */ + top = 0 ; + if (smc->mib.fddiSMTPeerWrapFlag) { + top |= SMT_ST_WRAPPED ; /* state wrapped */ + } +#ifdef CONCENTRATOR + if (cfm_status_unattached(smc)) { + top |= SMT_ST_UNATTACHED ; /* unattached concentrator */ + } +#endif + if ((twist = pcm_status_twisted(smc)) & 1) { + top |= SMT_ST_TWISTED_A ; /* twisted cable */ + } + if (twist & 2) { + top |= SMT_ST_TWISTED_B ; /* twisted cable */ + } +#ifdef OPT_SRF + top |= SMT_ST_SRF ; +#endif + if (pcm_rooted_station(smc)) + top |= SMT_ST_ROOTED_S ; + if (smc->mib.a[0].fddiPATHSbaPayload != 0) + top |= SMT_ST_SYNC_SERVICE ; + state->st_topology = top ; + state->st_dupl_addr = + ((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) | + (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ; +} + +/* + * fill values in timestamp parameter + */ +static void smt_fill_timestamp(smc,ts) +struct s_smc *smc ; +struct smt_p_timestamp *ts ; +{ + + SMTSETPARA(ts,SMT_P_TIMESTAMP) ; + smt_set_timestamp(smc,ts->ts_time) ; +} + +EXPORT_PMF void smt_set_timestamp(smc,p) +struct s_smc *smc ; +u_char *p ; +{ + u_long time ; + u_long utime ; + + /* + * timestamp is 64 bits long ; resolution is 80 nS + * our clock resolution is 10mS + * 10mS/80ns = 125000 ~ 2^17 = 131072 + */ + utime = smt_get_time() ; + time = utime * 100 ; + time /= TICKS_PER_SECOND ; + p[0] = 0 ; + p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ; + p[2] = (u_char)(time>>(8+8+8-1)) ; + p[3] = (u_char)(time>>(8+8-1)) ; + p[4] = (u_char)(time>>(8-1)) ; + p[5] = (u_char)(time<<1) ; + p[6] = (u_char)(smc->sm.uniq_ticks>>8) ; + p[7] = (u_char)smc->sm.uniq_ticks ; + /* + * make sure we don't wrap: restart whenever the upper digits change + */ + if (utime != smc->sm.uniq_time) { + smc->sm.uniq_ticks = 0 ; + } + smc->sm.uniq_ticks++ ; + smc->sm.uniq_time = utime ; +} + +/* + * fill values in station policy parameter + */ +static void smt_fill_policy(smc,policy) +struct s_smc *smc ; +struct smt_p_policy *policy ; +{ + int i ; + u_char *map ; + u_short in ; + u_short out ; + + /* + * MIB para 101b (fddiSMTConnectionPolicy) coding + * is different from 0005 coding + */ + static u_char ansi_weirdness[16] = { + 0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15 + } ; + SMTSETPARA(policy,SMT_P_POLICY) ; + + out = 0 ; + in = smc->mib.fddiSMTConnectionPolicy ; + for (i = 0, map = ansi_weirdness ; i < 16 ; i++) { + if (in & 1) + out |= (1<<*map) ; + in >>= 1 ; + map++ ; + } + policy->pl_config = smc->mib.fddiSMTConfigPolicy ; + policy->pl_connect = out ; +} + +/* + * fill values in latency equivalent parameter + */ +static void smt_fill_latency(smc,latency) +struct s_smc *smc ; +struct smt_p_latency *latency ; +{ + SMTSETPARA(latency,SMT_P_LATENCY) ; + + latency->lt_phyout_idx1 = phy_index(smc,0) ; + latency->lt_latency1 = 10 ; /* in octets (byte clock) */ + /* + * note: latency has two phy entries by definition + * for a SAS, the 2nd one is null + */ + if (smc->s.sas == SMT_DAS) { + latency->lt_phyout_idx2 = phy_index(smc,1) ; + latency->lt_latency2 = 10 ; /* in octets (byte clock) */ + } + else { + latency->lt_phyout_idx2 = 0 ; + latency->lt_latency2 = 0 ; + } +} + +/* + * fill values in MAC neighbors parameter + */ +static void smt_fill_neighbor(smc,neighbor) +struct s_smc *smc ; +struct smt_p_neighbor *neighbor ; +{ + SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ; + + neighbor->nb_mib_index = INDEX_MAC ; + neighbor->nb_mac_index = mac_index(smc,1) ; + neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ; + neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ; +} + +/* + * fill values in path descriptor + */ +#ifdef CONCENTRATOR +#define ALLPHYS NUMPHYS +#else +#define ALLPHYS ((smc->s.sas == SMT_SAS) ? 1 : 2) +#endif + +static int smt_fill_path(smc,path) +struct s_smc *smc ; +struct smt_p_path *path ; +{ + SK_LOC_DECL(int,type) ; + SK_LOC_DECL(int,state) ; + SK_LOC_DECL(int,remote) ; + SK_LOC_DECL(int,mac) ; + int len ; + int p ; + int physp ; + struct smt_phy_rec *phy ; + struct smt_mac_rec *pd_mac ; + + len = PARA_LEN + + sizeof(struct smt_mac_rec) * NUMMACS + + sizeof(struct smt_phy_rec) * ALLPHYS ; + path->para.p_type = SMT_P_PATH ; + path->para.p_len = len - PARA_LEN ; + + /* PHYs */ + for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) { + physp = p ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + physp = PS ; +#endif + pcm_status_state(smc,physp,&type,&state,&remote,&mac) ; +#ifdef LITTLE_ENDIAN + phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ; +#else + phy->phy_mib_index = p+INDEX_PORT ; +#endif + phy->phy_type = type ; + phy->phy_connect_state = state ; + phy->phy_remote_type = remote ; + phy->phy_remote_mac = mac ; + phy->phy_resource_idx = phy_con_resource_index(smc,p) ; + } + + /* MAC */ + pd_mac = (struct smt_mac_rec *) phy ; + pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ; + pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ; + return(len) ; +} + +/* + * fill values in mac status + */ +static void smt_fill_mac_status(smc,st) +struct s_smc *smc ; +struct smt_p_mac_status *st ; +{ + SMTSETPARA(st,SMT_P_MAC_STATUS) ; + + st->st_mib_index = INDEX_MAC ; + st->st_mac_index = mac_index(smc,1) ; + + mac_update_counter(smc) ; + /* + * timer values are represented in SMT as 2's complement numbers + * units : internal : 2's complement BCLK + */ + st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ; + st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ; + st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ; + st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ; + st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ; + + st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ; + st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ; + st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ; + st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ; +} + +/* + * fill values in LEM status + */ + +static void smt_fill_lem(smc,lem,phy) +struct s_smc *smc ; +struct smt_p_lem *lem ; +int phy ; +{ + struct fddi_mib_p *mib ; + + mib = smc->y[phy].mib ; + + SMTSETPARA(lem,SMT_P_LEM) ; + lem->lem_mib_index = phy+INDEX_PORT ; + lem->lem_phy_index = phy_index(smc,phy) ; + lem->lem_pad2 = 0 ; + lem->lem_cutoff = mib->fddiPORTLer_Cutoff ; + lem->lem_alarm = mib->fddiPORTLer_Alarm ; + /* long term bit error rate */ + lem->lem_estimate = mib->fddiPORTLer_Estimate ; + /* # of rejected connections */ + lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ; + lem->lem_ct = mib->fddiPORTLem_Ct ; /* total number of errors */ +} + +/* + * fill version parameter + */ +static void smt_fill_version(smc,vers) +struct s_smc *smc ; +struct smt_p_version *vers ; +{ + SK_UNUSED(smc) ; + SMTSETPARA(vers,SMT_P_VERSION) ; + vers->v_pad = 0 ; + vers->v_n = 1 ; /* one version is enough .. */ + vers->v_index = 1 ; + vers->v_version[0] = SMT_VID_2 ; + vers->v_pad2 = 0 ; +} + +#ifdef SMT6_10 +/* + * fill frame status capabilities + */ +/* + * note: this para 200B is NOT in swap table, because it's also set in + * PMF add_para + */ +static void smt_fill_fsc(smc,fsc) +struct s_smc *smc ; +struct smt_p_fsc *fsc ; +{ + SK_UNUSED(smc) ; + SMTSETPARA(fsc,SMT_P_FSC) ; + fsc->fsc_pad0 = 0 ; + fsc->fsc_mac_index = INDEX_MAC ; /* this is MIB ; MIB is NOT + * mac_index ()i ! + */ + fsc->fsc_pad1 = 0 ; + fsc->fsc_value = FSC_TYPE0 ; /* "normal" node */ +#ifdef LITTLE_ENDIAN + fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ; + fsc->fsc_value = smt_swap_short(FSC_TYPE0) ; +#endif +} +#endif + +/* + * fill mac counter field + */ +static void smt_fill_mac_counter(smc,mc) +struct s_smc *smc ; +struct smt_p_mac_counter *mc ; +{ + SMTSETPARA(mc,SMT_P_MAC_COUNTER) ; + mc->mc_mib_index = INDEX_MAC ; + mc->mc_index = mac_index(smc,1) ; + mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ; + mc->mc_transmit_ct = smc->mib.m[MAC0].fddiMACTransmit_Ct ; +} + +/* + * fill mac frame not copied counter + */ +static void smt_fill_mac_fnc(smc,fnc) +struct s_smc *smc ; +struct smt_p_mac_fnc *fnc ; +{ + SMTSETPARA(fnc,SMT_P_MAC_FNC) ; + fnc->nc_mib_index = INDEX_MAC ; + fnc->nc_index = mac_index(smc,1) ; + fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ; +} + + +/* + * fill manufacturer field + */ +static void smt_fill_manufacturer(smc,man) +struct s_smc *smc ; +struct smp_p_manufacturer *man ; +{ + SMTSETPARA(man,SMT_P_MANUFACTURER) ; + memcpy((char *) man->mf_data, + (char *) smc->mib.fddiSMTManufacturerData, + sizeof(man->mf_data)) ; +} + +/* + * fill user field + */ +static void smt_fill_user(smc,user) +struct s_smc *smc ; +struct smp_p_user *user ; +{ + SMTSETPARA(user,SMT_P_USER) ; + memcpy((char *) user->us_data, + (char *) smc->mib.fddiSMTUserData, + sizeof(user->us_data)) ; +} + + + +/* + * fill set count + */ +static void smt_fill_setcount(smc,setcount) +struct s_smc *smc ; +struct smt_p_setcount *setcount ; +{ + SK_UNUSED(smc) ; + SMTSETPARA(setcount,SMT_P_SETCOUNT) ; + setcount->count = smc->mib.fddiSMTSetCount.count ; + memcpy((char *)setcount->timestamp, + (char *)smc->mib.fddiSMTSetCount.timestamp,8) ; +} + +/* + * fill echo data + */ +static void smt_fill_echo(smc,echo,seed,len) +struct s_smc *smc ; +struct smt_p_echo *echo ; +u_long seed ; +int len ; +{ + + u_char *p ; + + SK_UNUSED(smc) ; + SMTSETPARA(echo,SMT_P_ECHODATA) ; + echo->para.p_len = len ; + for (p = echo->ec_data ; len ; len--) { + *p++ = (u_char) seed ; + seed += 13 ; + } +} + +/* + * clear DNA and UNA + * called from CFM if configuration changes + */ +void smt_clear_una_dna(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; +} + +static void smt_clear_old_una_dna(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ; +} + +u_long smt_get_tid(smc) +struct s_smc *smc ; +{ + u_long tid ; + while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0) + ; + return(tid & 0x3fffffffL) ; +} + + +/* + * table of parameter lengths + */ +static const struct smt_pdef { + int ptype ; + int plen ; + const char *pswap ; +} smt_pdef[] = { + { SMT_P_UNA, sizeof(struct smt_p_una) , + SWAP_SMT_P_UNA } , + { SMT_P_SDE, sizeof(struct smt_p_sde) , + SWAP_SMT_P_SDE } , + { SMT_P_STATE, sizeof(struct smt_p_state) , + SWAP_SMT_P_STATE } , + { SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) , + SWAP_SMT_P_TIMESTAMP } , + { SMT_P_POLICY, sizeof(struct smt_p_policy) , + SWAP_SMT_P_POLICY } , + { SMT_P_LATENCY, sizeof(struct smt_p_latency) , + SWAP_SMT_P_LATENCY } , + { SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) , + SWAP_SMT_P_NEIGHBORS } , + { SMT_P_PATH, sizeof(struct smt_p_path) , + SWAP_SMT_P_PATH } , + { SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) , + SWAP_SMT_P_MAC_STATUS } , + { SMT_P_LEM, sizeof(struct smt_p_lem) , + SWAP_SMT_P_LEM } , + { SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) , + SWAP_SMT_P_MAC_COUNTER } , + { SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) , + SWAP_SMT_P_MAC_FNC } , + { SMT_P_PRIORITY,sizeof(struct smt_p_priority) , + SWAP_SMT_P_PRIORITY } , + { SMT_P_EB,sizeof(struct smt_p_eb) , + SWAP_SMT_P_EB } , + { SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) , + SWAP_SMT_P_MANUFACTURER } , + { SMT_P_REASON, sizeof(struct smt_p_reason) , + SWAP_SMT_P_REASON } , + { SMT_P_REFUSED, sizeof(struct smt_p_refused) , + SWAP_SMT_P_REFUSED } , + { SMT_P_VERSION, sizeof(struct smt_p_version) , + SWAP_SMT_P_VERSION } , +#ifdef ESS + { SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } , + { SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } , + { SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } , + { SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } , + { SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } , + { SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } , + { SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } , + { SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } , + { SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } , +#endif +#if 0 + { SMT_P_FSC, sizeof(struct smt_p_fsc) , + SWAP_SMT_P_FSC } , +#endif + + { SMT_P_SETCOUNT,0, SWAP_SMT_P_SETCOUNT } , + { SMT_P1048, 0, SWAP_SMT_P1048 } , + { SMT_P208C, 0, SWAP_SMT_P208C } , + { SMT_P208D, 0, SWAP_SMT_P208D } , + { SMT_P208E, 0, SWAP_SMT_P208E } , + { SMT_P208F, 0, SWAP_SMT_P208F } , + { SMT_P2090, 0, SWAP_SMT_P2090 } , +#ifdef ESS + { SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } , + { SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } , + { SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } , +#endif + { SMT_P4050, 0, SWAP_SMT_P4050 } , + { SMT_P4051, 0, SWAP_SMT_P4051 } , + { SMT_P4052, 0, SWAP_SMT_P4052 } , + { SMT_P4053, 0, SWAP_SMT_P4053 } , +} ; + +#define N_SMT_PLEN (sizeof(smt_pdef)/sizeof(smt_pdef[0])) + +int smt_check_para(smc,sm,list) +struct s_smc *smc ; +struct smt_header *sm ; +const u_short list[] ; +{ + const u_short *p = list ; + while (*p) { + if (!sm_to_para(smc,sm,(int) *p)) { + DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0); + return(-1) ; + } + p++ ; + } + return(0) ; +} + +EXPORT_PMF void *sm_to_para(smc,sm,para) +struct s_smc *smc ; +struct smt_header *sm ; +int para ; +{ + char *p ; + int len ; + int plen ; + void *found = 0 ; + + SK_UNUSED(smc) ; + + len = sm->smt_len ; + p = (char *)(sm+1) ; /* pointer to info */ + while (len > 0 ) { + if (((struct smt_para *)p)->p_type == para) + found = (void *) p ; + plen = ((struct smt_para *)p)->p_len + PARA_LEN ; + p += plen ; + len -= plen ; + if (len < 0) { + DB_SMT("SMT : sm_to_para - length error %d\n",plen,0) ; + return(0) ; + } + if ((plen & 3) && (para != SMT_P_ECHODATA)) { + DB_SMT("SMT : sm_to_para - odd length %d\n",plen,0) ; + return(0) ; + } + if (found) + return(found) ; + } + return(0) ; +} + +int is_my_addr(smc,addr) +struct s_smc *smc ; +struct fddi_addr *addr ; +{ + return(*(short *)(&addr->a[0]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0]) + && *(short *)(&addr->a[2]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2]) + && *(short *)(&addr->a[4]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ; +} + +int is_zero(addr) +struct fddi_addr *addr ; +{ + return(*(short *)(&addr->a[0]) == 0 && + *(short *)(&addr->a[2]) == 0 && + *(short *)(&addr->a[4]) == 0 ) ; +} + +int is_broadcast(addr) +struct fddi_addr *addr ; +{ + return(*(u_short *)(&addr->a[0]) == 0xffff && + *(u_short *)(&addr->a[2]) == 0xffff && + *(u_short *)(&addr->a[4]) == 0xffff ) ; +} + +int is_individual(addr) +struct fddi_addr *addr ; +{ + return(!(addr->a[0] & GROUP_ADDR)) ; +} + +int is_equal(addr1,addr2) +struct fddi_addr *addr1 ; +struct fddi_addr *addr2 ; +{ + return(*(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) && + *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) && + *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]) ) ; +} + + +#if 0 +/* + * send ANTC data test frame + */ +void fddi_send_antc(smc,dest) +struct s_smc *smc ; +struct fddi_addr *dest ; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dest) ; +#if 0 + SMbuf *mb ; + struct smt_header *smt ; + int i ; + char *p ; + + mb = smt_get_mbuf() ; + mb->sm_len = 3000+12 ; + p = smtod(mb, char *) + 12 ; + for (i = 0 ; i < 3000 ; i++) + *p++ = 1 << (i&7) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = *dest ; + smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; + smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ; +#endif +} +#endif + +#ifdef DEBUG +#define hextoasc(x) "0123456789abcdef"[x] + +char *addr_to_string(addr) +struct fddi_addr *addr ; +{ + int i ; + static char string[6*3] = "****" ; + + for (i = 0 ; i < 6 ; i++) { + string[i*3] = hextoasc((addr->a[i]>>4)&0xf) ; + string[i*3+1] = hextoasc((addr->a[i])&0xf) ; + string[i*3+2] = ':' ; + } + string[5*3+2] = 0 ; + return(string) ; +} +#endif + +#ifdef AM29K +smt_ifconfig(argc,argv) +int argc ; +char *argv[] ; +{ + if (argc >= 2 && !strcmp(argv[0],"opt_bypass") && + !strcmp(argv[1],"yes")) { + smc->mib.fddiSMTBypassPresent = 1 ; + return(0) ; + } + return(amdfddi_config(0,argc,argv)) ; +} +#endif + +/* + * return static mac index + */ +static int mac_index(smc,mac) +struct s_smc *smc ; +int mac ; +{ + SK_UNUSED(mac) ; +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + return(NUMPHYS+1) ; +#else + return((smc->s.sas == SMT_SAS) ? 2 : 3) ; +#endif +} + +/* + * return static phy index + */ +static int phy_index(smc,phy) +struct s_smc *smc ; +int phy ; +{ + SK_UNUSED(smc) ; + return(phy+1); +} + +/* + * return dynamic mac connection resource index + */ +static int mac_con_resource_index(smc,mac) +struct s_smc *smc ; +int mac ; +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + SK_UNUSED(mac) ; + return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_MAC))) ; +#else + SK_UNUSED(mac) ; + switch (smc->mib.fddiSMTCF_State) { + case SC9_C_WRAP_A : + case SC5_THRU_B : + case SC11_C_WRAP_S : + return(1) ; + case SC10_C_WRAP_B : + case SC4_THRU_A : + return(2) ; + } + return(smc->s.sas == SMT_SAS ? 2 : 3) ; +#endif +} + +/* + * return dynamic phy connection resource index + */ +static int phy_con_resource_index(smc,phy) +struct s_smc *smc ; +int phy ; +{ +#ifdef CONCENTRATOR + return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_PHY(phy)))) ; +#else + switch (smc->mib.fddiSMTCF_State) { + case SC9_C_WRAP_A : + return(phy == PA ? 3 : 2) ; + case SC10_C_WRAP_B : + return(phy == PA ? 1 : 3) ; + case SC4_THRU_A : + return(phy == PA ? 3 : 1) ; + case SC5_THRU_B : + return(phy == PA ? 2 : 3) ; + case SC11_C_WRAP_S : + return(2) ; + } + return(phy) ; +#endif +} + +#ifdef CONCENTRATOR +static int entity_to_index(smc,e) +struct s_smc *smc ; +int e ; +{ + if (e == ENTITY_MAC) + return(mac_index(smc,1)) ; + else + return(phy_index(smc,e - ENTITY_PHY(0))) ; +} +#endif + +#ifdef LITTLE_ENDIAN +static int smt_swap_short(s) +u_short s ; +{ + return(((s>>8)&0xff)|((s&0xff)<<8)) ; +} + +void smt_swap_para(sm,len,direction) +struct smt_header *sm ; +int len ; +int direction ; /* 0 encode 1 decode */ +{ + struct smt_para *pa ; + const struct smt_pdef *pd ; + char *p ; + int plen ; + int type ; + int i ; + +/* printf("smt_swap_para sm %x len %d dir %d\n", + sm,len,direction) ; + */ + smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ; + + /* swap args */ + len -= sizeof(struct smt_header) ; + + p = (char *) (sm + 1) ; + while (len > 0) { + pa = (struct smt_para *) p ; + plen = pa->p_len ; + type = pa->p_type ; + pa->p_type = smt_swap_short(pa->p_type) ; + pa->p_len = smt_swap_short(pa->p_len) ; + if (direction) { + plen = pa->p_len ; + type = pa->p_type ; + } + /* + * note: paras can have 0 length ! + */ + if (plen < 0) + break ; + plen += PARA_LEN ; + for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) { + if (pd->ptype == type) + break ; + } + if (i && pd->pswap) { + smt_string_swap(p+PARA_LEN,pd->pswap,len) ; + } + len -= plen ; + p += plen ; + } +} + +static void smt_string_swap(data,format,len) +char *data ; +const char *format ; +int len ; +{ + const char *open_paren = 0 ; + int x ; + + while (len > 0 && *format) { + switch (*format) { + case '[' : + open_paren = format ; + break ; + case ']' : + format = open_paren ; + break ; + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + data += *format - '0' ; + len -= *format - '0' ; + break ; + case 'c': + data++ ; + len-- ; + break ; + case 's' : + x = data[0] ; + data[0] = data[1] ; + data[1] = x ; + data += 2 ; + len -= 2 ; + break ; + case 'l' : + x = data[0] ; + data[0] = data[3] ; + data[3] = x ; + x = data[1] ; + data[1] = data[2] ; + data[2] = x ; + data += 4 ; + len -= 4 ; + break ; + } + format++ ; + } +} +#else +void smt_swap_para(sm,len,direction) +struct smt_header *sm ; +int len ; +int direction ; /* 0 encode 1 decode */ +{ + SK_UNUSED(sm) ; + SK_UNUSED(len) ; + SK_UNUSED(direction) ; +} +#endif + +/* + * PMF actions + */ +int smt_action(smc,class,code,index) +struct s_smc *smc ; +int class ; +int code ; +int index ; +{ + int event ; + int port ; + DB_SMT("SMT: action %d code %d\n",class,code) ; + switch(class) { + case SMT_STATION_ACTION : + switch(code) { + case SMT_STATION_ACTION_CONNECT : + smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; + queue_event(smc,EVENT_ECM,EC_CONNECT) ; + break ; + case SMT_STATION_ACTION_DISCONNECT : + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ; + RS_SET(smc,RS_DISCONNECT) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_PATHTEST : + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_SELFTEST : + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_DISABLE_A : + if (smc->y[PA].pc_mode == PM_PEER) { + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ; + } + break ; + case SMT_STATION_ACTION_DISABLE_B : + if (smc->y[PB].pc_mode == PM_PEER) { + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ; + } + break ; + case SMT_STATION_ACTION_DISABLE_M : + for (port = 0 ; port < NUMPHYS ; port++) { + if (smc->mib.p[port].fddiPORTMy_Type != TM) + continue ; + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+port,PC_DISABLE) ; + } + break ; + default : + return(1) ; + } + break ; + case SMT_PORT_ACTION : + switch(code) { + case SMT_PORT_ACTION_ENABLE : + event = PC_ENABLE ; + break ; + case SMT_PORT_ACTION_DISABLE : + event = PC_DISABLE ; + break ; + case SMT_PORT_ACTION_MAINT : + event = PC_MAINT ; + break ; + case SMT_PORT_ACTION_START : + event = PC_START ; + break ; + case SMT_PORT_ACTION_STOP : + event = PC_STOP ; + break ; + default : + return(1) ; + } + queue_event(smc,EVENT_PCM+index,event) ; + break ; + default : + return(1) ; + } + return(0) ; +} + +/* + * change tneg + * set T_Req in MIB (Path Attribute) + * calculate new values for MAC + * if change required + * disconnect + * set reconnect + * end + */ +void smt_change_t_neg(smc,tneg) +struct s_smc *smc ; +u_long tneg ; +{ + smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ; + + if (smt_set_mac_opvalues(smc)) { + RS_SET(smc,RS_EVENT) ; + smc->sm.please_reconnect = 1 ; + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + } +} + +/* + * canonical conversion of bytes beginning form *data + */ +#ifdef USE_CAN_ADDR +void hwm_conv_can(smc,data,len) +struct s_smc *smc ; +char *data ; +int len ; +{ + int i ; + + SK_UNUSED(smc) ; + + for (i = len; i ; i--, data++) { + *data = canonical[*(u_char *)data] ; + } +} +#endif + +#endif /* no SLIM_SMT */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/smtdef.c linux/drivers/net/skfp/smtdef.c --- v2.2.17/drivers/net/skfp/smtdef.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/smtdef.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,371 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + SMT/CMT defaults +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef OEM_USER_DATA +#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" +#endif + +#ifndef lint +static const char ID_sccs[] = "@(#)smtdef.c 2.53 99/08/11 (C) SK " ; +#endif + +/* + * defaults + */ +#define TTMS(x) ((u_long)(x)*1000L) +#define TTS(x) ((u_long)(x)*1000000L) +#define TTUS(x) ((u_long)(x)) + +#define DEFAULT_TB_MIN TTMS(5) +#define DEFAULT_TB_MAX TTMS(50) +#define DEFAULT_C_MIN TTUS(1600) +#define DEFAULT_T_OUT TTMS(100+5) +#define DEFAULT_TL_MIN TTUS(30) +#define DEFAULT_LC_SHORT TTMS(50+5) +#define DEFAULT_LC_MEDIUM TTMS(500+20) +#define DEFAULT_LC_LONG TTS(5)+TTMS(50) +#define DEFAULT_LC_EXTENDED TTS(50)+TTMS(50) +#define DEFAULT_T_NEXT_9 TTMS(200+10) +#define DEFAULT_NS_MAX TTUS(1310) +#define DEFAULT_I_MAX TTMS(25) +#define DEFAULT_IN_MAX TTMS(40) +#define DEFAULT_TD_MIN TTMS(5) +#define DEFAULT_T_NON_OP TTS(1) +#define DEFAULT_T_STUCK TTS(8) +#define DEFAULT_T_DIRECT TTMS(370) +#define DEFAULT_T_JAM TTMS(370) +#define DEFAULT_T_ANNOUNCE TTMS(2500) +#define DEFAULT_D_MAX TTUS(1617) +#define DEFAULT_LEM_ALARM (8) +#define DEFAULT_LEM_CUTOFF (7) +#define DEFAULT_TEST_DONE TTS(1) +#define DEFAULT_CHECK_POLL TTS(1) +#define DEFAULT_POLL TTMS(50) + +/* + * LCT errors threshold + */ +#define DEFAULT_LCT_SHORT 1 +#define DEFAULT_LCT_MEDIUM 3 +#define DEFAULT_LCT_LONG 5 +#define DEFAULT_LCT_EXTEND 50 + +/* Forward declarations */ +extern void smt_reset_defaults (); +static void smt_init_mib (); + +static int set_min_max() ; + +void smt_set_defaults(smc) +struct s_smc *smc ; +{ + smt_reset_defaults(smc,0) ; +} + +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x)*1250L) + +void smt_reset_defaults(smc,level) +struct s_smc *smc ; +int level ; +{ + struct smt_config *smt ; + int i ; + u_long smt_boot_time; + + + smt_init_mib(smc,level) ; + + smc->os.smc_version = SMC_VERSION ; + smt_boot_time = smt_get_time(); + for( i = 0; i < NUMMACS; i++ ) + smc->sm.last_tok_time[i] = smt_boot_time ; + smt = &smc->s ; + smt->attach_s = 0 ; + smt->build_ring_map = 1 ; + smt->sas = SMT_DAS ; + smt->numphys = NUMPHYS ; + smt->pcm_tb_min = DEFAULT_TB_MIN ; + smt->pcm_tb_max = DEFAULT_TB_MAX ; + smt->pcm_c_min = DEFAULT_C_MIN ; + smt->pcm_t_out = DEFAULT_T_OUT ; + smt->pcm_tl_min = DEFAULT_TL_MIN ; + smt->pcm_lc_short = DEFAULT_LC_SHORT ; + smt->pcm_lc_medium = DEFAULT_LC_MEDIUM ; + smt->pcm_lc_long = DEFAULT_LC_LONG ; + smt->pcm_lc_extended = DEFAULT_LC_EXTENDED ; + smt->pcm_t_next_9 = DEFAULT_T_NEXT_9 ; + smt->pcm_ns_max = DEFAULT_NS_MAX ; + smt->ecm_i_max = DEFAULT_I_MAX ; + smt->ecm_in_max = DEFAULT_IN_MAX ; + smt->ecm_td_min = DEFAULT_TD_MIN ; + smt->ecm_test_done = DEFAULT_TEST_DONE ; + smt->ecm_check_poll = DEFAULT_CHECK_POLL ; + smt->rmt_t_non_op = DEFAULT_T_NON_OP ; + smt->rmt_t_stuck = DEFAULT_T_STUCK ; + smt->rmt_t_direct = DEFAULT_T_DIRECT ; + smt->rmt_t_jam = DEFAULT_T_JAM ; + smt->rmt_t_announce = DEFAULT_T_ANNOUNCE ; + smt->rmt_t_poll = DEFAULT_POLL ; + smt->rmt_dup_mac_behavior = FALSE ; /* See Struct smt_config */ + smt->mac_d_max = DEFAULT_D_MAX ; + + smt->lct_short = DEFAULT_LCT_SHORT ; + smt->lct_medium = DEFAULT_LCT_MEDIUM ; + smt->lct_long = DEFAULT_LCT_LONG ; + smt->lct_extended = DEFAULT_LCT_EXTEND ; + +#ifndef SLIM_SMT +#ifdef ESS + if (level == 0) { + smc->ess.sync_bw_available = FALSE ; + smc->mib.fddiESSPayload = 0 ; + smc->mib.fddiESSOverhead = 0 ; + smc->mib.fddiESSMaxTNeg = (u_long)(- MS2BCLK(25)) ; + smc->mib.fddiESSMinSegmentSize = 1 ; + smc->mib.fddiESSCategory = SB_STATIC ; + smc->mib.fddiESSSynchTxMode = FALSE ; + smc->ess.raf_act_timer_poll = FALSE ; + smc->ess.timer_count = 7 ; /* first RAF alc req after 3s */ + } + smc->ess.local_sba_active = FALSE ; + smc->ess.sba_reply_pend = NULL ; +#endif +#ifdef SBA + smt_init_sba(smc,level) ; +#endif +#endif /* no SLIM_SMT */ +#ifdef TAG_MODE + if (level == 0) { + smc->hw.pci_fix_value = 0 ; + } +#endif +} + +/* + * manufacturer data + */ +static const char man_data[32] = +/* 01234567890123456789012345678901 */ + "xxxSK-NET FDDI SMT 7.3 - V2.8.8" ; + +static void smt_init_mib(smc,level) +struct s_smc *smc ; +int level ; +{ + struct fddi_mib *mib ; + struct fddi_mib_p *pm ; + int port ; + int path ; + + mib = &smc->mib ; + if (level == 0) { + /* + * set EVERYTHING to ZERO + * EXCEPT hw and os + */ + memset(((char *)smc)+ + sizeof(struct s_smt_os)+sizeof(struct s_smt_hw), 0, + sizeof(struct s_smc) - + sizeof(struct s_smt_os) - sizeof(struct s_smt_hw)) ; + } + else { + mib->fddiSMTRemoteDisconnectFlag = 0 ; + mib->fddiSMTPeerWrapFlag = 0 ; + } + + mib->fddiSMTOpVersionId = 2 ; + mib->fddiSMTHiVersionId = 2 ; + mib->fddiSMTLoVersionId = 2 ; + memcpy((char *) mib->fddiSMTManufacturerData,man_data,32) ; + if (level == 0) { + strcpy(mib->fddiSMTUserData,OEM_USER_DATA) ; + } + mib->fddiSMTMIBVersionId = 1 ; + mib->fddiSMTMac_Ct = NUMMACS ; + mib->fddiSMTConnectionPolicy = POLICY_MM | POLICY_AA | POLICY_BB ; + + /* + * fddiSMTNonMaster_Ct and fddiSMTMaster_Ct are set in smt_fixup_mib + * s.sas is not set yet (is set in init driver) + */ + mib->fddiSMTAvailablePaths = MIB_PATH_P | MIB_PATH_S ; + + mib->fddiSMTConfigCapabilities = 0 ; /* no hold,no wrap_ab*/ + mib->fddiSMTTT_Notify = 10 ; + mib->fddiSMTStatRptPolicy = TRUE ; + mib->fddiSMTTrace_MaxExpiration = SEC2MIB(7) ; + mib->fddiSMTMACIndexes = INDEX_MAC ; + mib->fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; /* seperated */ + + mib->m[MAC0].fddiMACIndex = INDEX_MAC ; + mib->m[MAC0].fddiMACFrameStatusFunctions = FSC_TYPE0 ; + mib->m[MAC0].fddiMACRequestedPaths = + MIB_P_PATH_LOCAL | + MIB_P_PATH_SEC_ALTER | + MIB_P_PATH_PRIM_ALTER ; + mib->m[MAC0].fddiMACAvailablePaths = MIB_PATH_P ; + mib->m[MAC0].fddiMACCurrentPath = MIB_PATH_PRIMARY ; + mib->m[MAC0].fddiMACT_MaxCapabilitiy = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACTVXCapabilitiy = (u_long)(- US2BCLK(52)) ; + if (level == 0) { + mib->m[MAC0].fddiMACTvxValue = (u_long)(- US2BCLK(27)) ; + mib->m[MAC0].fddiMACTvxValueMIB = (u_long)(- US2BCLK(27)) ; + mib->m[MAC0].fddiMACT_Req = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_ReqMIB = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_Max = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_MaxMIB = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_Min = (u_long)(- MS2BCLK(4)) ; + } + mib->m[MAC0].fddiMACHardwarePresent = TRUE ; + mib->m[MAC0].fddiMACMA_UnitdataEnable = TRUE ; + mib->m[MAC0].fddiMACFrameErrorThreshold = 1 ; + mib->m[MAC0].fddiMACNotCopiedThreshold = 1 ; + /* + * Path attributes + */ + for (path = 0 ; path < NUMPATHS ; path++) { + mib->a[path].fddiPATHIndex = INDEX_PATH + path ; + if (level == 0) { + mib->a[path].fddiPATHTVXLowerBound = + (u_long)(- US2BCLK(27)) ; + mib->a[path].fddiPATHT_MaxLowerBound = + (u_long)(- MS2BCLK(165)) ; + mib->a[path].fddiPATHMaxT_Req = + (u_long)(- MS2BCLK(165)) ; + } + } + + + /* + * Port attributes + */ + pm = mib->p ; + for (port = 0 ; port < NUMPHYS ; port++) { + /* + * set MIB pointer in phy + */ + /* Attention: don't initialize mib pointer here! */ + /* It must be initialized during phase 2 */ + smc->y[port].mib = 0 ; + mib->fddiSMTPORTIndexes[port] = port+INDEX_PORT ; + + pm->fddiPORTIndex = port+INDEX_PORT ; + pm->fddiPORTHardwarePresent = TRUE ; + if (level == 0) { + pm->fddiPORTLer_Alarm = DEFAULT_LEM_ALARM ; + pm->fddiPORTLer_Cutoff = DEFAULT_LEM_CUTOFF ; + } + /* + * fddiPORTRequestedPaths are set in pcmplc.c + * we don't know the port type yet ! + */ + pm->fddiPORTRequestedPaths[1] = 0 ; + pm->fddiPORTRequestedPaths[2] = 0 ; + pm->fddiPORTRequestedPaths[3] = 0 ; + pm->fddiPORTAvailablePaths = MIB_PATH_P ; + pm->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; + pm++ ; + } + + (void) smt_set_mac_opvalues(smc) ; +} + +int smt_set_mac_opvalues(smc) +struct s_smc *smc ; +{ + int st ; + int st2 ; + + st = set_min_max(1,smc->mib.m[MAC0].fddiMACTvxValueMIB, + smc->mib.a[PATH0].fddiPATHTVXLowerBound, + &smc->mib.m[MAC0].fddiMACTvxValue) ; + st |= set_min_max(0,smc->mib.m[MAC0].fddiMACT_MaxMIB, + smc->mib.a[PATH0].fddiPATHT_MaxLowerBound, + &smc->mib.m[MAC0].fddiMACT_Max) ; + st |= (st2 = set_min_max(0,smc->mib.m[MAC0].fddiMACT_ReqMIB, + smc->mib.a[PATH0].fddiPATHMaxT_Req, + &smc->mib.m[MAC0].fddiMACT_Req)) ; + if (st2) { + /* Treq attribute changed remotely. So send an AIX_EVENT to the + * user + */ + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ, + smt_get_event_word(smc)); + } + return(st) ; +} + +void smt_fixup_mib(smc) +struct s_smc *smc ; +{ +#ifdef CONCENTRATOR + switch (smc->s.sas) { + case SMT_SAS : + smc->mib.fddiSMTNonMaster_Ct = 1 ; + break ; + case SMT_DAS : + smc->mib.fddiSMTNonMaster_Ct = 2 ; + break ; + case SMT_NAC : + smc->mib.fddiSMTNonMaster_Ct = 0 ; + break ; + } + smc->mib.fddiSMTMaster_Ct = NUMPHYS - smc->mib.fddiSMTNonMaster_Ct ; +#else + switch (smc->s.sas) { + case SMT_SAS : + smc->mib.fddiSMTNonMaster_Ct = 1 ; + break ; + case SMT_DAS : + smc->mib.fddiSMTNonMaster_Ct = 2 ; + break ; + } + smc->mib.fddiSMTMaster_Ct = 0 ; +#endif +} + +/* + * determine new setting for operational value + * if limit is lower than mib + * use limit + * else + * use mib + * NOTE : numbers are negative, negate comparison ! + */ +static int set_min_max(maxflag,mib,limit,oper) +int maxflag ; +u_long mib ; +u_long limit ; +u_long *oper ; +{ + u_long old ; + old = *oper ; + if ((limit > mib) ^ maxflag) + *oper = limit ; + else + *oper = mib ; + return(old != *oper) ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/smtinit.c linux/drivers/net/skfp/smtinit.c --- v2.2.17/drivers/net/skfp/smtinit.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/smtinit.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,126 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + Init SMT + call all module level initialization routines +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smtinit.c 1.15 97/05/06 (C) SK " ; +#endif + +extern void init_fddi_driver() ; + +/* define global debug variable */ +#if defined(DEBUG) && !defined(DEBUG_BRD) +struct smt_debug debug; +#endif + +#ifndef MULT_OEM +#define OEMID(smc,i) oem_id[i] + extern u_char oem_id[] ; +#else /* MULT_OEM */ +#define OEMID(smc,i) smc->hw.oem_id->oi_mark[i] + extern struct s_oem_ids oem_ids[] ; +#endif /* MULT_OEM */ + +/* + * Set OEM specific values + * + * Can not be called in smt_reset_defaults, because it is not sure that + * the OEM ID is already defined. + */ +static void set_oem_spec_val(smc) +struct s_smc *smc ; +{ + struct fddi_mib *mib ; + + mib = &smc->mib ; + + /* + * set IBM specific values + */ + if (OEMID(smc,0) == 'I') { + mib->fddiSMTConnectionPolicy = POLICY_MM ; + } +} + +/* + * Init SMT + */ +int init_smt(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; /* canonical address or NULL */ +{ + int p ; + +#if defined(DEBUG) && !defined(DEBUG_BRD) + debug.d_smt = 0 ; + debug.d_smtf = 0 ; + debug.d_rmt = 0 ; + debug.d_ecm = 0 ; + debug.d_pcm = 0 ; + debug.d_cfm = 0 ; + + debug.d_plc = 0 ; +#ifdef ESS + debug.d_ess = 0 ; +#endif +#ifdef SBA + debug.d_sba = 0 ; +#endif +#endif /* DEBUG && !DEBUG_BRD */ + + /* First initialize the ports mib->pointers */ + for ( p = 0; p < NUMPHYS; p ++ ) { + smc->y[p].mib = & smc->mib.p[p] ; + } + + set_oem_spec_val(smc) ; + (void) smt_set_mac_opvalues(smc) ; + init_fddi_driver(smc,mac_addr) ; /* HW driver */ + smt_fixup_mib(smc) ; /* update values that depend on s.sas */ + + ev_init(smc) ; /* event queue */ +#ifndef SLIM_SMT + smt_init_evc(smc) ; /* evcs in MIB */ +#endif /* no SLIM_SMT */ + smt_timer_init(smc) ; /* timer package */ + smt_agent_init(smc) ; /* SMT frame manager */ + + pcm_init(smc) ; /* PCM state machine */ + ecm_init(smc) ; /* ECM state machine */ + cfm_init(smc) ; /* CFM state machine */ + rmt_init(smc) ; /* RMT state machine */ + + for (p = 0 ; p < NUMPHYS ; p++) { + pcm(smc,p,0) ; /* PCM A state machine */ + } + ecm(smc,0) ; /* ECM state machine */ + cfm(smc,0) ; /* CFM state machine */ + rmt(smc,0) ; /* RMT state machine */ + + smt_agent_task(smc) ; /* NIF FSM etc */ + + PNMI_INIT(smc) ; /* PNMI initialization */ + + return(0) ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/smtparse.c linux/drivers/net/skfp/smtparse.c --- v2.2.17/drivers/net/skfp/smtparse.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/smtparse.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,475 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + + +/* + parser for SMT parameters +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smtparse.c 1.12 98/10/06 (C) SK " ; +#endif + +#ifdef sun +#define _far +#endif + +/* + * convert to BCLK units + */ +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x/10)*125L) + +/* + * parameter table + */ +static struct s_ptab { + char *pt_name ; + u_short pt_num ; + u_short pt_type ; + u_long pt_min ; + u_long pt_max ; +} ptab[] = { + { "PMFPASSWD",0, 0 } , + { "USERDATA",1, 0 } , + { "LERCUTOFFA",2, 1, 4, 15 } , + { "LERCUTOFFB",3, 1, 4, 15 } , + { "LERALARMA",4, 1, 4, 15 } , + { "LERALARMB",5, 1, 4, 15 } , + { "TMAX",6, 1, 5, 165 } , + { "TMIN",7, 1, 5, 165 } , + { "TREQ",8, 1, 5, 165 } , + { "TVX",9, 1, 2500, 10000 } , +#ifdef ESS + { "SBAPAYLOAD",10, 1, 0, 1562 } , + { "SBAOVERHEAD",11, 1, 50, 5000 } , + { "MAXTNEG",12, 1, 5, 165 } , + { "MINSEGMENTSIZE",13, 1, 0, 4478 } , + { "SBACATEGORY",14, 1, 0, 0xffff } , + { "SYNCHTXMODE",15, 0 } , +#endif +#ifdef SBA + { "SBACOMMAND",16, 0 } , + { "SBAAVAILABLE",17, 1, 0, 100 } , +#endif + { 0 } +} ; + +/* Define maximum string size for values and keybuffer */ +#define MAX_VAL 40 + +/* + * local function declarations + */ +static u_long parse_num() ; +static int parse_word() ; + +#ifdef SIM +#define DB_MAIN(a,b,c) printf(a,b,c) +#else +#define DB_MAIN(a,b,c) +#endif + +/* + * BEGIN_MANUAL_ENTRY() + * + * int smt_parse_arg(struct s_smc *,char _far *keyword,int type, + char _far *value) + * + * parse SMT parameter + * *keyword + * pointer to keyword, must be \0, \n or \r terminated + * *value pointer to value, either char * or u_long * + * if char * + * pointer to value, must be \0, \n or \r terminated + * if u_long * + * contains binary value + * + * type 0: integer + * 1: string + * return + * 0 parameter parsed ok + * != 0 error + * NOTE: + * function can be called with DS != SS + * + * + * END_MANUAL_ENTRY() + */ +int smt_parse_arg(smc,keyword,type,value) +struct s_smc *smc ; +char _far *keyword ; +int type ; +char _far *value ; +{ + char keybuf[MAX_VAL+1]; + char valbuf[MAX_VAL+1]; + char c ; + char *p ; + char *v ; + char *d ; + u_long val = 0 ; + struct s_ptab *pt ; + int st ; + int i ; + + /* + * parse keyword + */ + if ((st = parse_word(keybuf,keyword))) + return(st) ; + /* + * parse value if given as string + */ + if (type == 1) { + if ((st = parse_word(valbuf,value))) + return(st) ; + } + /* + * search in table + */ + st = 0 ; + for (pt = ptab ; (v = pt->pt_name) ; pt++) { + for (p = keybuf ; (c = *p) ; p++,v++) { + if (c != *v) + break ; + } + if (!c && !*v) + break ; + } + if (!v) + return(-1) ; +#if 0 + printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ; +#endif + /* + * set value in MIB + */ + if (pt->pt_type) + val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ; + switch (pt->pt_num) { + case 0 : + v = valbuf ; + d = (char *) smc->mib.fddiPRPMFPasswd ; + for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++) + *d++ = *v++ ; + DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ; + break ; + case 1 : + v = valbuf ; + d = (char *) smc->mib.fddiSMTUserData ; + for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++) + *d++ = *v++ ; + DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ; + break ; + case 2 : + smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ; + break ; + case 3 : + smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ; + break ; + case 4 : + smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ; + break ; + case 5 : + smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ; + break ; + case 6 : /* TMAX */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.a[PATH0].fddiPATHT_MaxLowerBound = + (u_long) -MS2BCLK((long)val) ; + break ; + case 7 : /* TMIN */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.m[MAC0].fddiMACT_Min = + (u_long) -MS2BCLK((long)val) ; + break ; + case 8 : /* TREQ */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.a[PATH0].fddiPATHMaxT_Req = + (u_long) -MS2BCLK((long)val) ; + break ; + case 9 : /* TVX */ + DB_MAIN("SET %s = %d \n",pt->pt_name,val) ; + smc->mib.a[PATH0].fddiPATHTVXLowerBound = + (u_long) -US2BCLK((long)val) ; + break ; +#ifdef ESS + case 10 : /* SBAPAYLOAD */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + if (smc->mib.fddiESSPayload != val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSPayload = val ; + } + break ; + case 11 : /* SBAOVERHEAD */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSOverhead = val ; + break ; + case 12 : /* MAXTNEG */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ; + break ; + case 13 : /* MINSEGMENTSIZE */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSMinSegmentSize = val ; + break ; + case 14 : /* SBACATEGORY */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSCategory = + (smc->mib.fddiESSCategory & 0xffff) | + ((u_long)(val << 16)) ; + break ; + case 15 : /* SYNCHTXMODE */ + /* do not use memcmp(valbuf,"ALL",3) because DS != SS */ + if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') { + smc->mib.fddiESSSynchTxMode = TRUE ; + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + } + /* if (!memcmp(valbuf,"SPLIT",5)) { */ + if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' && + valbuf[3] == 'I' && valbuf[4] == 'T') { + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + smc->mib.fddiESSSynchTxMode = FALSE ; + } + break ; +#endif +#ifdef SBA + case 16 : /* SBACOMMAND */ + /* if (!memcmp(valbuf,"START",5)) { */ + if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' && + valbuf[3] == 'R' && valbuf[4] == 'T') { + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + smc->mib.fddiSBACommand = SB_START ; + } + /* if (!memcmp(valbuf,"STOP",4)) { */ + if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' && + valbuf[3] == 'P') { + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + smc->mib.fddiSBACommand = SB_STOP ; + } + break ; + case 17 : /* SBAAVAILABLE */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiSBAAvailable = (u_char) val ; + break ; +#endif + } + return(0) ; +} + +static int parse_word(buf,text) +char *buf ; +char _far *text ; +{ + char c ; + char *p ; + int p_len ; + int quote ; + int i ; + int ok ; + + /* + * skip leading white space + */ + p = buf ; + for (i = 0 ; i < MAX_VAL ; i++) + *p++ = 0 ; + p = buf ; + p_len = 0 ; + ok = 0 ; + while ( (c = *text++) && (c != '\n') && (c != '\r')) { + if ((c != ' ') && (c != '\t')) { + ok = 1 ; + break ; + } + } + if (!ok) + return(-1) ; + if (c == '"') { + quote = 1 ; + } + else { + quote = 0 ; + text-- ; + } + /* + * parse valbuf + */ + ok = 0 ; + while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n') + && (c != '\r')) { + switch (quote) { + case 0 : + if ((c == ' ') || (c == '\t') || (c == '=')) { + ok = 1 ; + break ; + } + *p++ = c ; + p_len++ ; + break ; + case 2 : + *p++ = c ; + p_len++ ; + quote = 1 ; + break ; + case 1 : + switch (c) { + case '"' : + ok = 1 ; + break ; + case '\\' : + quote = 2 ; + break ; + default : + *p++ = c ; + p_len++ ; + } + } + } + *p++ = 0 ; + for (p = buf ; (c = *p) ; p++) { + if (c >= 'a' && c <= 'z') + *p = c + 'A' - 'a' ; + } + return(0) ; +} + +static u_long parse_num(type,value,v,mn,mx,scale) +int type ; +char _far *value ; +char *v ; +u_long mn ; +u_long mx ; +int scale ; +{ + u_long x = 0 ; + char c ; + + if (type == 0) { /* integer */ + u_long _far *l ; + u_long u1 ; + + l = (u_long _far *) value ; + u1 = *l ; + /* + * if the value is negative take the lower limit + */ + if ((long)u1 < 0) { + if (- ((long)u1) > (long) mx) { + u1 = 0 ; + } + else { + u1 = (u_long) - ((long)u1) ; + } + } + x = u1 ; + } + else { /* string */ + int sign = 0 ; + + if (*v == '-') { + sign = 1 ; + } + while ((c = *v++) && (c >= '0') && (c <= '9')) { + x = x * 10 + c - '0' ; + } + if (scale == 10) { + x *= 10 ; + if (c == '.') { + if ((c = *v++) && (c >= '0') && (c <= '9')) { + x += c - '0' ; + } + } + } + if (sign) + x = (u_long) - ((long)x) ; + } + /* + * if the value is negative + * and the absolute value is outside the limits + * take the lower limit + * else + * take the absoute value + */ + if ((long)x < 0) { + if (- ((long)x) > (long) mx) { + x = 0 ; + } + else { + x = (u_long) - ((long)x) ; + } + } + if (x < mn) + return(mn) ; + else if (x > mx) + return(mx) ; + return(x) ; +} + +#if 0 +struct s_smc SMC ; +main() +{ + char *p ; + char *v ; + char buf[100] ; + int toggle = 0 ; + + while (gets(buf)) { + p = buf ; + while (*p && ((*p == ' ') || (*p == '\t'))) + p++ ; + + while (*p && ((*p != ' ') && (*p != '\t'))) + p++ ; + + v = p ; + while (*v && ((*v == ' ') || (*v == '\t'))) + v++ ; + if ((*v >= '0') && (*v <= '9')) { + toggle = !toggle ; + if (toggle) { + u_long l ; + l = atol(v) ; + smt_parse_arg(&SMC,buf,0,(char _far *)&l) ; + } + else + smt_parse_arg(&SMC,buf,1,(char _far *)p) ; + } + else { + smt_parse_arg(&SMC,buf,1,(char _far *)p) ; + } + } + exit(0) ; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/smttimer.c linux/drivers/net/skfp/smttimer.c --- v2.2.17/drivers/net/skfp/smttimer.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/smttimer.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,173 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + SMT timer +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ; +#endif + +/* + * external function declarations + */ +extern u_long hwt_read() ; +extern void hwt_stop() ; +extern void hwt_start() ; + +static void timer_done() ; + + +void smt_timer_init(smc) +struct s_smc *smc ; +{ + smc->t.st_queue = 0 ; + smc->t.st_fast.tm_active = FALSE ; + smc->t.st_fast.tm_next = 0 ; + hwt_init(smc) ; +} + +void smt_timer_stop(smc,timer) +struct s_smc *smc ; +struct smt_timer *timer ; +{ + struct smt_timer **prev ; + struct smt_timer *tm ; + + /* + * remove timer from queue + */ + timer->tm_active = FALSE ; + if (smc->t.st_queue == timer && !timer->tm_next) { + hwt_stop(smc) ; + } + for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { + if (tm == timer) { + *prev = tm->tm_next ; + if (tm->tm_next) { + tm->tm_next->tm_delta += tm->tm_delta ; + } + return ; + } + } +} + +void smt_timer_start(smc,timer,time,token) +struct s_smc *smc ; +struct smt_timer *timer ; +u_long time ; +u_long token ; +{ + struct smt_timer **prev ; + struct smt_timer *tm ; + u_long delta = 0 ; + + time /= 16 ; /* input is uS, clock ticks are 16uS */ + if (!time) + time = 1 ; + smt_timer_stop(smc,timer) ; + timer->tm_smc = smc ; + timer->tm_token = token ; + timer->tm_active = TRUE ; + if (!smc->t.st_queue) { + smc->t.st_queue = timer ; + timer->tm_next = 0 ; + timer->tm_delta = time ; + hwt_start(smc,time) ; + return ; + } + /* + * timer correction + */ + timer_done(smc,0) ; + + /* + * find position in queue + */ + delta = 0 ; + for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { + if (delta + tm->tm_delta > time) { + break ; + } + delta += tm->tm_delta ; + } + /* insert in queue */ + *prev = timer ; + timer->tm_next = tm ; + timer->tm_delta = time - delta ; + if (tm) + tm->tm_delta -= timer->tm_delta ; + /* + * start new with first + */ + hwt_start(smc,smc->t.st_queue->tm_delta) ; +} + +void smt_force_irq(smc) +struct s_smc *smc ; +{ + smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); +} + +void smt_timer_done(smc) +struct s_smc *smc ; +{ + timer_done(smc,1) ; +} + +static void timer_done(smc,restart) +struct s_smc *smc ; +int restart ; +{ + u_long delta ; + struct smt_timer *tm ; + struct smt_timer *next ; + struct smt_timer **last ; + int done = 0 ; + + delta = hwt_read(smc) ; + last = &smc->t.st_queue ; + tm = smc->t.st_queue ; + while (tm && !done) { + if (delta >= tm->tm_delta) { + tm->tm_active = FALSE ; + delta -= tm->tm_delta ; + last = &tm->tm_next ; + tm = tm->tm_next ; + } + else { + tm->tm_delta -= delta ; + delta = 0 ; + done = 1 ; + } + } + *last = 0 ; + next = smc->t.st_queue ; + smc->t.st_queue = tm ; + + for ( tm = next ; tm ; tm = next) { + next = tm->tm_next ; + timer_event(smc,tm->tm_token) ; + } + + if (restart && smc->t.st_queue) + hwt_start(smc,smc->t.st_queue->tm_delta) ; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/skfp/srf.c linux/drivers/net/skfp/srf.c --- v2.2.17/drivers/net/skfp/srf.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/skfp/srf.c Fri Sep 1 13:48:23 2000 @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * 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. + * + ******************************************************************************/ + +/* + SMT 7.2 Status Response Frame Implementation + SRF state machine and frame generation +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef SLIM_SMT +#ifndef BOOT + +#ifndef lint +static const char ID_sccs[] = "@(#)srf.c 1.18 97/08/04 (C) SK " ; +#endif + + +/* + * function declarations + */ +static void clear_all_rep() ; +static void clear_reported() ; +static void smt_send_srf() ; +static struct s_srf_evc *smt_get_evc() ; + +#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0])) + +struct evc_init { + u_char code ; + u_char index ; + u_char n ; + u_short para ; +} ; + +static const struct evc_init evc_inits[] = { + { SMT_COND_SMT_PEER_WRAP, 0,1,SMT_P1048 } , + + { SMT_COND_MAC_DUP_ADDR, INDEX_MAC, NUMMACS,SMT_P208C } , + { SMT_COND_MAC_FRAME_ERROR, INDEX_MAC, NUMMACS,SMT_P208D } , + { SMT_COND_MAC_NOT_COPIED, INDEX_MAC, NUMMACS,SMT_P208E } , + { SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC, NUMMACS,SMT_P208F } , + { SMT_EVENT_MAC_PATH_CHANGE, INDEX_MAC, NUMMACS,SMT_P2090 } , + + { SMT_COND_PORT_LER, INDEX_PORT,NUMPHYS,SMT_P4050 } , + { SMT_COND_PORT_EB_ERROR, INDEX_PORT,NUMPHYS,SMT_P4052 } , + { SMT_EVENT_PORT_CONNECTION, INDEX_PORT,NUMPHYS,SMT_P4051 } , + { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } , +} ; + +#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0])) + +void smt_init_evc(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + const struct evc_init *init ; + int i ; + int index ; + int offset ; + + static u_char fail_safe = FALSE ; + + memset((char *)smc->evcs,0,sizeof(smc->evcs)) ; + + evc = smc->evcs ; + init = evc_inits ; + + for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) { + for (index = 0 ; index < init->n ; index++) { + evc->evc_code = init->code ; + evc->evc_para = init->para ; + evc->evc_index = init->index + index ; +#ifndef DEBUG + evc->evc_multiple = &fail_safe ; + evc->evc_cond_state = &fail_safe ; +#endif + evc++ ; + } + init++ ; + } + + if ((unsigned) (evc - smc->evcs) > MAX_EVCS) { + SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ; + } + + /* + * conditions + */ + smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ; + smc->evcs[1].evc_cond_state = + &smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; + smc->evcs[2].evc_cond_state = + &smc->mib.m[MAC0].fddiMACFrameErrorFlag ; + smc->evcs[3].evc_cond_state = + &smc->mib.m[MAC0].fddiMACNotCopiedFlag ; + + /* + * events + */ + smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ; + smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ; + + offset = 6 ; + for (i = 0 ; i < NUMPHYS ; i++) { + /* + * conditions + */ + smc->evcs[offset + 0*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTLerFlag ; + smc->evcs[offset + 1*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTEB_Condition ; + + /* + * events + */ + smc->evcs[offset + 2*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_U ; + smc->evcs[offset + 3*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_P ; + offset++ ; + } +#ifdef DEBUG + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (!evc->evc_cond_state) { + SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ; + } + evc->evc_multiple = &fail_safe ; + } + else { + if (!evc->evc_multiple) { + SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ; + } + evc->evc_cond_state = &fail_safe ; + } + } +#endif + smc->srf.TSR = smt_get_time() ; + smc->srf.sr_state = SR0_WAIT ; +} + +static struct s_srf_evc *smt_get_evc(smc,code,index) +struct s_smc *smc ; +int code ; +int index ; +{ + int i ; + struct s_srf_evc *evc ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_code == code && evc->evc_index == index) + return(evc) ; + } + return(0) ; +} + +#define THRESHOLD_2 (2*TICKS_PER_SECOND) +#define THRESHOLD_32 (32*TICKS_PER_SECOND) + +#ifdef DEBUG +static const char * const srf_names[] = { + "None","MACPathChangeEvent", "MACNeighborChangeEvent", + "PORTPathChangeEvent", "PORTUndesiredConnectionAttemptEvent", + "SMTPeerWrapCondition", "SMTHoldCondition", + "MACFrameErrorCondition", "MACDuplicateAddressCondition", + "MACNotCopiedCondition", "PORTEBErrorCondition", + "PORTLerCondition" +} ; +#endif + +void smt_srf_event(smc,code,index,cond) +struct s_smc *smc ; +int code ; +int index ; +int cond ; +{ + struct s_srf_evc *evc ; + int cond_asserted = 0 ; + int cond_deasserted = 0 ; + int event_occured = 0 ; + int tsr ; + int T_Limit = 2*TICKS_PER_SECOND ; + + if (code == SMT_COND_MAC_DUP_ADDR && cond) { + RS_SET(smc,RS_DUPADDR) ; + } + + if (code) { + DB_SMT("SRF: %s index %d\n",srf_names[code],index) ; + + if (!(evc = smt_get_evc(smc,code,index))) { + DB_SMT("SRF : smt_get_evc() failed\n",0,0) ; + return ; + } + /* + * ignore condition if no change + */ + if (SMT_IS_CONDITION(code)) { + if (*evc->evc_cond_state == cond) + return ; + } + + /* + * set transition time stamp + */ + smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ; + if (SMT_IS_CONDITION(code)) { + DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ; + if (cond) { + *evc->evc_cond_state = TRUE ; + evc->evc_rep_required = TRUE ; + smc->srf.any_report = TRUE ; + cond_asserted = TRUE ; + } + else { + *evc->evc_cond_state = FALSE ; + cond_deasserted = TRUE ; + } + } + else { + if (evc->evc_rep_required) { + *evc->evc_multiple = TRUE ; + } + else { + evc->evc_rep_required = TRUE ; + *evc->evc_multiple = FALSE ; + } + smc->srf.any_report = TRUE ; + event_occured = TRUE ; + } +#ifdef FDDI_MIB + snmp_srf_event(smc,evc) ; +#endif /* FDDI_MIB */ + } + tsr = smt_get_time() - smc->srf.TSR ; + + switch (smc->srf.sr_state) { + case SR0_WAIT : + /* SR01a */ + if (cond_asserted && tsr < T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01b */ + if (cond_deasserted && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01c */ + if (event_occured && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR00b */ + if (cond_asserted && tsr >= T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00c */ + if (cond_deasserted && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00d */ + if (event_occured && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00e */ + if (smc->srf.any_report && (u_long) tsr >= + smc->srf.SRThreshold) { + smc->srf.SRThreshold *= 2 ; + if (smc->srf.SRThreshold > THRESHOLD_32) + smc->srf.SRThreshold = THRESHOLD_32 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR02 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR1_HOLDOFF : + /* SR10b */ + if (tsr >= T_Limit) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR11a */ + if (cond_asserted) { + smc->srf.SRThreshold = THRESHOLD_2 ; + } + /* SR11b */ + /* SR11c */ + /* handled above */ + /* SR12 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR2_DISABLED : + if (smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smc->srf.SRThreshold = THRESHOLD_2 ; + clear_all_rep(smc) ; + break ; + } + break ; + } +} + +static void clear_all_rep(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + int i ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + evc->evc_rep_required = FALSE ; + if (SMT_IS_CONDITION(evc->evc_code)) + *evc->evc_cond_state = FALSE ; + } + smc->srf.any_report = FALSE ; +} + +static void clear_reported(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + int i ; + + smc->srf.any_report = FALSE ; + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (*evc->evc_cond_state == FALSE) + evc->evc_rep_required = FALSE ; + else + smc->srf.any_report = TRUE ; + } + else { + evc->evc_rep_required = FALSE ; + *evc->evc_multiple = FALSE ; + } + } +} + +extern SMbuf *smt_build_frame() ; + +/* + * build and send SMT SRF frame + */ +static void smt_send_srf(smc) +struct s_smc *smc ; +{ + + struct smt_header *smt ; + struct s_srf_evc *evc ; + SK_LOC_DECL(struct s_pcon,pcon) ; + SMbuf *mb ; + int i ; + + static const struct fddi_addr SMT_SRF_DA = { + { 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 } + } ; + + /* + * build SMT header + */ + if (!smc->r.sm_ma_avail) + return ; + if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0))) + return ; + + RS_SET(smc,RS_SOFTERROR) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = SMT_SRF_DA ; /* DA == SRF multicast */ + + /* + * setup parameter status + */ + pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ + pcon.pc_err = 0 ; /* no error */ + pcon.pc_badset = 0 ; /* no bad set count */ + pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ + + smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_rep_required) { + smt_add_para(smc,&pcon,evc->evc_para, + (int)evc->evc_index,0) ; + } + } + smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; + mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; + + DB_SMT("SRF: sending SRF at %x, len %d \n",smt,mb->sm_len) ; + DB_SMT("SRF: state SR%d Threshold %d\n", + smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ; +#ifdef DEBUG + dump_smt(smc,smt,"SRF Send") ; +#endif + smt_send_frame(smc,mb,FC_SMT_INFO,0) ; + clear_reported(smc) ; +} + +#endif /* no BOOT */ +#endif /* no SLIM_SMT */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.2.17/drivers/net/smc9194.c Sun Jun 11 21:44:15 2000 +++ linux/drivers/net/smc9194.c Thu Aug 31 14:28:50 2000 @@ -18,6 +18,8 @@ . . author: . Erik Stahlman ( erik@vt.edu ) + . contributors: + . Arnaldo Carvalho de Melo . . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) . @@ -47,6 +49,7 @@ . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory . allocation + . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet ----------------------------------------------------------------------------*/ static const char *version = @@ -667,7 +670,7 @@ if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); - kfree(skb); + kfree_skb(skb); lp->saved_skb = NULL; dev->tbusy = 0; return; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/syncppp.c linux/drivers/net/syncppp.c --- v2.2.17/drivers/net/syncppp.c Sun Jun 11 21:44:15 2000 +++ linux/drivers/net/syncppp.c Wed Sep 13 16:10:27 2000 @@ -517,7 +517,6 @@ sppp_ipcp_open (sp); break; case LCP_STATE_OPENED: -#if 0 /* Remote magic changed -- close session. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; @@ -525,7 +524,6 @@ sppp_lcp_open (sp); /* An ACK has already been sent. */ sp->lcp.state = LCP_STATE_ACK_SENT; -#endif break; } break; @@ -566,7 +564,7 @@ sp->lcp.magic += newmagic; } else sp->lcp.magic = rmagic; - } + } if (sp->lcp.state != LCP_STATE_ACK_SENT) { /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.2.17/drivers/net/tlan.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/net/tlan.c Mon Sep 25 18:23:46 2000 @@ -57,6 +57,8 @@ * * v1.3b June 28, 2000 - Clean ups. * + * v1.3c Sep 7, 2000 - Minor typo fix. + * ********************************************************************************/ @@ -81,7 +83,7 @@ static int aui = 0; static int duplex = 0; static int speed = 0; -static const char *tlan_banner = "ThunderLAN driver v1.3b\n"; +static const char *tlan_banner = "ThunderLAN driver v1.3c\n"; MODULE_AUTHOR("Maintainer: Torben Mathiasen "); MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet adapters"); @@ -510,7 +512,7 @@ } priv->debug = dev->mem_end; - printk(KERN_INFO "TLAN 1.3b: %s irq=%2d io=%04x, %s, Rev. %d\n", + printk(KERN_INFO "TLAN 1.3c: %s irq=%2d io=%04x, %s, Rev. %d\n", dev->name, (int) irq, io_base, @@ -1121,7 +1123,7 @@ u32 TLan_HandleInvalid( struct device *dev, u16 host_int ) { host_int = 0; - printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); + /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */ return 0; } /* TLan_HandleInvalid */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.2.17/drivers/net/tulip.c Fri Apr 21 12:46:21 2000 +++ linux/drivers/net/tulip.c Sat Nov 18 00:52:47 2000 @@ -126,6 +126,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -320,7 +321,7 @@ long ioaddr, int irq, int chip_idx, int fnd_cnt); }; #ifndef CARDBUS -static struct pci_id_info pci_tbl[] = { +static struct pci_id_info pci_tbl[] __initdata = { { "Digital DC21040 Tulip", 0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, { "Digital DC21041 Tulip", @@ -343,6 +344,8 @@ 0x11AD, 0xc115, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, { "ADMtek AN981 Comet", 0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, + { "ADMtek AN985 Comet", + 0x1317, 0x0985, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 }, { "Compex RL100-TX", 0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, { "Intel 21145 Tulip", @@ -571,7 +574,7 @@ static struct device *root_tulip_dev = NULL; #ifndef CARDBUS -int tulip_probe(struct device *dev) +int __init tulip_probe(struct device *dev) { int cards_found = 0; int pci_index = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.2.17/drivers/net/via-rhine.c Sun Jun 11 21:44:15 2000 +++ linux/drivers/net/via-rhine.c Sun Oct 1 11:20:09 2000 @@ -77,6 +77,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -110,7 +111,7 @@ #define RUN_AT(x) (jiffies + (x)) #if (LINUX_VERSION_CODE >= 0x20100) -char kernel_version[] = UTS_RELEASE; +static char kernel_version[] = UTS_RELEASE; #else #ifndef __alpha__ #define ioremap vremap @@ -261,7 +262,7 @@ struct device *dev, long ioaddr, int irq, int chp_idx, int fnd_cnt); -static struct pci_id_info pci_tbl[] = { +static struct pci_id_info pci_tbl[] __initdata = { { "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff, PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1}, { "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff, @@ -275,7 +276,7 @@ struct chip_info { int io_size; int flags; -} static cap_tbl[] = { +} static cap_tbl[] __initdata = { {128, CanHaveMII, }, {128, CanHaveMII, }, }; @@ -398,7 +399,7 @@ well when dynamically adding drivers. So instead we detect just the cards we know about in slot order. */ -static int pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[]) +static int __init pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[]) { int cards_found = 0; int pci_index = 0; @@ -506,7 +507,7 @@ } #ifndef MODULE -int via_rhine_probe(struct device *dev) +int __init via_rhine_probe(struct device *dev) { static int did_version = 0; if (!did_version++) @@ -515,7 +516,7 @@ } #endif -static struct device *via_probe1(int pci_bus, int pci_devfn, +static struct device * __init via_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr, int irq, int chip_id, int card_idx) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/Makefile linux/drivers/net/xpds/Makefile --- v2.2.17/drivers/net/xpds/Makefile Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/Makefile Sun Oct 15 21:57:15 2000 @@ -0,0 +1,23 @@ +# File: drivers/xpds/Makefile +# +# Makefile for Xpeed DSL NIC driver +# + +ifeq ($(CONFIG_XPEED),y) + O_TARGET := xpds-fr.o + O_OBJS = xpds.o xpds-fsm.o xpds-sdsl.o xpds-encap-fr.o +else + ifeq ($(CONFIG_XPEED),m) + MOD_LIST_NAME := NET_MODULES + M_OBJS := xpds-fr.o + O_TARGET := xpds-fr.o + O_OBJS = xpds.o xpds-fsm.o xpds-sdsl.o xpds-encap-fr.o + endif +endif + +EXTRA_CFLAGS += -I. -DDEBUG=0 + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-encap-fr.c linux/drivers/net/xpds/xpds-encap-fr.c --- v2.2.17/drivers/net/xpds/xpds-encap-fr.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-encap-fr.c Tue Nov 7 13:19:28 2000 @@ -0,0 +1,751 @@ +/* + * Copyright 2000 Xpeed, Inc. + * fr.c $Revision: 1.23 $ + * License to copy and distribute is GNU General Public License, version 2. + * Some code adapted from Mike McLagan's dlci.c 0.30 from Linux kernels + * 2.0-2.2. + */ +#define __KERNEL__ 1 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "xpds.h" +#include "xpds-encap-fr.h" +#include "xpds-softnet.h" + +#define XPDS_DLCI_LMI_OFF 0 +#define XPDS_DLCI_LMI_LT 1 +#define XPDS_DLCI_LMI_NT 2 +#define XPDS_DLCI_LMI_NT_BIDIRECTIONAL 3 + +int xpds_dlci_t391 = 10; +int xpds_dlci_n391 = 6; + +#define DEBUG_DLCI 4 +extern int xpds_debug_level; + +#if DEBUG +#define dprintk if (xpds_debug_level & DEBUG_DLCI) printk +#else +#define dprintk if (0) printk +#endif + +#define nrprintk if (net_ratelimit()) printk + +typedef struct { + u8 dlci_header[2] __attribute__ ((packed)); + u8 protocol_discriminator __attribute__ ((packed)); + u8 call_reference __attribute__ ((packed)); + u8 padding __attribute__ ((packed)); +} dlci_status_head_t __attribute__ ((packed)); + +typedef struct { + u8 message_type __attribute__ ((packed)); + u8 locking_shift __attribute__ ((packed)); + u8 report_content_id __attribute__ ((packed)); + u8 report_content_length __attribute__ ((packed)); + u8 report_type __attribute__ ((packed)); + u8 liv_element_id __attribute__ ((packed)); + u8 liv_length __attribute__ ((packed)); + u8 liv_send_sequence __attribute__ ((packed)); + u8 liv_receive_sequence __attribute__ ((packed)); +} dlci_status_tail_t __attribute__ ((packed)); + +#define MESSAGE_STATUS_ENQUIRY 0x75 +#define MESSAGE_STATUS 0x7d + +#define REPORT_FULL_STATUS 0x00 +#define REPORT_LIV 0x01 +#define REPORT_SINGLE_PVC_STATS 0x02 + +typedef struct { + u8 pvc_status_id __attribute__ ((packed)); + u8 length __attribute__ ((packed)); + u8 dlci_info[2] __attribute__ ((packed)); + u8 flags __attribute__ ((packed)); +} dlci_pvc_status_t; + +#define PVC_FLAGS__NEW 0x08 +#define PVC_FLAGS__ACTIVE 0x02 + +typedef struct dlci_timer_data_t { + struct net_device *dev; + int dlci_num; +} dlci_timer_data_t; + +/* + * We generate LMI status enquiries in DLCI_LMI_NT mode. + */ +static void +xpds_dlci_lmi_timer (void *p) +{ + dlci_timer_data_t *data; + struct net_device *dev; + int card_num; + struct frad_local *flp; + dlci_status_head_t *status_head; + dlci_status_tail_t *status_tail; + struct sk_buff *skb; + short dlci, lmi_dlci = 0; + int i; + + data = (dlci_timer_data_t *) p; + + dev = data->dev; + card_num = dev - xpds_devs; + flp = &(xpds_data[card_num].frad_data); + + dprintk (KERN_DEBUG "%s: xpds_dlci_lmi_timer()\n", dev->name); + + if (xpds_data[card_num].dlci_lmi != XPDS_DLCI_LMI_NT && + xpds_data[card_num].dlci_lmi != XPDS_DLCI_LMI_NT_BIDIRECTIONAL){ + return; + } + + if (flp->no_initiate_lmi) return; + + dlci = flp->dlci[data->dlci_num]; + dprintk (KERN_DEBUG "%s: xpds_dlci_lmi_timer(), dev = %p, dlci = %d\n", xpds_devs[card_num].name, dev, dlci); + + if (xpds_if_busy(dev)) { + + skb = alloc_skb (sizeof (dlci_status_head_t) + + sizeof (dlci_status_tail_t), GFP_ATOMIC); + if (skb == NULL) { + printk (KERN_ERR "%s: unable to allocate skb in xlds_dlci_lmi_timer()\n", dev->name); + return; + } + skb->dev = dev; + skb->len = sizeof (dlci_status_head_t) + + sizeof (dlci_status_tail_t); + status_head = (dlci_status_head_t *) skb->data; + status_tail = (dlci_status_tail_t *) (skb->data + + sizeof (dlci_status_head_t)); + status_head->dlci_header[0] = ((lmi_dlci >> 4) << 2) | + xpds_data[card_num].dlci_cr; + status_head->dlci_header[1] = (lmi_dlci << 4) | 1; + status_head->protocol_discriminator = 0x03; + status_head->call_reference = 0x08; + status_head->padding = 0; + + status_tail->message_type = MESSAGE_STATUS_ENQUIRY; + status_tail->locking_shift = 0x95; + status_tail->report_content_id = 0x01; + status_tail->report_content_length = 0x01; + status_tail->liv_element_id = 0x03 /* 0x19 */; + status_tail->liv_length = 0x02; + + status_tail->liv_send_sequence = (flp->liv_send_sequence) ++; + status_tail->liv_receive_sequence = flp->liv_receive_sequence; + if (flp->pvc_active[data->dlci_num]) { + if (flp->remote_liv_receive_sequence >= + flp->new_liv_send_sequence) { + flp->pvc_new[data->dlci_num] = 0; + } else { + flp->pvc_new[data->dlci_num] = 1; + } + } else { + flp->new_liv_send_sequence = + status_tail->liv_send_sequence; + } + dprintk (KERN_DEBUG "%s: dlci = %d ", xpds_devs[card_num].name, dlci); + dprintk (KERN_DEBUG "pvc = %d, new = %d\n", + flp->pvc_active[data->dlci_num], flp->pvc_new[data->dlci_num]); + dprintk (KERN_DEBUG "%s: liv_send_sequence = %d, liv_receive_sequence = %d\n", xpds_devs[card_num].name, status_tail->liv_send_sequence, status_tail->liv_receive_sequence); + flp->message_number ++; + if (flp->message_number >= xpds_dlci_n391) { + flp->message_number = 0; + } + status_tail->report_type = + (flp->message_number == 0) ? + REPORT_FULL_STATUS : REPORT_LIV; + dprintk (KERN_DEBUG "message_number = %d, sending %02x\n", + flp->message_number, status_tail->report_type); + dprintk (KERN_DEBUG "%s: sending LMI packet in xpds_dlci_lmi_timer()\n", xpds_devs[card_num].name); + xpds_tx (skb->data, skb->len, dev); + + dev_kfree_skb (skb); + } + + i = data->dlci_num; + + init_timer(&(xpds_data[card_num].dlci_lmi_timers[i])); + xpds_data[card_num].dlci_lmi_timers[i].function = (void *)&xpds_dlci_lmi_timer; + xpds_data[card_num].dlci_lmi_timers[i].expires = jiffies + xpds_dlci_t391 * HZ; + xpds_data[card_num].dlci_lmi_timers[i].data = (unsigned long)&(xpds_data[card_num].dlci_lmi_timer_data[i]); + add_timer(&(xpds_data[card_num].dlci_lmi_timers[i])); + + dprintk(KERN_DEBUG "%s: xpds_dlci_lmi_timer()\n", dev->name); +} + +void +xpds_dlci_install_lmi_timer (int i, struct net_device *dev) +{ + int card_num; + + card_num = dev - xpds_devs; + + dprintk (KERN_DEBUG "%s: xpds_dlci_install_lmi_timer (%d, %p)\n", xpds_devs[card_num].name, i, dev); + if (i < 0 || i >= CONFIG_DLCI_COUNT) { + printk (KERN_ERR "%s: invalid DLCI device number %d\n", xpds_devs[card_num].name, i); + return; + } + init_timer(&(xpds_data[card_num].dlci_lmi_timers[i])); + xpds_data[card_num].dlci_lmi_timers[i].function = (void *)&xpds_dlci_lmi_timer; + xpds_data[card_num].dlci_lmi_timers[i].expires = jiffies + xpds_dlci_t391 * HZ; + xpds_data[card_num].dlci_lmi_timer_data[i].dev = dev; + xpds_data[card_num].dlci_lmi_timer_data[i].dlci_num = i; + xpds_data[card_num].dlci_lmi_timers[i].data = (unsigned long)&(xpds_data[card_num].dlci_lmi_timer_data[i]); + add_timer(&(xpds_data[card_num].dlci_lmi_timers[i])); + dprintk (KERN_DEBUG "%s: xpds_dlci_install_lmi_timer() done\n", + dev->name); +} + +void +xpds_dlci_remove_lmi_timer (int i, struct net_device *dev) +{ + int card_num; + + card_num = dev - xpds_devs; + + dprintk (KERN_DEBUG "%s: xpds_dlci_remove_lmi_timer (%d, %p)\n", + dev->name, i, dev); + if (i < 0 || i >= CONFIG_DLCI_COUNT) { + printk (KERN_ERR "%s: invalid DLCI device number %d\n", xpds_devs[card_num].name, i); + return; + } + del_timer(&(xpds_data[card_num].dlci_lmi_timers[i])); + dprintk (KERN_DEBUG "%s: xpds_dlci_remove_lmi_timer() done\n", + dev->name); +} + + +static void +xpds_dlci_handle_status (struct sk_buff *skb, struct net_device *dev) +{ + struct frad_local *flp; + dlci_status_head_t *dlci_status_head, *reply_status_head; + dlci_status_tail_t *dlci_status_tail, *reply_status_tail; + dlci_pvc_status_t *dlci_pvc_status, *reply_pvc_status; + struct sk_buff *reply_skb; + short dlci, lmi_dlci = 0; + int i; + int old_pvc_active; + int has_pvc_status; + int has_padding; + int card_num; + + card_num = dev - xpds_devs; + + if (xpds_data[card_num].dlci_lmi == XPDS_DLCI_LMI_OFF) return; + + flp = &(xpds_data[card_num].frad_data); + skb->dev = dev; + + dlci_status_head = (dlci_status_head_t *)skb->data; + if (dlci_status_head->padding != 0) { + /* + * no padding + */ + has_padding = 0; + } else { + /* + * one byte of zero padding between call reference + * and message type + */ + has_padding = 1; + } + dlci_status_tail = (dlci_status_tail_t *) + (skb->data + sizeof (*dlci_status_head) - 1 + has_padding); + if (skb->len < sizeof (*dlci_status_head) + sizeof (*dlci_status_tail) - 1 + has_padding) { + dprintk (KERN_ERR "%s: LMI packet of length %lu is too short\n", xpds_devs[card_num].name, (unsigned long) (skb->len)); + } + dlci_pvc_status = (dlci_pvc_status_t *) + (skb->data + sizeof (*dlci_status_head) + + sizeof (*dlci_status_tail) - 1 + has_padding); + + dprintk (KERN_DEBUG "%s: LMI packet received has protocol discriminator = 0x%02x\n", xpds_devs[card_num].name, dlci_status_head->protocol_discriminator); + dprintk (KERN_DEBUG "%s: LMI packet received has call reference = 0x%02x\n", + dev->name, dlci_status_head->call_reference); + if (dlci_status_head->protocol_discriminator != FRAD_I_UI || + dlci_status_head->call_reference != FRAD_P_Q933) { + printk (KERN_NOTICE "%s: dlci_handle_status called with 0x%02x 0x%02x\n", + dev->name, dlci_status_head->protocol_discriminator, + dlci_status_head->call_reference); + return; + } + + dprintk (KERN_DEBUG "LMI packet received has message type = 0x%02x\n", + dlci_status_tail->message_type); + if (dlci_status_tail->message_type != MESSAGE_STATUS_ENQUIRY && + dlci_status_tail->message_type != MESSAGE_STATUS) { + printk (KERN_NOTICE "unknown message type 0x%02x\n", + dlci_status_tail->message_type); + return; + } + + dprintk (KERN_DEBUG "LMI packet received has report type = 0x%02x\n", + dlci_status_tail->report_type); + if (dlci_status_tail->report_type != REPORT_FULL_STATUS && + dlci_status_tail->report_type != REPORT_LIV) { + dprintk (KERN_DEBUG "report type is not full status or LIV\n"); + return; + } + + dprintk (KERN_DEBUG "LMI packet received has receive sequence = %d\n", + dlci_status_tail->liv_receive_sequence); + dprintk (KERN_DEBUG "LMI packet received has send sequence = %d\n", + dlci_status_tail->liv_send_sequence); + + reply_skb = alloc_skb (sizeof (dlci_status_head_t) + + sizeof (dlci_status_tail_t) + sizeof (dlci_pvc_status_t), + GFP_ATOMIC); + if (reply_skb == NULL) { + printk (KERN_ERR "%s: unable to allocate reply_skb in xpds_dlci_handle_status().\n", dev->name); + return; + } + reply_skb->len = sizeof (dlci_status_head_t) + + sizeof (dlci_status_tail_t) /* + sizeof (dlci_pvc_status_t) */; + reply_status_head = (dlci_status_head_t *) reply_skb->data; + reply_status_tail = (dlci_status_tail_t *) (reply_skb->data + + sizeof (dlci_status_head_t)); + reply_pvc_status = (dlci_pvc_status_t *) (reply_skb->data + + sizeof (dlci_status_head_t) + sizeof (dlci_status_tail_t) ); + + if (dlci_status_tail->liv_receive_sequence > flp->liv_send_sequence){ + dprintk (KERN_DEBUG "received receive sequence number %d > %d\n", + dlci_status_tail->liv_receive_sequence, + flp->liv_send_sequence); + } + flp->remote_liv_receive_sequence = + dlci_status_tail->liv_receive_sequence; + flp->liv_send_sequence = dlci_status_tail->liv_receive_sequence + 1; + + flp->remote_liv_send_sequence = + dlci_status_tail->liv_send_sequence; + flp->liv_receive_sequence = dlci_status_tail->liv_send_sequence; + + if (dlci_status_tail->report_type == REPORT_FULL_STATUS) { + if (skb->len < sizeof (*dlci_status_head) + sizeof (*dlci_status_tail) - 1 + has_padding + sizeof (*dlci_pvc_status)) { + if (dlci_status_tail->message_type == MESSAGE_STATUS) { + printk (KERN_ERR "%s: LMI packet length %lu is too short for report type REPORT_FULL_STATUS\n", xpds_devs[card_num].name, (unsigned long) (skb->len)); + } + dlci = -1; + has_pvc_status = 0; + } else { + dlci = ((dlci_pvc_status->dlci_info[0] & 0x7f) << 4) | + ((dlci_pvc_status->dlci_info[1] & 0x7f) >> 3); + has_pvc_status = 1; + } + } else { + dprintk (KERN_DEBUG "%s: dlci_status_tail->report_type = 0x%02x (not REPORT_FULL_STATUS)\n", xpds_devs[card_num].name, dlci_status_tail->report_type); + dlci = -1; + has_pvc_status = 0; + } + dprintk (KERN_DEBUG "%s: LMI packet received has DLCI = %d, has_pvc_status = %d\n", xpds_devs[card_num].name, dlci, has_pvc_status); + + if (has_pvc_status) { + for (i = 0; i < CONFIG_DLCI_MAX; i ++) { + if (dlci == flp->dlci[i]) break; + } + if (i >= CONFIG_DLCI_MAX) { + int j; + + printk (KERN_ERR "%s: invalid DLCI %d\n", + dev->name, dlci); + + printk (KERN_ERR "%s: flp->dlci[] = {", xpds_devs[card_num].name); + for (j = 0; j < CONFIG_DLCI_MAX; j ++) { + if (j != 0) printk (", "); + printk ("%d", flp->dlci[j]); + } + printk ("}\n"); + dev_kfree_skb (reply_skb); + return; + } + } else { + i = 0; + } + + reply_status_head->dlci_header[0] = ((lmi_dlci >> 4) << 2) | + xpds_data[card_num].dlci_cr; + reply_status_head->dlci_header[1] = (lmi_dlci << 4) | 1; + reply_status_head->protocol_discriminator = 0x03; + reply_status_head->call_reference = 0x08; + reply_status_head->padding = 0; + + reply_status_tail->message_type = MESSAGE_STATUS; + reply_status_tail->locking_shift = 0x95; + reply_status_tail->report_content_id = 0x01; + reply_status_tail->report_content_length = 0x01; + flp->message_number ++; + if (flp->message_number >= xpds_dlci_n391) { + flp->message_number = 0; + } + reply_status_tail->report_type = + (flp->message_number == 0) ? + REPORT_FULL_STATUS : REPORT_LIV; + dprintk (KERN_DEBUG "%s: message_number = %d, sending 0x%02x\n", + dev->name, flp->message_number, reply_status_tail->report_type); + reply_status_tail->liv_element_id = 0x03 /* 0x19 */; + reply_status_tail->liv_length = 0x02; + reply_status_tail->liv_send_sequence = (flp->liv_send_sequence) ++; + reply_status_tail->liv_receive_sequence = flp->liv_receive_sequence; + + if (has_pvc_status) { + reply_pvc_status->pvc_status_id = 0x7; + reply_pvc_status->length = 3; + reply_pvc_status->dlci_info[0] = (dlci >> 6) & 0x3f; + reply_pvc_status->dlci_info[1] = ((dlci << 3) & 0x78) | 0x80; + + dprintk (KERN_DEBUG "dlci_pvc_status->pvc_status_id = 0x%02x\n", + dlci_pvc_status->pvc_status_id); + dprintk (KERN_DEBUG "dlci_pvc_status->length = 0x%02x\n", + dlci_pvc_status->length); + dprintk (KERN_DEBUG "dlci_pvc_status->dlci_info = 0x%02x 0x%02x\n", dlci_pvc_status->dlci_info[0], dlci_pvc_status->dlci_info[1]); + dprintk (KERN_DEBUG "dlci_pvc_status->flags = 0x%02x\n", + dlci_pvc_status->flags); + old_pvc_active = flp->pvc_active[i]; + flp->pvc_active[i] = (dlci_pvc_status->flags & PVC_FLAGS__ACTIVE) != 0; + if (! old_pvc_active && flp->pvc_active[i]) { + printk (KERN_NOTICE "%s: DLCI %d PVC became active\n", xpds_devs[card_num].name, dlci); + } + if (old_pvc_active && ! flp->pvc_active[i]) { + printk (KERN_NOTICE "%s: DLCI %d PVC became inactive\n", xpds_devs[card_num].name, dlci); + } + if (flp->pvc_active[i]) { + if (dlci_status_tail->liv_receive_sequence >= + flp->new_liv_send_sequence) { + flp->pvc_new[i] = 0; + } else { + flp->pvc_new[i] = 1; + } + } else { + flp->new_liv_send_sequence = + reply_status_tail->liv_send_sequence; + } + dprintk (KERN_DEBUG "dlci = %d\n", dlci); + dprintk (KERN_DEBUG "pvc = %d, new = %d\n", + flp->pvc_active[i], flp->pvc_new[i]); + dprintk (KERN_DEBUG "liv_send_sequence = %d, liv_receive_sequence = %d\n", reply_status_tail->liv_send_sequence, reply_status_tail->liv_receive_sequence); + reply_pvc_status->flags = 0x80 | (flp->pvc_new[i] << 3) | + (flp->pvc_active[i] << 1); + } + + /* ... */ + + if (xpds_data[card_num].dlci_lmi == XPDS_DLCI_LMI_LT || + xpds_data[card_num].dlci_lmi == XPDS_DLCI_LMI_NT_BIDIRECTIONAL){ + dprintk (KERN_DEBUG "sending LMI packet in xpds_dlci_handle_status()\n"); + xpds_tx (reply_skb->data, reply_skb->len, dev); + dev_kfree_skb(reply_skb); + } + + /* This is freed by the caller. */ + /* dev_kfree_skb(skb); */ +} + +void +xpds_dlci_receive(struct sk_buff *skb, struct net_device *dev) +{ + int card_num; + struct frhdr *hdr; + struct frad_local *flp; + int process, header, actual_header_size; + + dprintk(KERN_DEBUG "xpds_dlci_receive (%p, %p)\n", skb, dev); + card_num = dev - xpds_devs; + flp = &(xpds_data[card_num].frad_data); + hdr = (struct frhdr *) (skb->data); + process = 0; + header = sizeof(hdr->addr_control); + skb->dev = dev; + + actual_header_size = skb->tail - skb->data; + if (actual_header_size < header + 2) { + nrprintk (KERN_NOTICE "%s: header is too short (%d bytes)\n", + dev->name, skb->tail - skb->data); + dev_kfree_skb(skb); + xpds_data[card_num].stats.rx_errors++; + return; + } + + if (hdr->control != FRAD_I_UI) { + nrprintk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", + dev->name, hdr->control); + xpds_data[card_num].stats.rx_errors++; + } else { + switch (hdr->IP_NLPID) { + case FRAD_P_PADDING: + if (hdr->NLPID != FRAD_P_SNAP) { + nrprintk(KERN_NOTICE + "%s: Unsupported NLPID 0x%02X.\n", + dev->name, hdr->NLPID); + xpds_data[card_num].stats.rx_errors++; + break; + } + + if (actual_header_size < sizeof (struct frhdr)) { + nrprintk (KERN_NOTICE "%s: header is too short (%d bytes, IP_NLPID == FRAD_P_PADDING)\n", dev->name, skb->tail - skb->data); + dev_kfree_skb(skb); + return; + } + + if (hdr->OUI[0] == FRAD_OUI_BRIDGED_0 && + hdr->OUI[1] == FRAD_OUI_BRIDGED_1 && + hdr->OUI[2] == FRAD_OUI_BRIDGED_2) { + /* bridged ethernet */ + + struct ethhdr *ehdr; + + header = sizeof(struct frhdr); + ehdr = + (struct ethhdr *) (skb->data + header); + skb->protocol = ntohs(ehdr->h_proto); + /* skb->mac.raw = (char *)&(ehdr->h_dest); */ + dprintk(KERN_DEBUG + "hdr->NLPID = FRAD_P_SNAP (%02X), protocol = 0x%04x\n", + FRAD_P_SNAP, skb->protocol); + process = 1; + break; + } + + if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0) { + nrprintk(KERN_NOTICE + "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", + dev->name, hdr->OUI[0], hdr->OUI[1], + hdr->OUI[2]); + xpds_data[card_num].stats.rx_errors++; + break; + } + + /* at this point, it's an EtherType frame */ + header = sizeof(struct frhdr); + /* Already in network order ! */ + skb->protocol = hdr->PID; + process = 1; + break; + + case FRAD_P_IP: + dprintk(KERN_DEBUG + "hdr->IP_NLPID = FRAD_P_IP (%02X)\n", + FRAD_P_IP); + header = + sizeof(hdr->addr_control) + + sizeof(hdr->control) + sizeof(hdr->IP_NLPID); + if (actual_header_size < header) { + nrprintk (KERN_NOTICE "%s: header is too short (%d bytes, IP_NLPID == FRAD_P_IP)\n", dev->name, skb->tail - skb->data); + xpds_data[card_num].stats.rx_errors++; + } else { + skb->protocol = htons(ETH_P_IP); + process = 1; + } + break; + + case FRAD_P_Q933: + /* status / status enquiry message */ + dprintk(KERN_DEBUG + "hdr->IP_NLPID = FRAD_P_Q933 (%02X)\n", + FRAD_P_Q933); + xpds_dlci_handle_status(skb, dev); + break; + case FRAD_P_SNAP: + dprintk(KERN_DEBUG + "hdr->IP_NLPID = FRAD_P_SNAP (%02X)\n", + FRAD_P_SNAP); + skb->protocol = htons(ETH_P_ARP); + process = 1; + break; + case FRAD_P_CLNP: + nrprintk(KERN_NOTICE + "%s: Unsupported NLPID 0x%02X.\n", + dev->name, hdr->pad); + xpds_data[card_num].stats.rx_errors++; + break; + + default: + nrprintk(KERN_NOTICE + "%s: Invalid pad byte 0x%02X.\n", dev->name, + hdr->pad); + xpds_data[card_num].stats.rx_errors++; + break; + } + } + + if (process) { + dprintk(KERN_DEBUG "%s: header size = %d\n", dev->name, + header); + if (xpds_data[card_num].bridged_ethernet) { + skb_pull(skb, header); + } else { + struct ethhdr *ehdr; + skb_pull(skb, header); + skb_push(skb, sizeof(struct ethhdr)); + ehdr = (struct ethhdr *) skb->data; + memcpy(ehdr->h_dest, + xpds_data[card_num].serial_data.mac_address, + sizeof(ehdr->h_dest)); + /* +++ */ + memset(ehdr->h_source, 0xff, + sizeof(ehdr->h_source)); + /* +++ */ + ehdr->h_proto = skb->protocol; + } + skb->ip_summed = CHECKSUM_NONE; +#if DEBUG + { + long i, skblen; + + dprintk(KERN_DEBUG + "%s: packet of length %ld to be given to netif_rx():", dev->name, (long) (skb->len)); + skblen = skb->len > 256 ? 256 : skb->len; + for (i = 0; i < skblen; i++) { + dprintk(" %02x", skb->data[i]); + } + if (skb->len > skblen) dprintk (" ..."); + dprintk("\n"); + dprintk(KERN_DEBUG + "%s: skb->head = %p, skb->data = %p, skb->tail = %p, skb->end = %p\n", + dev->name, skb->head, skb->data, skb->tail, + skb->end); + } +#endif + skb->protocol = eth_type_trans(skb, dev); + dprintk(KERN_DEBUG "calling netif_rx (%p)\n", skb); + netif_rx(skb); + } else { + dev_kfree_skb(skb); + } + dprintk(KERN_DEBUG "xpds_dlci_receive done\n"); +} + +static unsigned int +xpds_dlci_add_fr_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, u8 * hdr) +{ + unsigned hlen; + short dlci; + struct frad_local *flp; + int card_num; + struct frhdr *frhdr; + + frhdr = (struct frhdr *) hdr; + card_num = dev - xpds_devs; + dprintk(KERN_DEBUG "%s: adding frame relay header\n", dev->name); + flp = &(xpds_data[card_num].frad_data); + dlci = xpds_data[card_num].dlci; + hdr[0] = ((dlci >> 4) << 2) | xpds_data[card_num].dlci_cr; + hdr[1] = (dlci << 4) | 1; + + frhdr->control = FRAD_I_UI; + dprintk(KERN_DEBUG "%s: type = 0x%04x\n", dev->name, type); + switch (type) { + case ETH_P_IP: + case ETH_P_ARP: + if (xpds_data[card_num].bridged_ethernet) { + frhdr->pad = FRAD_P_PADDING; + frhdr->NLPID = FRAD_P_SNAP; + frhdr->OUI[0] = FRAD_OUI_BRIDGED_0; + frhdr->OUI[1] = FRAD_OUI_BRIDGED_1; + frhdr->OUI[2] = FRAD_OUI_BRIDGED_2; + frhdr->PID = htons(FRAD_PID); + hlen = sizeof(*frhdr); + } else { + frhdr->IP_NLPID = FRAD_P_IP; + hlen = + sizeof(frhdr->addr_control) + + sizeof(frhdr->control) + + sizeof(frhdr->IP_NLPID); + } + break; + + /* feel free to add other types, if necessary */ + + default: + frhdr->pad = FRAD_P_PADDING; + frhdr->NLPID = FRAD_P_SNAP; + memset(frhdr->OUI, 0, sizeof(frhdr->OUI)); + frhdr->PID = htons(type); + hlen = sizeof(*frhdr); + break; + } + + dprintk(KERN_DEBUG "type = 0x%02x, bridged = %d, hlen = %d\n", + type, xpds_data[card_num].bridged_ethernet, hlen); + +#if DEBUG + { + int i; + + dprintk(KERN_DEBUG "dlci_header added:"); + for (i = 0; i < hlen; i++) { + dprintk(" %02x", ((u8 *) hdr)[i]); + } + dprintk("\n"); + } +#endif + return hlen; +} + +int +xpds_dlci_transmit(struct sk_buff *skb, struct net_device *dev) +{ + u8 *hdr, *buffer; + int card_num, rc; + unsigned int ptr, len; + + dprintk(KERN_DEBUG "xpds_dlci_transmit (%p, %p)\n", skb, dev); + card_num = dev - xpds_devs; + + buffer = kmalloc (skb->len + sizeof(struct frhdr), GFP_ATOMIC); + if (buffer == NULL) { + printk (KERN_ERR "%s: failed to allocate buffer in xpds_dlci_transmit()\n", xpds_devs[card_num].name); + return -ENOMEM; + } + hdr = buffer; + ptr = xpds_dlci_add_fr_header(skb, dev, ntohs(skb->protocol), hdr); + + if (xpds_data[card_num].bridged_ethernet) { + memcpy(buffer + ptr, skb->data, + sizeof(struct ethhdr)); + ptr += sizeof(struct ethhdr); + } + memcpy(buffer + ptr, + skb->data + sizeof(struct ethhdr), + skb->len - sizeof(struct ethhdr)); + len = ptr + skb->len - sizeof(struct ethhdr); + + rc = xpds_tx(buffer, len, dev); + kfree (buffer); + + if (rc) { + if (rc != -EBUSY) xpds_data[card_num].stats.tx_errors++; + } else { + xpds_data[card_num].stats.tx_packets++; + dev_kfree_skb(skb); + } + + dprintk(KERN_DEBUG "xpds_dlci_transmit done\n"); + return rc; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-encap-fr.h linux/drivers/net/xpds/xpds-encap-fr.h --- v2.2.17/drivers/net/xpds/xpds-encap-fr.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-encap-fr.h Sun Oct 15 21:57:15 2000 @@ -0,0 +1,105 @@ +/* + * Copyright 2000, Xpeed, Inc. + * fr.h $Revision: 1.10 $ + * License to copy and distribute is GNU General Public License, version 2. + * Some code adapted from Mike McLagen's /usr/include/linux/if_frad.h in + * Linux kernels 2.0-2.2. + */ + +#ifndef XPDS_ENCAP_FR_H +#define XPDS_ENCAP_FR_H + +#include +#include +#include +#include "xpds-softnet.h" + +#ifndef CONFIG_DLCI_MAX +#define CONFIG_DLCI_MODULE 1 +#define CONFIG_DLCI_MAX 8 +#define CONFIG_DLCI_COUNT 24 +#endif + +#define FRAD_STATION_CPE 0x0000 +#define FRAD_STATION_NODE 0x0001 + +#define FRAD_TX_IGNORE_CIR 0x0001 +#define FRAD_RX_ACCOUNT_CIR 0x0002 +#define FRAD_DROP_ABORTED 0x0004 +#define FRAD_BUFFERIF 0x0008 +#define FRAD_STATS 0x0010 +#define FRAD_MCI 0x0100 +#define FRAD_AUTODLCI 0x8000 +#define FRAD_VALID_FLAGS 0x811F + +#define FRAD_CLOCK_INT 0x0001 +#define FRAD_CLOCK_EXT 0x0000 + +/* these are the fields of an RFC 1490 header */ +struct frhdr { + u8 addr_control[2] __attribute__ ((packed)); + u8 control __attribute__ ((packed)); + + /* for IP packets, this can be the NLPID */ + u8 pad __attribute__ ((packed)); + + u8 NLPID __attribute__ ((packed)); + u8 OUI[3] __attribute__ ((packed)); + u16 PID __attribute__ ((packed)); + +#define IP_NLPID pad +} __attribute__ ((packed)); + +/* see RFC 1490 for the definition of the following */ +#define FRAD_I_UI 0x03 + +#define FRAD_P_PADDING 0x00 +#define FRAD_P_Q933 0x08 +#define FRAD_P_SNAP 0x80 +#define FRAD_P_CLNP 0x81 +#define FRAD_P_IP 0xCC + +#define FRAD_OUI_BRIDGED_0 0x00 +#define FRAD_OUI_BRIDGED_1 0x80 +#define FRAD_OUI_BRIDGED_2 0xc2 + +#define FRAD_PID 0x0007 + +struct frad_local { + short dlci[CONFIG_DLCI_MAX]; + + /* fields for LMI messages */ + int liv_send_sequence; + int liv_receive_sequence; + int remote_liv_send_sequence; + int remote_liv_receive_sequence; + int new_liv_send_sequence; + int pvc_active[CONFIG_DLCI_MAX]; + int pvc_new[CONFIG_DLCI_MAX]; + int no_initiate_lmi; + int message_number; + +}; + +extern void xpds_dlci_receive(struct sk_buff *skb, struct net_device *dev); +extern int xpds_dlci_transmit(struct sk_buff *skb, struct net_device *dev); + +#define XPDS_DEFAULT_DLCI 16 +#define XPDS_DEFAULT_DLCI_CR 0 /* 0 or 2 are the possible values */ + +#define XPDS_DLCI_LMI_LT_OR_NT (-1) +#define XPDS_DLCI_LMI_NONE 0 +#define XPDS_DLCI_LMI_LT 1 +#define XPDS_DLCI_LMI_NT 2 +#define XPDS_DLCI_LMI_NT_BIDIRECTIONAL 3 + +typedef struct dlci_lmi_timer_data_t { + struct net_device *dev; + int dlci_num; +} dlci_lmi_timer_data_t; + +void xpds_dlci_install_lmi_timer (int i, struct net_device *dev); +void xpds_dlci_remove_lmi_timer (int i, struct net_device *dev); + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-fsm.c linux/drivers/net/xpds/xpds-fsm.c --- v2.2.17/drivers/net/xpds/xpds-fsm.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-fsm.c Sun Oct 15 21:57:15 2000 @@ -0,0 +1,790 @@ +/* + * Copyright 1998, 1999, 2000 Xpeed, Inc. + * xpds-fsm.c, $Revision: 1.2 $ + * License to copy and distribute is GNU General Public License, version 2. + */ +#ifdef DEBUG +#define dprintk if (xpds_debug_level & DEBUG_FSM) printk +#else +#define dprintk if (0) printk +#endif + +#ifndef __KERNEL__ +#define __KERNEL__ 1 +#endif +#ifndef MODULE +#define MODULE 1 +#endif + +#define __NO_VERSION__ 1 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#if ! defined (CONFIG_PCI) +#error "CONFIG_PCI is not defined" +#endif + +#include "xpds-reg.h" +#include "xpds-softnet.h" +#include "xpds.h" + +/* + * Time periods in milliseconds. + */ +#define JIFFIES_COUNT(t) ((t)*HZ/1000?(t)*HZ/1000:1) + +#define T1 JIFFIES_COUNT(15000) +#define T2 JIFFIES_COUNT(3) +#define T3 JIFFIES_COUNT(40) +#define T4 JIFFIES_COUNT(6000) +#define T5 JIFFIES_COUNT(1000) +#define T6 JIFFIES_COUNT(6000) +#define T7 JIFFIES_COUNT(40) +#define T8 JIFFIES_COUNT(24) +#define T9 JIFFIES_COUNT(40) +#define T10 JIFFIES_COUNT(40) +#define T11 JIFFIES_COUNT(9) +#define T12 JIFFIES_COUNT(5500) +#define T13 JIFFIES_COUNT(15000) +#define T14 JIFFIES_COUNT(1/2) + +static unsigned long timer_limits[15] = { + 0, T1, T2, T3, T4, T5, T6, T7, + T8, T9, T10, T11, T12, T13, T14 +}; + +static unsigned long timers[15]; + +#define MODE_LT 0 +#define MODE_NT 1 + +/* + * States + */ +#define FSM_LT_RECEIVE_RESET 0 +#define FSM_LT_AWAKE_ERROR 1 +#define FSM_LT_DEACTIVATED 2 +#define FSM_LT_RESET_FOR_LOOP 3 +#define FSM_LT_ALERTING 4 +#define FSM_LT_WAIT_FOR_TN 5 +#define FSM_LT_AWAKE 6 +#define FSM_LT_EC_TRAINING 7 +#define FSM_LT_EC_CONVERGED 8 +#define FSM_LT_EQ_TRAINING 9 +#define FSM_LT_LINE_ACTIVE 10 +#define FSM_LT_PENDING_TRANSPARENT 11 +#define FSM_LT_TRANSPARENT 12 +#define FSM_LT_ST_DEACTIVATED 13 +#define FSM_LT_PENDING_DEACTIVATION 14 +#define FSM_LT_LOSS_OF_SYNC 15 +#define FSM_LT_LOSS_OF_SIGNAL 16 +#define FSM_LT_TEAR_DOWN_ERROR 17 +#define FSM_LT_TEST 18 +#define FSM_LT_TEAR_DOWN 19 + +#define FSM_NT_RECEIVE_RESET 0 +#define FSM_NT_PENDING_TIMING 1 +#define FSM_NT_DEACTIVATED 2 +#define FSM_NT_IOM_AWAKED 3 +#define FSM_NT_ALERTING 4 +#define FSM_NT_EC_TRAINING 5 +#define FSM_NT_EQ_TRAINING 6 +#define FSM_NT_WAIT_FOR_SF 7 +#define FSM_NT_SYNCHRONIZED_1 8 +#define FSM_NT_SYNCHRONIZED_2 9 +#define FSM_NT_WAIT_FOR_ACT 10 +#define FSM_NT_TRANSPARENT 11 +#define FSM_NT_ALERTING_1 12 +#define FSM_NT_EC_TRAINING_1 13 +#define FSM_NT_PEND_DEACT_ST 14 +#define FSM_NT_ERROR_ST 15 +#define FSM_NT_PEND_RECEIVE_RES 16 +#define FSM_NT_PEND_DEACT_U 17 +#define FSM_NT_TEST 18 +#define FSM_NT_EC_TRAINING_AL 19 +#define FSM_NT_WAIT_FOR_SF_AL 20 +#define FSM_NT_ANALOG_LOOP_BACK 21 + +static int lt_state = FSM_LT_TEST; +static int nt_state = FSM_NT_RECEIVE_RESET; + +/* + * Commands (written to TXCI in MCR) + */ +#define CMD_NULL (~0) + +#define CMD_LT_DR 0x00 +#define CMD_LT_RES 0x01 +#define CMD_LT_LTD 0x03 +#define CMD_LT_RES1 0x04 +#define CMD_LT_SSP 0x05 +#define CMD_LT_DT 0x06 +#define CMD_LT_UAR 0x07 +#define CMD_LT_AR 0x08 +#define CMD_LT_ARL 0x0a +#define CMD_LT_AR0 0x0d +#define CMD_LT_DC 0x0f + +#define CMD_NT_TIMING 0x00 +#define CMD_NT_RESET 0x01 +#define CMD_NT_DU 0x03 +#define CMD_NT_EI1 0x04 +#define CMD_NT_SSP 0x05 +#define CMD_NT_DT 0x06 +#define CMD_NT_AR 0x08 +#define CMD_NT_ARL 0x0a +#define CMD_NT_AI 0x0c +#define CMD_NT_DI 0x0f + +#define TXCI_VAL(cmd,channels) (((cmd) & XPDS_MCR_TXCI__MASK) | \ + (channels) | \ + XPDS_MCR_TXCI__PMD_ENABLE | \ + XPDS_MCR_TXCI__PMD_RESQ) +/* + * Indications (read from RXCI in MCR) + */ +#define IND_LT_NULL (~0) +#define IND_LT_DEAC 0x01 +#define IND_LT_FJ 0x02 +#define IND_LT_HI 0x03 +#define IND_LT_RSY 0x04 +#define IND_LT_EI2 0x05 +#define IND_LT_INT 0x06 +#define IND_LT_UAI 0x07 +#define IND_LT_AR 0x08 +#define IND_LT_ARM 0x09 +#define IND_LT_EI3 0x0b +#define IND_LT_AI 0x0c +#define IND_LT_LSL 0x0d +#define IND_LT_DI 0x0f + +#define IND_NT_NULL (~0) +#define IND_NT_DR 0x00 +#define IND_NT_FJ 0x02 +#define IND_NT_EI1 0x04 +#define IND_NT_INT 0x06 +#define IND_NT_PU 0x07 +#define IND_NT_AR 0x08 +#define IND_NT_ARL 0x0a +#define IND_NT_AI 0x0c +#define IND_NT_AIL 0x0e +#define IND_NT_DC 0x0f + +typedef struct { + int state; + u32 rxci; + int timer_start_1; + int timer_start_2; + u32 txci; + int timer_end; + int next_state; +} state_t; + +static state_t lt_states[] = { + { FSM_LT_RECEIVE_RESET, IND_LT_LSL, -1, -1, CMD_NULL, -1, FSM_LT_AWAKE_ERROR }, + { FSM_LT_AWAKE_ERROR, IND_LT_AR, 9, -1, CMD_NULL, 9, FSM_LT_EC_TRAINING }, + { FSM_LT_TEST, IND_LT_DEAC, -1, -1, CMD_LT_DR, -1, FSM_LT_DEACTIVATED }, + { FSM_LT_DEACTIVATED, IND_LT_DI, -1, -1, CMD_NULL, -1, FSM_LT_ALERTING }, + { FSM_LT_RESET_FOR_LOOP, IND_LT_DI, 2, -1, CMD_NULL, 2, FSM_LT_ALERTING }, + { FSM_LT_ALERTING, IND_LT_DI, 1, 2, CMD_LT_AR, 2, FSM_LT_WAIT_FOR_TN }, + { FSM_LT_WAIT_FOR_TN, IND_LT_DI, -1, -1, CMD_NULL, -1, FSM_LT_AWAKE }, + { FSM_LT_AWAKE, IND_LT_AR, 1, -1, CMD_LT_AR, -1, FSM_LT_EC_TRAINING }, + { FSM_LT_EC_TRAINING, IND_LT_AR, 5, -1, CMD_NULL, 5, FSM_LT_EC_CONVERGED }, + { FSM_LT_EC_CONVERGED, IND_LT_ARM, 6, -1, CMD_LT_ARL, 6, FSM_LT_EQ_TRAINING }, + { FSM_LT_EQ_TRAINING, IND_LT_ARM, -1, -1, CMD_NULL, -1, FSM_LT_LINE_ACTIVE }, + { FSM_LT_LINE_ACTIVE, IND_LT_UAI | IND_LT_FJ, -1, -1, CMD_LT_AR0, -1, FSM_LT_PENDING_TRANSPARENT }, + { FSM_LT_PENDING_TRANSPARENT, IND_LT_UAI | IND_LT_FJ, 8, -1, CMD_NULL, 8, FSM_LT_TRANSPARENT }, + { FSM_LT_ST_DEACTIVATED, IND_LT_AR | IND_LT_UAI, -1, -1, CMD_LT_AR0, -1, FSM_LT_LINE_ACTIVE }, + { FSM_LT_LOSS_OF_SIGNAL, IND_LT_LSL, -1, -1, CMD_LT_RES1, -1, FSM_LT_RECEIVE_RESET }, + { FSM_LT_LOSS_OF_SYNC, IND_LT_RSY, -1, -1, CMD_LT_RES1, -1, FSM_LT_TEAR_DOWN_ERROR }, + { FSM_LT_TEAR_DOWN_ERROR, IND_LT_EI3 | IND_LT_RSY, -1, -1, CMD_NULL, -1, FSM_LT_RECEIVE_RESET }, + { FSM_LT_PENDING_DEACTIVATION, IND_LT_DEAC, 10, -1, CMD_NULL, 10, FSM_LT_TEAR_DOWN }, + { FSM_LT_TEAR_DOWN, IND_LT_DEAC, -1, -1, CMD_NULL, -1, FSM_LT_DEACTIVATED }, +}; + +static state_t nt_states[] = { + { FSM_NT_RECEIVE_RESET, IND_NT_DR, 7, -1, CMD_NT_DI, 7, FSM_NT_PENDING_TIMING }, + { FSM_NT_TEST, IND_NT_DR, -1, -1, CMD_NT_DI, -1, FSM_NT_PENDING_TIMING }, + { FSM_NT_PENDING_TIMING, IND_NT_DC, 14, -1, CMD_NULL, 14, FSM_NT_DEACTIVATED }, + { FSM_NT_DEACTIVATED, IND_NT_DC, -1, -1, CMD_NT_TIMING, -1, FSM_NT_IOM_AWAKED }, + { FSM_NT_IOM_AWAKED, IND_NT_PU, -1, -1, CMD_NULL, -1, FSM_NT_ALERTING }, + { FSM_NT_ALERTING, IND_NT_DC, 1, 11, CMD_NT_AR, 11, FSM_NT_EC_TRAINING }, + { FSM_NT_EC_TRAINING, IND_NT_DC, 12, -1, CMD_NULL, 12, FSM_NT_SYNCHRONIZED_1 }, + { FSM_NT_EQ_TRAINING, IND_NT_DC, -1, -1, CMD_NULL, -1, FSM_NT_WAIT_FOR_SF }, + { FSM_NT_EQ_TRAINING, IND_NT_DC, -1, -1, CMD_NULL, 1, FSM_NT_PEND_RECEIVE_RES }, + { FSM_NT_WAIT_FOR_SF, IND_NT_DC, -1, -1, CMD_NULL, -1, FSM_NT_PEND_RECEIVE_RES }, + { FSM_NT_SYNCHRONIZED_1, IND_NT_AR, -1, -1, CMD_NULL, -1, FSM_NT_SYNCHRONIZED_2 }, + { FSM_NT_SYNCHRONIZED_2, IND_NT_AR, -1, -1, CMD_NT_AI, -1, FSM_NT_WAIT_FOR_ACT }, + { FSM_NT_WAIT_FOR_ACT, IND_NT_AR, -1, -1, CMD_NULL, -1, FSM_NT_TRANSPARENT }, + { FSM_NT_TRANSPARENT, IND_NT_AI, -1, -1, CMD_NULL, -1, FSM_NT_ERROR_ST }, + { FSM_NT_ERROR_ST, IND_NT_AR, -1, -1, CMD_NULL, -1, FSM_NT_PEND_RECEIVE_RES }, + { FSM_NT_PEND_RECEIVE_RES, IND_NT_EI1, 13, -1, CMD_NULL, 13, FSM_NT_RECEIVE_RESET }, +}; + +#define LT_NUM_STATES (sizeof (lt_states) / sizeof (*lt_states)) +#define NT_NUM_STATES (sizeof (nt_states) / sizeof (*nt_states)) + +static int +get_state_index (int st, int ltnt) +{ + int i; + + switch (ltnt) { + case MODE_LT: for (i = 0; i < LT_NUM_STATES; i ++) { + if (lt_states[i].state == st) return i; + } + break; + case MODE_NT: for (i = 0; i < NT_NUM_STATES; i ++) { + if (nt_states[i].state == st) return i; + } + break; + } + dprintk (KERN_ERR "Unknown state %d\n", st); + return 0; +} + +static void +set_timers (int state_index, int ltnt) +{ + switch (ltnt) { + case MODE_LT: if (lt_states[state_index].timer_start_1 >= 0) { + timers[lt_states[state_index].timer_start_1] = jiffies; + } + if (lt_states[state_index].timer_start_2 >= 0) { + timers[lt_states[state_index].timer_start_2] = jiffies; + } + break; + case MODE_NT: if (nt_states[state_index].timer_start_1 >= 0) { + timers[nt_states[state_index].timer_start_1] = jiffies; + } + if (nt_states[state_index].timer_start_2 >= 0) { + timers[nt_states[state_index].timer_start_2] = jiffies; + } + break; + } +} + +static void +write_txci (int txci, int channels, int card_num) +{ + u32 val; + + dprintk (KERN_DEBUG "write_txci (0x%x, %d)\n", txci, card_num); + xpds_read_control_register_quiet (card_num, XPDS_MCR_TXCI, + &val, XPDS_MAIN); + + val &= ~0xf; + val |= TXCI_VAL (txci, channels); + + xpds_write_control_register_quiet (card_num, XPDS_MCR_TXCI, + val, XPDS_MAIN); +} + +static void +set_txci (int state_index, int channels, int card_num, int ltnt) +{ + switch (ltnt) { + case MODE_LT: if (lt_states[state_index].txci != CMD_NULL) { + write_txci (lt_states[state_index].txci, channels, card_num); + } + break; + case MODE_NT: if (nt_states[state_index].txci != CMD_NULL) { + write_txci (nt_states[state_index].txci, channels, card_num); + } + break; + } +} + +/* lt */ +static int +check_state_lt (int state_index, int channels, int card_num) +{ + int i; + u32 val; + + if (xpds_data[card_num].rxci_interrupt_received) { + /* lock against interrupts? */ + xpds_data[card_num].rxci_interrupt_received = 0; + xpds_read_control_register_quiet (card_num, XPDS_MCR_RXCI, + &val, XPDS_MAIN); + val &= XPDS_MCR_RXCI__MASK; + /* unlock? */ + } else { + val = IND_LT_NULL; + } + + if (val != lt_states[state_index].rxci && val != IND_LT_NULL) { + dprintk (KERN_DEBUG "%s RXCI = 0x%01x, expected 0x%01x\n", + xpds_devs[card_num].name, val, lt_states[state_index].rxci); + } + + if (lt_state == FSM_LT_AWAKE) { + switch (val) { + case IND_LT_UAI: + dprintk (KERN_DEBUG "AWAKE/UAI -> PENDING_TRANSPARENT\n"); + return FSM_LT_PENDING_TRANSPARENT; + case IND_LT_ARM: + dprintk (KERN_DEBUG "AWAKE/ARM -> EQ_TRAINING\n"); + return FSM_LT_EQ_TRAINING; + case IND_LT_DI: + dprintk (KERN_DEBUG "AWAKE/DI -> TEST/RES\n"); + write_txci (CMD_LT_RES, channels, card_num); + return FSM_LT_TEST; + case IND_LT_EI3: + dprintk (KERN_DEBUG "AWAKE/EI3 -> TEST/RES\n"); + write_txci (CMD_LT_RES, channels, card_num); + return FSM_LT_TEST; + default: + write_txci (CMD_LT_AR, channels, card_num); + return FSM_LT_AWAKE; + } + } else if (lt_state == FSM_LT_DEACTIVATED) { + switch (val) { + case IND_LT_AR: + dprintk (KERN_DEBUG "DEACTIVATED/AR -> AWAKE/AR\n"); + write_txci (CMD_LT_AR, channels, card_num); + return FSM_LT_AWAKE; + case IND_LT_ARM: + dprintk (KERN_DEBUG "DEACTIVATED/ARM -> EQ_TRAINING\n"); + return FSM_LT_EQ_TRAINING; + case IND_LT_EI3: + dprintk (KERN_DEBUG "DEACTIVATED/EI3 -> TEST/RES\n"); + write_txci (CMD_LT_RES, channels, card_num); + return FSM_LT_TEST; + case IND_LT_DI: + dprintk (KERN_DEBUG "DEACTIVATED/DI -> AWAKE/AR\n"); + write_txci (CMD_LT_AR, channels, card_num); + return FSM_LT_AWAKE; + default: + dprintk (KERN_DEBUG "DEACTIVATED/* -> AWAKE/AR\n"); + write_txci (CMD_LT_AR, channels, card_num); + return FSM_LT_AWAKE; + } + } else if (lt_state == FSM_LT_EC_TRAINING) { + switch (val) { + case IND_LT_UAI: + dprintk (KERN_DEBUG "EC_TRAINING/UAI -> PENDING_TRANSPARENT\n"); + return FSM_LT_PENDING_TRANSPARENT; + case IND_LT_AI: + dprintk (KERN_DEBUG "EC_TRAINING/AI -> TRANSPARENT\n"); + return FSM_LT_TRANSPARENT; + default: + break; + } + } else if (lt_state == FSM_LT_EC_CONVERGED) { + switch (val) { + case IND_LT_UAI: + dprintk (KERN_DEBUG "EC_CONVERGED/UAI -> PENDING_TRANSPARENT\n"); + return FSM_LT_PENDING_TRANSPARENT; + case IND_LT_AI: + dprintk (KERN_DEBUG "EC_CONVERGED/AI -> TRANSPARENT\n"); + return FSM_LT_TRANSPARENT; + default: + break; + } + } else if (lt_state == FSM_LT_EQ_TRAINING) { + switch (val) { + case IND_LT_UAI: + dprintk (KERN_DEBUG "EQ_TRAINING/UAI -> PENDING_TRANSPARENT\n"); + return FSM_LT_PENDING_TRANSPARENT; + case IND_LT_AI: + dprintk (KERN_DEBUG "EQ_TRAINING/AI -> TRANSPARENT\n"); + return FSM_LT_TRANSPARENT; + case IND_LT_EI3: + dprintk (KERN_DEBUG "EQ_TRAINING/EI3 -> TEST/RES\n"); + write_txci (CMD_LT_RES, channels, card_num); + return FSM_LT_TEST; + case IND_LT_DI: + dprintk (KERN_DEBUG "EQ_TRAINING/DI -> AWAKE/AR\n"); + write_txci (CMD_LT_AR, channels, card_num); + return FSM_LT_AWAKE; + default: + if (val != IND_LT_NULL) dprintk (KERN_DEBUG "EQ_TRAINING/0x%01x\n", val); + return FSM_LT_EQ_TRAINING; + } + } else if (lt_state == FSM_LT_PENDING_TRANSPARENT) { + switch (val) { + case IND_LT_RSY: + dprintk (KERN_DEBUG "PENDING_TRANSPARENT/RSY -> WAIT_FOR_TN/RES1\n"); + write_txci (CMD_LT_RES1, channels, card_num); + return FSM_LT_WAIT_FOR_TN; + case IND_LT_AI: + dprintk (KERN_DEBUG "PENDING_TRANSPARENT/AI -> TRANSPARENT\n"); + return FSM_LT_TRANSPARENT; + case IND_LT_LSL: + dprintk (KERN_DEBUG "PENDING_TRANSPARENT/LSL -> RECEIVE_RESET/RES1\n"); + write_txci (CMD_LT_RES1, channels, card_num); + return FSM_LT_RECEIVE_RESET; + default: + return FSM_LT_PENDING_TRANSPARENT; + } + } else if (lt_state == FSM_LT_RECEIVE_RESET) { + switch (val) { + case IND_LT_AR: + dprintk (KERN_DEBUG "RECEIVE_RESET/AR -> AWAKE\n"); + return FSM_LT_AWAKE; + case IND_LT_DI: + dprintk (KERN_DEBUG "RECEIVE_RESET/DI -> DEACTIVATED/AR\n"); + write_txci (CMD_LT_AR, channels, card_num); + return FSM_LT_DEACTIVATED; + default: + break; + } + } else if (lt_state == FSM_LT_TEAR_DOWN_ERROR) { + switch (val) { + case IND_LT_LSL: + dprintk (KERN_DEBUG "TEAR_DOWN_ERROR/LSL -> RECEIVE_RESET\n"); + return FSM_LT_RECEIVE_RESET; + default: + break; + } + } else if (lt_state == FSM_LT_TEST) { + switch (val) { + case IND_LT_DEAC: + dprintk (KERN_DEBUG "TEST/DEAC -> DEACTIVATED/DR\n"); + write_txci (CMD_LT_DR, channels, card_num); + return FSM_LT_DEACTIVATED; + case IND_LT_DI: + dprintk (KERN_DEBUG "TEST/DI -> DEACTIVATED/DC\n"); + write_txci (CMD_LT_DC, channels, card_num); + return FSM_LT_DEACTIVATED; + default: + break; + } + } else if (lt_state == FSM_LT_TRANSPARENT) { + switch (val) { + case IND_LT_RSY: + dprintk (KERN_DEBUG "TRANSPARENT/RSY -> TEAR_DOWN_ERROR/RES1\n"); + write_txci (CMD_LT_RES1, channels, card_num); + return FSM_LT_TEAR_DOWN_ERROR; + case IND_LT_LSL: + dprintk (KERN_DEBUG "TRANSPARENT/LSL -> RECEIVE_RESET\n"); + return FSM_LT_RECEIVE_RESET; + default: + break; + } + } else if (lt_state == FSM_LT_WAIT_FOR_TN) { + switch (val) { + case IND_LT_AR: + dprintk (KERN_DEBUG "WAIT_FOR_TN/AR -> AWAKE/AR\n"); + write_txci (CMD_LT_AR, channels, card_num); + return FSM_LT_AWAKE; + case IND_LT_EI3: + dprintk (KERN_DEBUG "WAIT_FOR_TN/EI3 -> TEST/RES\n"); + write_txci (CMD_LT_RES, channels, card_num); + return FSM_LT_TEST; + case IND_LT_DI: + dprintk (KERN_DEBUG "WAIT_FOR_TN/DI -> TEST/RES\n"); + write_txci (CMD_LT_RES, channels, card_num); + return FSM_LT_TEST; + default: + break; + } + } + + for (i = state_index; + lt_states[i].state == lt_states[state_index].state; i ++) { + int timer_done = 0; + + if (lt_states[i].timer_end < 0) { + timer_done = 1; + } else if (jiffies - timers[lt_states[i].timer_end] >= + timer_limits[lt_states[i].timer_end]) { + dprintk (KERN_DEBUG "%s timer %d expired\n", + xpds_devs[card_num].name, lt_states[i].timer_end); + timer_done = 1; + } + + if (timer_done) return lt_states[i].next_state; + } + return lt_states[state_index].state; +} + +/* nt */ +static int +check_state_nt (int state_index, int channels, int card_num) +{ + int i; + u32 val; + + if (xpds_data[card_num].rxci_interrupt_received) { + /* lock ? */ + xpds_data[card_num].rxci_interrupt_received = 0; + xpds_read_control_register_quiet (card_num, XPDS_MCR_RXCI, + &val, XPDS_MAIN); + val &= XPDS_MCR_RXCI__MASK; + /* unlock ? */ + } else { + val = IND_NT_NULL; + } + + if (val != nt_states[state_index].rxci && val != IND_NT_NULL) { + dprintk (KERN_DEBUG "%s RXCI = 0x%01x, expected 0x%01x\n", + xpds_devs[card_num].name, val, nt_states[state_index].rxci); + } + + if (nt_state == FSM_NT_DEACTIVATED) { + switch (val) { + case IND_NT_AR: + dprintk (KERN_DEBUG "DEACTIVATED/AR -> SYNCHRONIZED_2/AI\n"); + write_txci (CMD_NT_AI, channels, card_num); + return FSM_NT_SYNCHRONIZED_2; + case IND_NT_PU: + dprintk (KERN_DEBUG "DEACTIVATED/PU -> IOM_AWAKED/TIMING\n"); + write_txci (CMD_NT_TIMING, channels, card_num); + return FSM_NT_IOM_AWAKED; + default: + return FSM_NT_DEACTIVATED; + } + } else if (nt_state == FSM_NT_IOM_AWAKED) { + switch (val) { + case IND_NT_DC: + dprintk (KERN_DEBUG "IOM_AWAKED/DC -> ALERTING/AR\n"); + write_txci (CMD_NT_AR, channels, card_num); + return FSM_NT_ALERTING; + default: + dprintk (KERN_DEBUG "IOM_AWAKED/* -> ALERTING/AR\n"); + write_txci (CMD_NT_AR, channels, card_num); + return FSM_NT_IOM_AWAKED; + } + } else if (nt_state == FSM_NT_ALERTING) { + switch (val) { + case IND_NT_AR: + dprintk (KERN_DEBUG "ALERTING/AR -> SYNCHRONIZED_2/AI\n"); + write_txci (CMD_NT_AI, channels, card_num); + return FSM_NT_SYNCHRONIZED_2; + default: + return FSM_NT_ALERTING; + } + } else if (nt_state == FSM_NT_EC_TRAINING) { + if (val == IND_NT_AR) { + dprintk (KERN_DEBUG "EC_TRAINING/AR -> WAIT_FOR_ACT/AI\n"); + write_txci (CMD_NT_AI, channels, card_num); + return FSM_NT_WAIT_FOR_ACT; + } + } else if (nt_state == FSM_NT_SYNCHRONIZED_1) { + if (val == IND_NT_AR) { + dprintk (KERN_DEBUG "SYNCHRONIZED_1/AR -> SYNCHRONIZED_2/AI\n"); + write_txci (CMD_NT_AI, channels, card_num); + return FSM_NT_SYNCHRONIZED_2; + } + } else if (nt_state == FSM_NT_SYNCHRONIZED_2) { + switch (val) { + case IND_NT_AR: + dprintk (KERN_DEBUG "SYNCHRONIZED_2/AR -> WAIT_FOR_ACT/AI\n"); + write_txci (CMD_NT_AI, channels, card_num); + return FSM_NT_WAIT_FOR_ACT; + case IND_NT_AI: + dprintk (KERN_DEBUG "SYNCHRONIZED_2/AI -> TRANSPARENT\n"); + return FSM_NT_TRANSPARENT; + case IND_NT_DR: + dprintk (KERN_DEBUG "SYNCHRONIZED_2/DR -> PEND_DEACT_ST/DI\n"); + write_txci (CMD_NT_DI, channels, card_num); + return FSM_NT_PEND_DEACT_ST; + default: + if (val != IND_NT_NULL) dprintk (KERN_DEBUG "SYNCHRONIZED_2/0x%01x\n", val); + return FSM_NT_SYNCHRONIZED_2; + } + } else if (nt_state == FSM_NT_WAIT_FOR_ACT) { + switch (val) { + case IND_NT_AI: + dprintk (KERN_DEBUG "WAIT_FOR_ACT/AI -> TRANSPARENT\n"); + return FSM_NT_TRANSPARENT; + case IND_NT_DR: + write_txci (CMD_NT_DI, channels, card_num); + dprintk (KERN_DEBUG "WAIT_FOR_ACT/DI -> PEND_DEACT_ST\n"); + return FSM_NT_PEND_DEACT_ST; + case IND_NT_AR: + dprintk (KERN_DEBUG "WAIT_FOR_ACT/AR -> WAIT_FOR_ACT/AI\n"); + write_txci (CMD_NT_AI, channels, card_num); + return FSM_NT_WAIT_FOR_ACT; + default: + /* write_txci (CMD_NT_AI, channels, card_num); */ + return FSM_NT_WAIT_FOR_ACT; + } + } else if (nt_state == FSM_NT_TRANSPARENT) { + switch (val) { + case IND_NT_AR: + dprintk (KERN_DEBUG "TRANSPARENT/AR -> ERROR_ST\n"); + return FSM_NT_ERROR_ST; + case IND_NT_DR: + write_txci (CMD_NT_DI, channels, card_num); + dprintk (KERN_DEBUG "TRANSPARENT/DR -> PEND_DEACT_ST\n"); + return FSM_NT_PEND_DEACT_ST; + default: + return FSM_NT_TRANSPARENT; + } + } + + if (val == IND_NT_AR) { + dprintk (KERN_DEBUG "*/AR -> SYNCHRONIZED_2/AI\n"); + write_txci (CMD_NT_AI, channels, card_num); + return FSM_NT_SYNCHRONIZED_2; + } + + for (i = state_index; + nt_states[i].state == nt_states[state_index].state; i ++) { + int timer_done = 0; + + if (nt_states[i].timer_end < 0) { + timer_done = 1; + } else if (jiffies - timers[nt_states[i].timer_end] >= + timer_limits[nt_states[i].timer_end]) { + dprintk (KERN_DEBUG "%s timer %d expired\n", + xpds_devs[card_num].name, nt_states[i].timer_end); + timer_done = 1; + } + + if (timer_done) return nt_states[i].next_state; + } + return nt_states[state_index].state; +} + +/* lt */ +int +xpds_fsm_lt (int card_num, int channels, int guard_time) +{ + u32 guard; + + dprintk (KERN_DEBUG "xpds_fsm_lt (%d) (LT - line termination)\n", card_num); + + guard = jiffies + guard_time * HZ; + + /* + * Reset + */ + xpds_data[card_num].rxci_interrupt_received = 0; + xpds_write_control_register (card_num, XPDS_MCR_TXCI, + TXCI_VAL (CMD_LT_RES, channels), XPDS_MAIN); + /* + * Unreset + */ + xpds_write_control_register (card_num, XPDS_MCR_TXCI, + TXCI_VAL (CMD_LT_DR, channels), XPDS_MAIN); + + lt_state = FSM_LT_TEST; + + dprintk (KERN_DEBUG "waiting for RXCI interrupt\n"); + while (! xpds_data[card_num].rxci_interrupt_received && + jiffies < guard) { + schedule (); + } + + guard = jiffies + guard_time * HZ; + + /* + * For each state set the timers, set the TXCI value, + * then loop, checking for transition. We want to + * get into the transparent state. + */ + while (lt_state != FSM_LT_TRANSPARENT) { + int state_index, new_state; + + dprintk (KERN_DEBUG "%s state %d\n", xpds_devs[card_num].name, lt_state); + state_index = get_state_index (lt_state, MODE_LT); + set_timers (state_index, MODE_LT); + set_txci (state_index, channels, card_num, MODE_LT); + + do { + new_state = check_state_lt (state_index, channels, card_num); + if (guard_time > 0 && jiffies >= guard) { + dprintk (KERN_ERR "%s FSM guard timer (%d seconds) expired in state %d\n", xpds_devs[card_num].name, guard_time, lt_state); + return -ETIME; + } + schedule (); + } while (new_state == lt_state); + + lt_state = new_state; + guard = jiffies + guard_time * HZ; + } + + dprintk (KERN_DEBUG "state %d == TRANSPARENT\n", lt_state); + + return 0; +} + +/* nt */ +int +xpds_fsm_nt (int card_num, int channels, int guard_time) +{ + u32 guard; + + dprintk (KERN_DEBUG "xpds_fsm_nt (%d) (NT - network termination)\n", card_num); + + guard = jiffies + guard_time * HZ; + + /* + * Reset + */ + xpds_data[card_num].rxci_interrupt_received = 0; + xpds_write_control_register (card_num, XPDS_MCR_TXCI, + TXCI_VAL (CMD_NT_RESET, channels), XPDS_MAIN); + /* + * Unreset + */ + xpds_write_control_register (card_num, XPDS_MCR_TXCI, + TXCI_VAL (CMD_NT_DI, channels), XPDS_MAIN); + + nt_state = FSM_NT_TEST; + + dprintk (KERN_DEBUG "waiting for RXCI interrupt\n"); + while ( ! xpds_data[card_num].rxci_interrupt_received && + jiffies < guard) { + schedule (); + } + + guard = jiffies + guard_time * HZ; + + /* + * For each state set the timers, set the TXCI value, + * then loop, checking for transition. We want to + * get into the transparent state. + */ + while (nt_state != FSM_NT_TRANSPARENT) { + int state_index, new_state; + + dprintk (KERN_DEBUG "%s state %d\n", xpds_devs[card_num].name, nt_state); + state_index = get_state_index (nt_state, MODE_NT); + set_timers (state_index, MODE_NT); + set_txci (state_index, channels, card_num, MODE_NT); + + do { + new_state = check_state_nt (state_index, channels, card_num); + if (guard_time > 0 && jiffies >= guard) { + dprintk (KERN_ERR "%s FSM guard timer (%d seconds) expired in state %d\n", xpds_devs[card_num].name, guard_time, nt_state); + return -ETIME; + } + schedule (); + } while (new_state == nt_state); + + nt_state = new_state; + guard = jiffies + guard_time * HZ; + } + + dprintk (KERN_DEBUG "state %d == TRANSPARENT\n", nt_state); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-fsm.h linux/drivers/net/xpds/xpds-fsm.h --- v2.2.17/drivers/net/xpds/xpds-fsm.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-fsm.h Sun Oct 15 21:57:15 2000 @@ -0,0 +1,12 @@ +/* + * Copyright 1998, 1999, 2000 Xpeed, Inc. + * xpds-fsm.h, $Revision: 1.2 $ + * License to copy and distribute is GNU General Public License, version 2. + */ +#ifndef XPDS_FSM_H +#define XPDS_FSM_H 1 + +int xpds_fsm_nt (int card_num, int channels, int guard_time); +int xpds_fsm_lt (int card_num, int channels, int guard_time); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-reg.h linux/drivers/net/xpds/xpds-reg.h --- v2.2.17/drivers/net/xpds/xpds-reg.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-reg.h Sun Oct 15 21:57:15 2000 @@ -0,0 +1,220 @@ +/* + * Copyright 1998, 1999, 2000 Xpeed, Inc. + * xpds-reg.h, $Revision: 1.2 $ + * License to copy and distribute is GNU General Public License, version 2. + */ +#ifndef XPDS_REG_H +#define XPDS_REG_H 1 + +/* + * Main control registers + */ +#define XPDS_MCR_CONFIG 0x00 +#define XPDS_MCR_TEST 0x04 +#define XPDS_MCR_MASK_SET 0x08 +#define XPDS_MCR_MASK_CLR 0x0c +#define XPDS_MCR_INT_SET 0x10 +#define XPDS_MCR_INT_CLR 0x14 +#define XPDS_MCR_GPIO_SET 0x18 +#define XPDS_MCR_GPIO_CLR 0x1c +#define XPDS_MCR_TXCFG 0x20 +#define XPDS_MCR_RXCFG 0x24 +#define XPDS_MCR_PACKH 0x28 +#define XPDS_MCR_PACKL 0x2c +#define XPDS_MCR_TXCI 0x30 +#define XPDS_MCR_RXCI 0x34 +#define XPDS_MCR_DBG_ADDR 0x38 +#define XPDS_MCR_DBG 0x3c + +#define XPDS_MCR_INT_MASK_SET XPDS_MCR_MASK_SET +#define XPDS_MCR_INT_MASK_CLR XPDS_MCR_MASK_CLR +#define XPDS_MCR_INT_STATUS_SET XPDS_MCR_INT_SET +#define XPDS_MCR_INT_STATUS_CLR XPDS_MCR_INT_CLR +#define XPDS_MCR_TX_CONFIG XPDS_MCR_TXCFG +#define XPDS_MCR_RX_CONFIG XPDS_MCR_RXCFG + +#define XPDS_MCR_CONFIG__REVISION_MASK 0xe0 +#define XPDS_MCR_CONFIG__MODE_NORMAL 0x00 +#define XPDS_MCR_CONFIG__MODE_LOOPBACK 0x18 +#define XPDS_MCR_CONFIG__CONFIG_MASK 0x07 + +#define XPDS_MCR_TEST__BIT_CLK_EN 0x10 +#define XPDS_MCR_TEST__CLK_DIV_4 0x00 +#define XPDS_MCR_TEST__CLK_DIV_8 0x02 +#define XPDS_MCR_TEST__CLK_DIV_16 0x04 +#define XPDS_MCR_TEST__CLK_DIV_32 0x06 +#define XPDS_MCR_TEST__CLK_DIV_64 0x08 +#define XPDS_MCR_TEST__SEL_PMD_CLK 0x01 + +#define XPDS_MCR_MASK__RX_FIFO 0x01 +#define XPDS_MCR_MASK__TX_FIFO 0x02 +#define XPDS_MCR_MASK__RX_DMA 0x04 +#define XPDS_MCR_MASK__TX_DMA 0x08 +#define XPDS_MCR_MASK__PCI_ERROR 0x10 +#define XPDS_MCR_MASK__EXT 0x20 +#define XPDS_MCR_MASK__RXCI 0x40 + +#define XPDS_MCR_INT__RX_FIFO 0x01 +#define XPDS_MCR_INT__TX_FIFO 0x02 +#define XPDS_MCR_INT__RX_DMA 0x04 +#define XPDS_MCR_INT__TX_DMA 0x08 +#define XPDS_MCR_INT__PCI_ERROR 0x10 +#define XPDS_MCR_INT__EXT 0x20 +#define XPDS_MCR_INT__RXCI 0x40 +#define XPDS_MCR_INT__INT 0x80 + +#define XPDS_MCR_GPIO__GP_MASK 0x0f +#define XPDS_MCR_GPIO__GP_SEPROM_CS 0x01 +#define XPDS_MCR_GPIO__GP_SEPROM_SK 0x02 +#define XPDS_MCR_GPIO__GP_SEPROM_DO 0x04 +#define XPDS_MCR_GPIO__GP_SEPROM_DI 0x08 +#define XPDS_MCR_GPIO__GP_FPGA_NT 0x00 +#define XPDS_MCR_GPIO__GP_FPGA_LT 0x01 +#define XPDS_MCR_GPIO__GP_ASIC_ACT_LED 0x02 +#define XPDS_MCR_GPIO__GP_ASIC_LINK_LED 0x08 +#define XPDS_MCR_GPIO__GP_SDSL_ACT_LED 0x08 +#define XPDS_MCR_GPIO__GP_FPGA_LT_NT 0x01 +#define XPDS_MCR_GPIO__GP_FPGA_TX_LED 0x02 +#define XPDS_MCR_GPIO__GP_FPGA_RX_LED 0x04 +#define XPDS_MCR_GPIO__OE_MASK 0xf0 +#define XPDS_MCR_GPIO__OE_SEPROM_CS 0x10 +#define XPDS_MCR_GPIO__OE_SEPROM_SK 0x20 +#define XPDS_MCR_GPIO__OE_SEPROM_DO 0x40 +#define XPDS_MCR_GPIO__OE_SEPROM_DI 0x80 +#define XPDS_MCR_GPIO__OE_ASIC_ACT_LED 0x20 +#define XPDS_MCR_GPIO__OE_ASIC_LINK_LED 0x80 +#define XPDS_MCR_GPIO__OE_SDSL_ACT_LED 0x80 +#define XPDS_MCR_GPIO__OE_FPGA_LT_NT 0x10 +#define XPDS_MCR_GPIO__OE_FPGA_TX_LED 0x20 +#define XPDS_MCR_GPIO__OE_FPGA_RX_LED 0x40 + +#define XPDS_MCR_TXCFG__TRANS 0x01 +#define XPDS_MCR_TXCFG__ENABLE 0x02 +#define XPDS_MCR_TXCFG__FILL 0x04 +#define XPDS_MCR_TXCFG__SKIP_CRC 0x08 +#define XPDS_MCR_TXCFG__CRC 0x10 +#define XPDS_MCR_TXCFG__BIT_REV_CRC 0x20 +#define XPDS_MCR_TXCFG__BIT_REV_DATA 0x40 +#define XPDS_MCR_TXCFG__SWAP_CRC 0x80 + +#define XPDS_MCR_RXCFG__TRANS 0x01 +#define XPDS_MCR_RXCFG__ENABLE 0x02 +#define XPDS_MCR_RXCFG__IGNORE_CRC 0x04 +#define XPDS_MCR_RXCFG__NO_CRC 0x08 +#define XPDS_MCR_RXCFG__CRC 0x10 +#define XPDS_MCR_RXCFG__BIT_REV_CRC 0x20 +#define XPDS_MCR_RXCFG__BIT_REV_DATA 0x40 +#define XPDS_MCR_RXCFG__SWAP_CRC 0x80 + +#define XPDS_MCR_TXCI__PMD_ENABLE 0x80 +#define XPDS_MCR_TXCI__PMD_CONFIG_MASK 0x60 +#define XPDS_MCR_TXCI__PMD_CONFIG_B1 0x00 +#define XPDS_MCR_TXCI__PMD_CONFIG_B2 0x20 +#define XPDS_MCR_TXCI__PMD_CONFIG_B1B2 0x40 +#define XPDS_MCR_TXCI__PMD_CONFIG_B1B2D 0x60 +#define XPDS_MCR_TXCI__PMD_RESQ 0x10 +#define XPDS_MCR_TXCI__MASK 0x0f + +#define XPDS_MCR_RXCI__PMD_ACTIVE 0x40 +#define XPDS_MCR_RXCI__MASK 0x0f + +/* + * FIFO control registers + */ +#define XPDS_FCR_CONFIG 0x00 +#define XPDS_FCR_INC 0x04 +#define XPDS_FCR_STAT 0x08 +#define XPDS_FCR_TAG 0x0c + +#define XPDS_FCR_STATUS XPDS_FCR_STAT + +#define XPDS_FCR_CONFIG__RESET 0x01 +#define XPDS_FCR_CONFIG__PTR_MASK 0x06 + +#define XPDS_FCR_INC__NEXT 0x01 + +#define XPDS_FCR_STAT__LAST 0x80 +#define XPDS_FCR_STAT__SIZE_MASK 0x1f + +#define XPDS_FCR_TAG__MASK 0x0f + +/* + * DMA + */ +#define XPDS_DMA_CONFIG 0x00 +#define XPDS_DMA_GO 0x04 +#define XPDS_DMA_DESC 0x08 +#define XPDS_DMA_SET_MASK 0x0c +#define XPDS_DMA_CLR_MASK 0x10 +#define XPDS_DMA_SET_STAT 0x14 +#define XPDS_DMA_CLR_STAT 0x18 +#define XPDS_DMA_STAT_ADDR 0x1c +#define XPDS_DMA_BUF_ADDR 0x20 +#define XPDS_DMA_DBG_ADDR 0x24 +#define XPDS_DMA_DBG 0x28 + +#define XPDS_DMA_MASK_SET XPDS_DMA_SET_MASK +#define XPDS_DMA_MASK_CLR XPDS_DMA_CLR_MASK +#define XPDS_DMA_STAT_SET XPDS_DMA_SET_STAT +#define XPDS_DMA_STAT_CLR XPDS_DMA_CLR_STAT + +#define XPDS_DMA_CONFIG__TEST_ENABLE 0x08 +#define XPDS_DMA_CONFIG__BURST_ENABLE 0x04 +#define XPDS_DMA_CONFIG__RESET 0x02 +#define XPDS_DMA_CONFIG__ENABLE 0x01 + +#define XPDS_DMA_GO__HUNT 0x01 + +#define XPDS_DMA_DESC__SW_GO 0x80000000 +#define XPDS_DMA_DESC__HW_GO 0x40000000 +#define XPDS_DMA_DESC__NEXT_VALID 0x20000000 +#define XPDS_DMA_DESC__PACKET_TAG_MASK 0x000f0000 +#define XPDS_DMA_DESC__PACKET_TAG_OK 0x00000000 +#define XPDS_DMA_DESC__PACKET_TAG_CRC 0x00010000 +#define XPDS_DMA_DESC__PACKET_TAG_BOUNDARY_VIOLATION 0x00020000 +#define XPDS_DMA_DESC__PACKET_TAG_LONG 0x00040000 +#define XPDS_DMA_DESC__PACKET_TAG_ABORT 0x00050000 +#define XPDS_DMA_DESC__PACKET_TAG_OVERFLOW 0x00080000 +#define XPDS_DMA_DESC__PACKET_LENGTH_MASK 0x0000ffff + +#define XPDS_DMA_MASK__FLOW 0x20 +#define XPDS_DMA_MASK__CRC 0x10 +#define XPDS_DMA_MASK__LONG 0x08 +#define XPDS_DMA_MASK__ABORT 0x04 +#define XPDS_DMA_MASK__DONE 0x01 + +#define XPDS_DMA_STAT__FLOW 0x20 +#define XPDS_DMA_STAT__CRC 0x10 +#define XPDS_DMA_STAT__LONG 0x08 +#define XPDS_DMA_STAT__ABORT 0x04 +#define XPDS_DMA_STAT__DONE 0x01 + +/* + * Auxiliary registers (8032 for SDSL) + */ +#define XPDS_AUX_CONTROL 0x00 +#define XPDS_AUX_WRITE_ADDR 0x04 +#define XPDS_AUX_WRITE_DATA 0x08 +#define XPDS_AUX_READ_DATA 0x04 +#define XPDS_AUX_READ_ADDR 0x08 +#define XPDS_AUX_MAILBOX_DATA 0x0c + +#define XPDS_AUX_MAILBOX__HANDSHAKE 0x80 +#define XPDS_AUX_MAILBOX__WRITE_BOOTDATA 0x00 +#define XPDS_AUX_MAILBOX__WRITE_MAC_ADDR 0x01 +#define XPDS_AUX_MAILBOX__WRITE_HARDWARE_VERSION 0x02 +#define XPDS_AUX_MAILBOX__WRITE_FIRMWARE_VERSION 0x03 +#define XPDS_AUX_MAILBOX__WRITE_PHYSICAL_MODE 0x04 +#define XPDS_AUX_MAILBOX__READ_MAC_ADDR 0x05 +#define XPDS_AUX_MAILBOX__READ_HARDWARE_VERSION 0x06 +#define XPDS_AUX_MAILBOX__READ_FIRMWARE_VERSION 0x07 +#define XPDS_AUX_MAILBOX__READ_PHYSICAL_MODE 0x08 +#define XPDS_AUX_MAILBOX__WRITE_TEST_MODE 0x09 +#define XPDS_AUX_MAILBOX__CLEAR_IRQ 0x0a +#define XPDS_AUX_MAILBOX__READ_PHYSICAL_STATE 0x0b + +#define XPDS_AUX_MAILBOX__NIC_WRITE_DEBUG_PORT 0x0d +#define XPDS_AUX_MAILBOX__NIC_WRITE_IRQ_TYPE 0x0e +#define XPDS_AUX_MAILBOX__NIC_WRITE_EXIT_CODE 0x0f + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-sdsl.c linux/drivers/net/xpds/xpds-sdsl.c --- v2.2.17/drivers/net/xpds/xpds-sdsl.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-sdsl.c Sun Oct 15 21:57:15 2000 @@ -0,0 +1,965 @@ +/* + * Copyright 1999, 2000 Xpeed, Inc. + * xpds-sdsl.c, $Revision: 1.7 $ + * License to copy and distribute is GNU General Public License, version 2. + */ +#ifdef DEBUG +#define dprintk if (xpds_debug_level & DEBUG_MAIN) printk +#define ddprintk if ((xpds_debug_level & (DEBUG_MAIN | DEBUG_DETAILED)) == (DEBUG_MAIN | DEBUG_DETAILED)) printk +#else +#define dprintk if (0) printk +#define ddprintk if (0) printk +#endif + +#ifndef __KERNEL__ +#define __KERNEL__ 1 +#endif +#ifndef MODULE +#define MODULE 1 +#endif + +#define __NO_VERSION__ 1 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "xpds-encap-fr.h" +#include + +#include + +#include +#include +#include + +#if ! defined (CONFIG_PCI) +#error "CONFIG_PCI is not defined" +#endif + +#include "xpds.h" +#include "xpds-reg.h" + +#define AUX_CONTROL 0x0 +#define AUX_WRITE_ADDR 0x4 +#define AUX_WRITE_DATA 0x8 +#define AUX_READ_DATA 0x4 +#define AUX_READ_ADDR 0x8 +#define AUX_MAILBOX 0xc + +#define AUX_CONTROL__BUSY 0x08 + +#define ASIC_FLASHSIZE 0x8000 +#define FPGA_FLASHSIZE 0x10000 + +/* + * Using __inline__ produces bugs. + */ +#define __inline__ + +#define aux_busy_wait(card_num,n) \ + do { \ + u32 wait_until_abw = jiffies + (n) * HZ; \ + for (;;) { \ + u32 val_d; \ + int rc_abw; \ + rc_abw = xpds_read_control_register_quiet (card_num, AUX_CONTROL, &val_d, AUX); \ + if (rc_abw > 0) return rc_abw; \ + if (! (val_d & AUX_CONTROL__BUSY) ) break; \ + schedule_if_no_interrupt (card_num); \ + if (jiffies > wait_until_abw) return 5; \ + } \ + } while (0) + +#define flash_addr_control(card_num,addr,ctrl) \ + do { \ + int rc_fac; \ + rc_fac = xpds_write_control_register_quiet (card_num, AUX_WRITE_ADDR, (addr), AUX); \ + if (rc_fac > 0) return rc_fac; \ + rc_fac = xpds_write_control_register_quiet (card_num, AUX_CONTROL, (ctrl), AUX); \ + if (rc_fac > 0) return rc_fac; \ + aux_busy_wait (card_num, 1); \ + } while (0) + +#define flash_data_control(card_num,data,ctrl) \ + do { \ + int rc_fdc; \ + rc_fdc = xpds_write_control_register_quiet (card_num, AUX_WRITE_DATA, (data), AUX); \ + if (rc_fdc > 0) return rc_fdc; \ + rc_fdc = xpds_write_control_register_quiet (card_num, AUX_CONTROL, (ctrl), AUX); \ + if (rc_fdc > 0) return rc_fdc; \ + aux_busy_wait (card_num, 1); \ + } while (0) + +__inline__ int +xpds_reset_flash (int card_num) +{ + flash_addr_control (card_num, 0, 0x106); + flash_data_control (card_num, 0xff, 0x105); + return 0; +} + +__inline__ static int +set_flash_read_mode (int card_num) +{ + flash_addr_control (card_num, 0, 0x106); + flash_data_control (card_num, 0, 0x105); + return 0; +} + +__inline__ int +xpds_read_flash_byte (int card_num, u32 address, u8 *valuep) +{ + u32 val; + int rc; + + rc = set_flash_read_mode (card_num); + if (rc > 0) return rc; + + address &= 0xffff; + + flash_addr_control (card_num, address, 0x106); + flash_data_control (card_num, 0xaa, 0x104); + + /* will this work on a big-endian computer? */ + rc = xpds_read_control_register_quiet (card_num, + AUX_READ_DATA, &val, AUX); + if (rc > 0) return rc; + + *valuep = val; + + ddprintk ("flash[%04x]->%02x\n", address, *valuep); + return 0; +} + +__inline__ int +xpds_write_flash_byte (int card_num, u32 address, u8 value) +{ + int rc, done, count; + u8 rval; + + rc = xpds_reset_flash (card_num); + if (rc > 0) return rc; + + address &= 0xffff; + + for (count = 0, done = 0; ! done && count < 100; ) { + + /* program setup command */ + flash_addr_control (card_num, address, 0x106); + flash_data_control (card_num, 0x40, 0x105); + + /* program command */ + flash_addr_control (card_num, address, 0x106); + flash_data_control (card_num, value, 0x105); + + udelay (10); + + /* program verify command */ + flash_addr_control (card_num, address, 0x106); + flash_data_control (card_num, 0xc0, 0x105); + + udelay (6); + + /* read back */ + rc = xpds_read_flash_byte (card_num, address, &rval); + + if (rval == value) { + done = 1; + } else { + count ++; + } + } + if (! done) { + printk (KERN_ERR "write_flash_byte (%d, %04lx, %02x) failed (rval = %02x)\n", card_num, (unsigned long) address, value, rval); + return 6; + } + + ddprintk ("%02x->flash[%04x]\n", value, address); + + return 0; +} + +__inline__ int +xpds_verify_flash (int card_num, u8 *buffer, u8 expected_byte, int length) +{ + int i; + int rc; + + for (i = 0; i < length; i ++) { + u8 byte, ex_byte; + + rc = xpds_read_flash_byte (card_num, i, &byte); + ex_byte = ((buffer != NULL) ? buffer[i] : expected_byte); + if (byte != ex_byte) { + printk (KERN_ERR "xpds_verify_flash() failed at %04x (got %02x, expected %02x)\n", i, byte, ex_byte); + return 6; + } + } + return -1; +} + +__inline__ int +xpds_erase_flash (int card_num) +{ + int i, verified = 0, done = 0, rc; + int flashsize; + + /* write all zeros */ + flashsize = xpds_data[card_num].is_fpga ? + FPGA_FLASHSIZE : ASIC_FLASHSIZE; + for (i = 0; i < flashsize; i ++) { + rc = xpds_write_flash_byte (card_num, i, 0); + if (rc > 0) { + printk (KERN_ERR "%s: writing 0 to flash byte %04x during erase failed\n", xpds_devs[card_num].name, i); + return rc; + } + schedule (); + } + + rc = xpds_verify_flash (card_num, NULL, 0, flashsize); + if (rc > 0) return rc; + + /* bulk erase 1000 times */ + + for (i = 0; i < 1000; ) { + u32 wait_until; + int j; + + /* erase setup */ + flash_addr_control (card_num, 0, 0x106); + flash_data_control (card_num, 0x20, 0x105); + + /* erase */ + flash_addr_control (card_num, 0, 0x106); + flash_data_control (card_num, 0x20, 0x105); + + /* delay 10ms */ + wait_until = jiffies + 10 * HZ / 1000; + while (jiffies < wait_until) { + schedule (); + } + + /* verify that each byte is 0xff */ + for (j = verified; j < flashsize; j ++) { + u32 val; + u8 byte; + + /* erase verify */ + flash_addr_control (card_num, (j & 0xffff), 0x106); + flash_data_control (card_num, 0xa0, 0x105); + udelay (6); + + /* read data */ + flash_addr_control (card_num, (j & 0xffff), 0x106); + flash_data_control (card_num, 0, 0x104); + + rc = xpds_read_control_register (card_num, AUX_READ_DATA, &val, AUX); + byte = val; + if (rc > 0 || byte != 0xff) { + done = 0; + verified = j; + i ++; + break; + } else { + done = 1; + } + } + /* + printk ("i = %d, verified = %04x, done = %d\n", + i, verified, done); + */ + + if (done) break; + } + if (i >= 1000) { + ddprintk ("xpds_erase_flash() failed\n"); + return 6; + } + + xpds_reset_flash (card_num); + ddprintk ("xpds_erase_flash() succeeded\n"); + + rc = xpds_verify_flash (card_num, NULL, 0xff, flashsize); + if (rc > 0) { + printk (KERN_ERR "xpds_verify_flash () during erase failed\n"); + return rc; + } + + return 0; +} + +/* + * IRQ types for value returned by using XPDS_MBX_WRITE_IRQTYPE + * with xpds_mailbox_read(). + */ +typedef enum { /* Codes for physical layer i/o */ + XPDS_SDSL_CMD_FAILED, /* Physical layer command failed */ + XPDS_SDSL_CMD_COMPLETED, /* Physical layer command completed successfully */ + XPDS_SDSL_CMD_TIMEOUT, /* Physical layer command timed out */ + XPDS_SDSL_FLASH_ERASE_ERROR, /* Flash could not be erased */ + XPDS_SDSL_FLASH_ZERO_ERROR, /* Flash could not be zeroed out */ + XPDS_SDSL_FLASH_WRITE_ERROR, /* Flash could not be written */ + XPDS_SDSL_AUX_MODE_PCI, /* PCI is the aux bus master */ + XPDS_SDSL_AUX_MODE_NIC, /* NIC is the aux bus master */ + XPDS_SDSL_AUX_MODE_BOTH, /* Both can be aux master */ + XPDS_SDSL_RAM_ERROR, /* RAM failed a self-test */ + XPDS_SDSL_IRQTYPE_STATE_CHANGE, /* Physical layer has gone into an important state */ + XPDS_SDSL_STATE_BOOTED, /* PL State: Booted */ + XPDS_SDSL_TESTMODE_NORMAL_OPERATION, /* Return to normal operation */ + XPDS_SDSL_TESTMODE_EXTERNAL_ANALOG_LOOPBACK, /* Transmit then receive echo */ + XPDS_SDSL_TESTMODE_FOUR_LEVEL_SCR, /* Transmit a continuous stream of 4 level scrambled ones */ + XPDS_SDSL_TESTMODE_TWO_LEVEL_SCR, /* Transmit a continuous stream of 2 level scrambled ones */ + XPDS_SDSL_TESTMODE_INTERNAL_ANALOG_LOOPBACK, /* Loopback bypassing pins */ + XPDS_SDSL_TESTMODE_FORCE_LINKUP, /* Force link up so driver can start */ + XPDS_SDSL_MAX /* Not a code - Used for bounds checking */ +} xpds_sdsl_codes_t; + +typedef enum { /* Maximum 128 types total */ + /* BEGIN PCI MAILBOX */ + XPDS_MBX_WRITE_BOOTDATA, /* Write bootdata from the mailbox */ + XPDS_MBX_WRITE_MACADDR, /* Write the mac address from the mailbox */ + XPDS_MBX_WRITE_HWVER, /* Write the hardware version from the mailbox */ + XPDS_MBX_WRITE_FWVER, /* Write the firmware version from the mailbox */ + XPDS_MBX_WRITE_PHYSMODE, /* Write the physical layer mode */ + XPDS_MBX_READ_MACADDR, /* Send the mac address to the mailbox */ + XPDS_MBX_READ_HWVER, /* Send the hardware version to the mailbox */ + XPDS_MBX_READ_FWVER, /* Send the firmware version to the mailbox */ + XPDS_MBX_READ_PHYSMODE, /* Write the physical layer mode */ + XPDS_MBX_WRITE_TESTMODE, /* Put the rs8973 into a test mode */ + XPDS_MBX_CLEAR_IRQ, /* Clear the interrupt being generated */ + XPDS_MBX_READ_PHYS_STATE, /* Read the physical layer state */ + XPDS_MBX_WRITE_MFGDATE, /* 4 bytes */ + XPDS_MBX_READ_MFGDATE, + XPDS_MBX_READ_SERIALNUMBER, /* 16 bytes */ + XPDS_MBX_WRITE_SERIALNUMBER, + XPDS_MBX_READ_STAGE, + XPDS_MBX_START_BITPUMP, + XPDS_MBX_START_BITPUMP_FOR_MFG, + XPDS_MBX_READ_PHYSMODE_IN_FLASH, + XPDS_MBX_READ_PHYS_QUALITY, + XPDS_MBX_PCIMASTER_MAXTYPE, /* Types below this value are for the PCI mailbox only */ + /* BEGIN NIC MAILBOX (r/w from NIC perspective) */ + XPDS_MBX_WRITE_DEBUGPORT = 64, /* Get the NIC supplied terminal output from the mailbox */ + XPDS_MBX_WRITE_IRQTYPE, /* Get the type of irq being generated */ + XPDS_MBX_WRITE_EXITCODE, /* Write the completion code */ + XPDS_MBX_NICMASTER_MAXTYPE /* Types below this value are for NIC mailbox only */ +} xpds_mbx_t; + +/* MAILBOX BITMASKS */ +#define XPDS_MBX_PCI_HANDSHAKE_BIT 0x00000080 +#define XPDS_MBX_NIC_HANDSHAKE_BIT 0x00800000 +#define XPDS_MBX_NIC_HANDSHAKE_BIT_SHIFTED 0x00000080 + +typedef union { + u8 bytes[4]; + u32 word; +} mailbox_t; + +#define XPDS_MBX_PCI_FLAGS 0 +#define XPDS_MBX_PCI_DATA 1 +#define XPDS_MBX_NIC_FLAGS 2 +#define XPDS_MBX_NIC_DATA 3 + +#define mailbox_busy_wait(card_num,n,bit) \ + do { \ + u32 wait_until_mbw = jiffies + (n) * HZ / 1000; \ + for (;;) { \ + u32 val_mbw; \ + xpds_read_control_register_quiet (card_num, AUX_MAILBOX, &val_mbw, AUX); \ + if (val_mbw & (bit)) break; \ + schedule_if_no_interrupt (card_num); \ + if (jiffies > wait_until_mbw) { \ + printk (KERN_ERR "(val_mbw=%x,bit=%x)", val_mbw, bit);\ + return 5; \ + } \ + } \ + } while (0) + +#define mailbox_busy_wait_not(card_num,n,bit) \ + do { \ + u32 wait_until_mbw = jiffies + (n) * HZ / 1000; \ + for (;;) { \ + u32 val_mbw; \ + xpds_read_control_register_quiet (card_num, AUX_MAILBOX, &val_mbw, AUX); \ + if (! (val_mbw & (bit))) break; \ + schedule_if_no_interrupt (card_num); \ + if (jiffies > wait_until_mbw) { \ + printk (KERN_ERR "(val_mbw=%x,!bit=%x)", val_mbw, bit);\ + return 5; \ + } \ + } \ + } while (0) + + +static mailbox_t *mailbox = NULL; +/* + * Timeouts in milliseconds. + * Need a longer timeout for use with Copper Mountain when getting the + * speed assigned by the DSLAM. + */ +#define MAILBOX_WRITE_TIMEOUT (xpds_data[card_num].sdsl_speed == 0 ? 1100 :50) +#define MAILBOX_READ_TIMEOUT (xpds_data[card_num].sdsl_speed == 0 ? 1100 :50) + +__inline__ int +xpds_mailbox_write (int card_num, xpds_mbx_t transfer_type, u8 byte) +{ + if (transfer_type < XPDS_MBX_PCIMASTER_MAXTYPE) { + /* PCI mailbox flag */ + + if (mailbox == NULL || card_num >= xpds_max_cards) { + printk (KERN_ERR "mailbox problem: mailbox = %p, xpds_max_cards = %d, card_num = %d\n", mailbox, xpds_max_cards, card_num); + return 2; + } + + /* write data into data mailbox */ + mailbox[card_num].bytes[XPDS_MBX_PCI_DATA] = byte; + xpds_write_control_register (card_num, AUX_MAILBOX, mailbox[card_num].word, AUX); + + /* change transfer type and set handshake bit */ + mailbox[card_num].bytes[XPDS_MBX_PCI_FLAGS] = + transfer_type | XPDS_MBX_PCI_HANDSHAKE_BIT; + xpds_write_control_register (card_num, AUX_MAILBOX, mailbox[card_num].word, AUX); + + /* wait until data has been received */ + mailbox_busy_wait (card_num, MAILBOX_WRITE_TIMEOUT, XPDS_MBX_PCI_HANDSHAKE_BIT); + + /* clear handshake bit */ + mailbox[card_num].bytes[XPDS_MBX_PCI_FLAGS] &= + ~ XPDS_MBX_PCI_HANDSHAKE_BIT; + xpds_write_control_register (card_num, AUX_MAILBOX, mailbox[card_num].word, AUX); + + /* wait until data has been received */ + mailbox_busy_wait_not (card_num, MAILBOX_WRITE_TIMEOUT, XPDS_MBX_PCI_HANDSHAKE_BIT); + + return 0; + } else if (transfer_type < XPDS_MBX_NICMASTER_MAXTYPE) { + /* 8032 mailbox flag */ + return 2; + } else { + return 2; + } +} + +typedef struct { + u8 *bytes; + u32 size; + u32 head; + u32 tail; +} queue_t; + +static queue_t *debug_queue = NULL; +static queue_t *irq_queue = NULL; +static queue_t *exitcode_queue = NULL; + +static int +expand_queue (queue_t *q) +{ + u32 new_size; + u8 *new_bytes; + + if (q->size == 0) { + new_size = 100; + } else { + new_size = q->size * 2; + } + dprintk (KERN_DEBUG "expanding queue %p from %d bytes to %d bytes\n", + q, q->size, new_size); + new_bytes = kmalloc (new_size, GFP_ATOMIC); + if (new_bytes == NULL) { + printk (KERN_ERR "failed to increase size of queue to %d\n", new_size); + return 1; + } + if (q->size > 0) { + memcpy (new_bytes, q->bytes + q->head, q->size - q->head); + memcpy (new_bytes + q->size - q->head, q->bytes, q->head); + } + if (q->bytes != NULL) { + dprintk (KERN_DEBUG "freeing q->bytes (%p)\n", q->bytes); + kfree (q->bytes); + } + q->head = 0; + q->tail = q->size; + q->size = new_size; + q->bytes = new_bytes; + return 0; +} + +__inline__ static int +add_to_queue (queue_t *q, u8 byte) +{ + if (q == NULL) return 1; + if (q->size == 0 || (q->tail + 1) % q->size == q->head) { + int rc; + rc = expand_queue (q); + if (rc) return rc; + } + dprintk (KERN_DEBUG "adding %02x in queue %p position %d\n", + byte, q, q->tail); + q->bytes[q->tail] = byte; + q->tail ++; + q->tail %= q->size; + return 0; +} + +__inline__ static int +get_from_queue (queue_t *q, u8 *bytep) +{ + if (q == NULL) return 1; + if (q->head == q->tail) return 1; + dprintk (KERN_DEBUG "getting %02x from queue %p position %d\n", + q->bytes[q->head], q, q->head); + *bytep = q->bytes[q->head]; + q->head ++; + q->head %= q->size; + return 0; +} + +__inline__ int +xpds_mailbox_read (int card_num, xpds_mbx_t transfer_type, u8 *bytep) +{ + u32 val; + + /* check to see if NIC is the master? */ + + if (transfer_type < XPDS_MBX_PCIMASTER_MAXTYPE) { + /* change transfer type and set handshake bit */ + mailbox[card_num].bytes[XPDS_MBX_PCI_FLAGS] = + transfer_type | XPDS_MBX_PCI_HANDSHAKE_BIT; + xpds_write_control_register (card_num, AUX_MAILBOX, mailbox[card_num].word, AUX); + + /* wait until data has been received */ + mailbox_busy_wait (card_num, MAILBOX_READ_TIMEOUT, XPDS_MBX_PCI_HANDSHAKE_BIT); + + /* get data */ + xpds_read_control_register (card_num, AUX_MAILBOX, &val, AUX); + *bytep = (val & 0xff00) >> 8; + + /* clear handshake bit */ + mailbox[card_num].bytes[XPDS_MBX_PCI_FLAGS] &= + ~ XPDS_MBX_PCI_HANDSHAKE_BIT; + xpds_write_control_register (card_num, AUX_MAILBOX, mailbox[card_num].word, AUX); + + /* wait until handshake clear is received */ + mailbox_busy_wait_not (card_num, MAILBOX_READ_TIMEOUT, XPDS_MBX_PCI_HANDSHAKE_BIT); + + return 0; + } else if (transfer_type < XPDS_MBX_NICMASTER_MAXTYPE) { + queue_t *q; + int rc; + u32 wait_until; + + /* first check the appropriate queue */ + switch (transfer_type) { + case XPDS_MBX_WRITE_DEBUGPORT: + q = &(debug_queue[card_num]); break; + case XPDS_MBX_WRITE_IRQTYPE: + q = &(irq_queue[card_num]); break; + case XPDS_MBX_WRITE_EXITCODE: + q = &(exitcode_queue[card_num]); break; + default: + return 2; + } + rc = get_from_queue (q, bytep); + dprintk (KERN_DEBUG "%s: got %02x from queue (%p/%02x) (rc = %d)\n", xpds_devs[card_num].name, *bytep, q, transfer_type, rc); + if (rc == 0) return 0; + + /* not in queue, get from NIC */ + wait_until = jiffies + (MAILBOX_READ_TIMEOUT * 2) * HZ / 1000; + for (;;) { + u32 val_nic; + queue_t *q_nic; + int done = 0; + + xpds_read_control_register_quiet (card_num, AUX_MAILBOX, &val_nic, AUX); + if (val_nic & XPDS_MBX_NIC_HANDSHAKE_BIT) { + xpds_mbx_t nic_transfer_type; + u8 byte; + + nic_transfer_type = (val_nic & 0x007f0000) >> 16; + + switch (nic_transfer_type) { + case XPDS_MBX_WRITE_DEBUGPORT: + q_nic = &(debug_queue[card_num]); break; + case XPDS_MBX_WRITE_IRQTYPE: + q_nic = &(irq_queue[card_num]); break; + case XPDS_MBX_WRITE_EXITCODE: + q_nic = &(exitcode_queue[card_num]); break; + default: + q_nic = &(debug_queue[card_num]); break; + } + byte = (val_nic & 0xff000000) >> 24; + dprintk (KERN_DEBUG "%s: adding %02x to queue (%p/%02x)\n", xpds_devs[card_num].name, byte, q_nic, nic_transfer_type); + add_to_queue (q_nic, byte); + + mailbox[card_num].bytes[XPDS_MBX_NIC_FLAGS] = + transfer_type | + XPDS_MBX_NIC_HANDSHAKE_BIT_SHIFTED; + xpds_write_control_register (card_num, AUX_MAILBOX, mailbox[card_num].word, AUX); + + mailbox_busy_wait_not (card_num, MAILBOX_READ_TIMEOUT, XPDS_MBX_NIC_HANDSHAKE_BIT); + mailbox[card_num].bytes[XPDS_MBX_NIC_FLAGS] &= + ~ XPDS_MBX_NIC_HANDSHAKE_BIT_SHIFTED; + xpds_write_control_register (card_num, AUX_MAILBOX, mailbox[card_num].word, AUX); + + schedule_if_no_interrupt (card_num); + + if (nic_transfer_type == transfer_type) { + done = 1; + } + } + if (done || jiffies > wait_until) break; + } + rc = get_from_queue (q, bytep); + dprintk (KERN_DEBUG "%s: got %02x from queue (%p/%02x) (rc = %d)\n", xpds_devs[card_num].name, *bytep, q, transfer_type, rc); + if (rc == 0) return 0; + + return 1; + } else { + return 2; + } +} + +int +xpds_get_sdsl_exit_code (int card_num, u8 *bytep) +{ + int rc; + + rc = xpds_mailbox_read (card_num, XPDS_MBX_WRITE_EXITCODE, bytep); + return rc; +} + +/* + * This gets the mode in the flash memory, but the speed section of + * the mode may be a default speed instead of the actual value if the + * speed section is invalid (the SDSL card will operate at the default + * speed in this case). + */ +int +xpds_get_sdsl_mode (int card_num, u32 *val) +{ + int i, rc, rval = 0; + u8 byte = 0; + + *val = 0; + for (i = 0; i < 4; i ++) { + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_PHYSMODE, &byte); + if (rc > 0) rval = 1; + *val |= byte << ((3 - i) * 8); + } + return rval; +} + +/* + * This gets the actual mode in the flash memory. + */ +int +xpds_get_flash_sdsl_mode (int card_num, u32 *val) +{ + int i, rc, rval = 0; + u8 byte = 0; + + *val = 0; + for (i = 0; i < 4; i ++) { + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_PHYSMODE_IN_FLASH, &byte); + if (rc > 0) rval = 1; + *val |= byte << ((3 - i) * 8); + } + return rval; +} + +int +xpds_set_sdsl_mode (int card_num, u32 val) +{ + int i, rc, rval = 0; + u8 byte; + + for (i = 0; i < 4; i ++) { + byte = (val >> ((3 - i) * 8)) & 0xff; + rc = xpds_mailbox_write (card_num, XPDS_MBX_WRITE_PHYSMODE, byte); + if (rc > 0) rval = 1; + } + return rval; +} + +int +xpds_reset_sdsl (int card_num) +{ + u32 wait_until, val; + + /* reset 8032 and Rockwell */ + dprintk (KERN_DEBUG "%s: resetting the 8032\n", xpds_devs[card_num].name); + xpds_read_control_register (card_num, XPDS_MCR_TXCI, &val, MAIN); + xpds_write_control_register (card_num, XPDS_MCR_TXCI, val & 0x6f, MAIN); + xpds_read_control_register (card_num, AUX_CONTROL, &val, AUX); + xpds_write_control_register (card_num, AUX_CONTROL, val & ~0x80, AUX); + xpds_read_control_register (card_num, AUX_CONTROL, &val, AUX); + xpds_write_control_register (card_num, AUX_CONTROL, val | 0x100, AUX); + + wait_until = jiffies + 1 * HZ; + while (jiffies < wait_until) { + schedule (); + } + return 0; +} + +int +xpds_start_sdsl (int card_num) +{ + u32 wait_until, val; + + /* unreset 8032 and Rockwell */ + dprintk (KERN_DEBUG "%s: unresetting the 8032\n", xpds_devs[card_num].name); + + xpds_read_control_register (card_num, AUX_CONTROL, &val, AUX); + xpds_write_control_register (card_num, AUX_CONTROL, val & ~0x100, AUX); + + xpds_read_control_register (card_num, XPDS_MCR_TXCI, &val, MAIN); + xpds_write_control_register (card_num, XPDS_MCR_TXCI, val | 0x90, MAIN); + + xpds_read_control_register (card_num, AUX_CONTROL, &val, AUX); + xpds_write_control_register (card_num, AUX_CONTROL, val | 0x80, AUX); + + wait_until = jiffies + HZ * 1; + while (jiffies < wait_until) { + schedule (); + } + + return 0; +} + +typedef struct { + int size; + u8 *image; +} xpds_flash_image_t; + +int +xpds_install_flash_image (int card_num, xpds_flash_image_t *fd) +{ + int i, rc; + xpds_flash_image_t kfd; + u8 *image; + int flashsize; + + flashsize = xpds_data[card_num].is_fpga ? + FPGA_FLASHSIZE : ASIC_FLASHSIZE; + + printk (KERN_NOTICE "%s: resetting SDSL\n", xpds_devs[card_num].name); + rc = xpds_reset_sdsl (card_num); + if (rc > 0) { + printk (KERN_ERR "%s: SDSL reset failed\n", xpds_devs[card_num].name); + return rc; + } + printk (KERN_NOTICE "%s: resetting flash\n", xpds_devs[card_num].name); + rc = xpds_reset_flash (card_num); + if (rc > 0) { + printk (KERN_ERR "%s: flash reset failed\n", xpds_devs[card_num].name); + return rc; + } + + printk (KERN_NOTICE "%s: erasing flash\n", xpds_devs[card_num].name); + rc = xpds_erase_flash (card_num); + if (rc > 0) { + printk (KERN_ERR "%s: flash erase failed\n", xpds_devs[card_num].name); + return rc; + } + + printk (KERN_NOTICE "%s: writing flash image\n", xpds_devs[card_num].name); + copy_from_user (&kfd, fd, sizeof (kfd)); + if (kfd.size > flashsize) kfd.size = flashsize; + image = kmalloc (kfd.size, GFP_KERNEL); + if (image == NULL) return 1; + copy_from_user (image, kfd.image, kfd.size); + + for (i = 0; i < kfd.size; i ++) { + rc = xpds_write_flash_byte (card_num, i, image[i]); + if (rc > 0) { + printk (KERN_ERR "%s: flash write failed, address %04x, data %02x\n", xpds_devs[card_num].name, i, image[i]); + kfree (image); + return rc; + } + schedule (); + } + printk (KERN_NOTICE "%s: verifying flash image\n", xpds_devs[card_num].name); + rc = xpds_verify_flash (card_num, image, 0, kfd.size); + if (rc > 0) { + printk (KERN_ERR "%s: flash verify failed\n", xpds_devs[card_num].name); + kfree (image); + return rc; + } + + xpds_reset_sdsl (card_num); + xpds_start_sdsl (card_num); + + kfree (image); + return 0; +} + +int +xpds_sdsl_loopback (int card_num) +{ + int rc; + + dprintk (KERN_DEBUG "%s: setting SDSL loopback mode\n", xpds_devs[card_num].name); + rc = xpds_mailbox_write (card_num, XPDS_MBX_WRITE_TESTMODE, 0x10); + return rc; +} + +/* + * Set data like hardware version, serial number, etc. + * Only one exit code is generated for the whole thing, except for + * bytes which were unwritable (which cause additional exit codes). + */ +static int +xpds_set_sdsl_serial_data (int card_num, xpds_mbx_t transfer_type, u8 *data, + int size) +{ + int i, rc, rval = 0; + u8 ec; + + for (i = 0; i < size; i ++) { + rc = xpds_mailbox_write (card_num, transfer_type, data[i]); + if (rc > 0) { + rval = 1; + xpds_get_sdsl_exit_code (card_num, &ec); + } + } + rc = xpds_get_sdsl_exit_code (card_num, &ec); + if (rc > 0 || ec != XPDS_SDSL_CMD_COMPLETED) rval = 1; + return rval; +} + +int +xpds_set_sdsl_info (int card_num) +{ + xpds_serial_data_t *sdata; + int rc, rval = 0; + + sdata = &(xpds_data[card_num].serial_data); + + rc = xpds_set_sdsl_serial_data (card_num, XPDS_MBX_WRITE_HWVER, + sdata->hardware_version, sizeof (sdata->hardware_version)); + if (rc > 0) { + printk (KERN_ERR "%s: failed to write hardware version\n", xpds_devs[card_num].name); + rval = 1; + } + +#if REWRITE_FWVER + rc = xpds_set_sdsl_serial_data (card_num, XPDS_MBX_WRITE_FWVER, + sdata->firmware_version, sizeof (sdata->firmware_version)); + if (rc > 0) { + printk (KERN_ERR "%s: failed to write firmware version\n", xpds_devs[card_num].name); + rval = 1; + } +#else + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_FWVER, + &(sdata->firmware_version[0])); + if (rc) rval = 1; + + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_FWVER, + &(sdata->firmware_version[1])); + if (rc) rval = 1; + + if (rval) { + printk (KERN_ERR "%s: failed to read new firmware version\n", xpds_devs[card_num].name); + sdata->firmware_version[0] = 0; + sdata->firmware_version[1] = 0; + } + + printk (KERN_INFO "%s: new firmware version is %d.%d\n", + xpds_devs[card_num].name, sdata->firmware_version[0], + sdata->firmware_version[1]); +#endif + + rc = xpds_set_sdsl_serial_data (card_num, XPDS_MBX_WRITE_MFGDATE, + sdata->mfg_date, sizeof (sdata->mfg_date)); + if (rc > 0) { + printk (KERN_ERR "%s: failed to write manufacturing date\n", xpds_devs[card_num].name); + rval = 1; + } + + rc = xpds_set_sdsl_serial_data (card_num, XPDS_MBX_WRITE_MACADDR, + sdata->mac_address, sizeof (sdata->mac_address)); + if (rc > 0) { + printk (KERN_ERR "%s: failed to write MAC address\n", xpds_devs[card_num].name); + rval = 1; + } + + rc = xpds_set_sdsl_serial_data (card_num, XPDS_MBX_WRITE_SERIALNUMBER, + sdata->serial_number, sizeof (sdata->serial_number)); + if (rc > 0) { + printk (KERN_ERR "%s: failed to write serial number\n", xpds_devs[card_num].name); + rval = 1; + } + + return rval; +} + +int +xpds_sdsl_allocate (void) +{ + if (debug_queue == NULL) { + debug_queue = kmalloc (xpds_max_cards * sizeof (*debug_queue), GFP_KERNEL); + if (debug_queue == NULL) return -ENOMEM; + memset (debug_queue, 0, xpds_max_cards * sizeof (*debug_queue)); + } + if (irq_queue == NULL) { + irq_queue = kmalloc (xpds_max_cards * sizeof (*irq_queue), GFP_KERNEL); + if (irq_queue == NULL) return -ENOMEM; + memset (irq_queue, 0, xpds_max_cards * sizeof (*irq_queue)); + } + if (exitcode_queue == NULL) { + exitcode_queue = kmalloc (xpds_max_cards * sizeof (*exitcode_queue), GFP_KERNEL); + if (exitcode_queue == NULL) return -ENOMEM; + memset (exitcode_queue, 0, xpds_max_cards * sizeof (*exitcode_queue)); + } + if (mailbox == NULL) { + dprintk (KERN_DEBUG "allocating mailbox (%d * %d)\n", + xpds_max_cards, sizeof (*mailbox)); + mailbox = kmalloc (xpds_max_cards * sizeof (*mailbox), GFP_KERNEL); + if (mailbox == NULL) return -ENOMEM; + memset (mailbox, 0, xpds_max_cards * sizeof (*mailbox)); + } + return 0; +} + +int +xpds_sdsl_get_state (int card_num, u8 *state) +{ + return xpds_mailbox_read (card_num, XPDS_MBX_READ_STAGE, state); +} + +int +xpds_sdsl_cleanup (void) +{ + int i; + + for (i = 0; i < xpds_max_cards; i ++) { + if (debug_queue != NULL && debug_queue[i].bytes != NULL) kfree (debug_queue[i].bytes); + if (irq_queue != NULL && irq_queue[i].bytes != NULL) kfree (irq_queue[i].bytes); + if (exitcode_queue != NULL && exitcode_queue[i].bytes != NULL) kfree (exitcode_queue[i].bytes); + } + if (debug_queue != NULL) kfree (debug_queue); + if (irq_queue != NULL) kfree (irq_queue); + if (exitcode_queue != NULL) kfree (exitcode_queue); + if (mailbox != NULL) kfree (mailbox); + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-sdsl.h linux/drivers/net/xpds/xpds-sdsl.h --- v2.2.17/drivers/net/xpds/xpds-sdsl.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-sdsl.h Sun Oct 15 21:57:15 2000 @@ -0,0 +1,122 @@ +/* + * Copyright 1999, 2000 Xpeed, Inc. + * xpds-sdsl.h, $Revision: 1.3 $ + * License to copy and distribute is GNU General Public License, version 2. + */ + +#ifndef XPDS_SDSL_H +#define XPDS_SDSL_H 1 + +int xpds_reset_flash (int card_num); +int xpds_read_flash_byte (int card_num, u32 address, u8 *valuep); +int xpds_write_flash_byte (int card_num, u32 address, u8 value); +int xpds_verify_flash (int card_num, u8 *buffer, u8 expected_byte, int length); +int xpds_erase_flash (int card_num); + +typedef enum { /* Maximum 128 types total */ + /* BEGIN PCI MAILBOX */ +/* Write bootdata from the mailbox */ + XPDS_MBX_WRITE_BOOTDATA, + XPDS_MBX_WRITE_MACADDR, /* Write the mac address from the mailbox */ + XPDS_MBX_WRITE_HWVER, /* Write the hardware version from the mailbox */ + XPDS_MBX_WRITE_FWVER, /* Write the firmware version from the mailbox */ + XPDS_MBX_WRITE_PHYSMODE, /* Write the physical layer mode */ + XPDS_MBX_READ_MACADDR, /* Send the mac address to the mailbox */ + XPDS_MBX_READ_HWVER, /* Send the hardware version to the mailbox */ + XPDS_MBX_READ_FWVER, /* Send the firmware version to the mailbox */ + XPDS_MBX_READ_PHYSMODE, /* Write the physical layer mode */ + XPDS_MBX_WRITE_TESTMODE, /* Put the rs8973 into a test mode */ + XPDS_MBX_CLEAR_IRQ, /* Clear the interrupt being generated */ + XPDS_MBX_READ_PHYS_STATE, /* Read the physical layer state */ + XPDS_MBX_WRITE_MFGDATE, /* 4 bytes */ + XPDS_MBX_READ_MFGDATE, + XPDS_MBX_READ_SERIALNUMBER, /* 16 bytes */ + XPDS_MBX_WRITE_SERIALNUMBER, + XPDS_MBX_READ_STAGE, + XPDS_MBX_START_BITPUMP, + XPDS_MBX_START_BITPUMP_FOR_MFG, + XPDS_MBX_READ_PHYSMODE_IN_FLASH, + XPDS_MBX_READ_PHYS_QUALITY, + XPDS_MBX_PCIMASTER_MAXTYPE, /* Types below this value are for the PCI mailbox only */ + /* BEGIN NIC MAILBOX (r/w from NIC perspective) */ + XPDS_MBX_WRITE_DEBUGPORT = 64, /* Get the NIC supplied terminal output from the mailbox */ + XPDS_MBX_WRITE_IRQTYPE, /* Get the type of irq being generated */ + XPDS_MBX_WRITE_EXITCODE, /* Write the completion code */ + XPDS_MBX_NICMASTER_MAXTYPE /* Types below this value are for NIC mailbox only */ +} xpds_mbx_t; + +/* + * IRQ types for value returned by using XPDS_MBX_WRITE_IRQTYPE + * with xpds_mailbox_read(). + */ +typedef enum { /* Codes for physical layer i/o */ + XPDS_SDSL_CMD_FAILED, /* Physical layer command failed */ + XPDS_SDSL_CMD_COMPLETED, /* Physical layer command completed successfu + lly */ + XPDS_SDSL_CMD_TIMEOUT, /* Physical layer command timed out */ + XPDS_SDSL_FLASH_ERASE_ERROR, /* Flash could not be erased */ + XPDS_SDSL_FLASH_ZERO_ERROR, /* Flash could not be zeroed out */ + XPDS_SDSL_FLASH_WRITE_ERROR, /* Flash could not be written */ + XPDS_SDSL_AUX_MODE_PCI, /* PCI is the aux bus master */ + XPDS_SDSL_AUX_MODE_NIC, /* NIC is the aux bus master */ + XPDS_SDSL_AUX_MODE_BOTH, /* Both can be aux master */ + XPDS_SDSL_RAM_ERROR, /* RAM failed a self-test */ + XPDS_SDSL_IRQTYPE_STATE_CHANGE, /* Physical layer has gone into an important + state */ + XPDS_SDSL_STATE_BOOTED, /* PL State: Booted */ + XPDS_SDSL_TESTMODE_NORMAL_OPERATION, /* Return to normal operation */ + XPDS_SDSL_TESTMODE_EXTERNAL_ANALOG_LOOPBACK, /* Transmit then receive echo */ + XPDS_SDSL_TESTMODE_FOUR_LEVEL_SCR, /* Transmit a continuous stream of 4 level scrambled ones */ + XPDS_SDSL_TESTMODE_TWO_LEVEL_SCR, /* Transmit a continuous stream of 2 level scrambled ones */ + XPDS_SDSL_TESTMODE_INTERNAL_ANALOG_LOOPBACK, /* Loopback bypassing pins */ + XPDS_SDSL_TESTMODE_FORCE_LINKUP, /* Force link up so driver can st + art */ + XPDS_SDSL_MAX /* Not a code - Used for bounds c +hecking */ +} xpds_sdsl_codes_t; + +/* + * Physical layer states for value returned by mailbox read + * with XPDS_RETURN_PHYS_STATE. + */ +#define XPDS_SDSL_STATE_LOS 0x01 +#define XPDS_SDSL_STATE_LOST 0x02 +#define XPDS_SDSL_STATE_TIPRING_REVERSED 0x04 +#define XPDS_SDSL_STATE_2LEVEL_TIMER_EXPIRED 0x08 +#define XPDS_SDSL_STATE_GOOD_NOISE_MARGIN 0x10 +#define XPDS_SDSL_STATE_RESERVED 0x20 +#define XPDS_SDSL_STATE_4LEVEL 0x40 +#define XPDS_SDSL_STATE_LINKUP 0x80 + +/* + * SDSL operating mode definitions + */ +#define XPDS_SDSL_MODE__UNUSED 0xfff80000 +#define XPDS_SDSL_MODE__NT 0x00040000 +#define XPDS_SDSL_MODE__INVERT 0x00020000 +#define XPDS_SDSL_MODE__SWAP 0x00010000 +#define XPDS_SDSL_MODE__SPEED_MASK 0x0000ffff + +typedef struct { + int size; + u8 *image; +} xpds_flash_image_t; + +int xpds_mailbox_write (int card_num, xpds_mbx_t transfer_type, u8 byte); +int xpds_mailbox_read (int card_num, xpds_mbx_t transfer_type, u8 *bytep); +int xpds_get_sdsl_exit_code (int card_num, u8 *bytep); +int xpds_get_sdsl_mode (int card_num, u32 *value); +int xpds_get_flash_sdsl_mode (int card_num, u32 *value); +int xpds_set_sdsl_mode (int card_num, u32 value); +int xpds_reset_sdsl (int card_num); +int xpds_start_sdsl (int card_num); +int xpds_install_flash_image (int card_num, xpds_flash_image_t *fd); +int xpds_sdsl_loopback (int card_num); +int xpds_set_sdsl_info (int card_num); +int xpds_sdsl_allocate (void); +int xpds_sdsl_get_state (int card_num, u8 *state); +int xpds_sdsl_cleanup (void); + +#define XPDS_SDSL_MAILBOX_READ_INCOMPLETE 1000 + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds-softnet.h linux/drivers/net/xpds/xpds-softnet.h --- v2.2.17/drivers/net/xpds/xpds-softnet.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds-softnet.h Sun Oct 15 21:57:15 2000 @@ -0,0 +1,44 @@ +#ifndef XPDS_SOFT_NET_H +#define XPDS_SOFT_NET_H 1 + +/* + * 2.4 softnet api macros taken from rrunner.c + */ +#if (LINUX_VERSION_CODE < 0x02030e) +#define net_device device +#endif + +#if (LINUX_VERSION_CODE >= 0x02031b) +#define NEW_NETINIT 1 +#endif + +#define HAS_SOFT_NET 0x02032b + +#if (LINUX_VERSION_CODE < HAS_SOFT_NET) +/* + * SoftNet changes + */ +#define dev_kfree_skb_irq(a) dev_kfree_skb(a) +#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) +#define netif_stop_queue(dev) set_bit(0, &dev->tbusy) +#define net_device_stats enet_statistics + +static inline void netif_start_queue(struct net_device *dev) +{ + dev->tbusy = 0; + dev->start = 1; +} + +#define xpds_mark_net_bh(foo) mark_bh(foo) +#define xpds_if_busy(dev) dev->tbusy +#define xpds_if_running(dev) dev->start /* Currently unused. */ +#define xpds_if_down(dev) {do{dev->start = 0;}while (0);} +#else +#define NET_BH 0 +#define xpds_mark_net_bh(foo) {do{} while(0);} +#define xpds_if_busy(dev) netif_queue_stopped(dev) +#define xpds_if_running(dev) netif_running(dev) +#define xpds_if_down(dev) {do{} while(0);} +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds.c linux/drivers/net/xpds/xpds.c --- v2.2.17/drivers/net/xpds/xpds.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds.c Tue Nov 7 13:19:46 2000 @@ -0,0 +1,4023 @@ +/* + * Copyright 1998, 1999, 2000 Xpeed, Inc. + * xpds.c, $Revision: 1.33 $ + * License to copy and distribute is GNU General Public License, version 2. + */ +#ifndef VERSION_STRING +#define VERSION_STRING "release-20001009k" +#endif + +#define LT_IND_AI 0xc +#define NT_IND_AI 0xc + +#ifndef __KERNEL__ +#define __KERNEL__ 1 +#endif + +#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 + +#if ! defined (CONFIG_PCI) +#error "CONFIG_PCI is not defined" +#endif + +#include "xpds-softnet.h" +#include "xpds-reg.h" +#include "xpds-fsm.h" +#include +#include "xpds-sdsl.h" +#include "xpds-encap-fr.h" +#include "xpds.h" + +MODULE_AUTHOR("Timothy J. Lee "); +MODULE_DESCRIPTION("Xpeed 200 IDSL and 300 SDSL NIC driver (frame relay)"); + +/* + * Debugging stuff. + */ +#define DEBUG_MAIN 1 +#define DEBUG_FSM 2 +#define DEBUG_PACKET 64 +#define DEBUG_DETAILED 128 +int xpds_debug_level = 0 /* DEBUG_MAIN | DEBUG_FSM */; +MODULE_PARM(xpds_debug_level, "i"); + +#ifdef DEBUG +#define dprintk if (xpds_debug_level & DEBUG_MAIN) printk +#define dpprintk if ((xpds_debug_level & (DEBUG_MAIN | DEBUG_PACKET)) == (DEBUG_MAIN | DEBUG_PACKET)) printk +#define ddprintk if ((xpds_debug_level & (DEBUG_MAIN | DEBUG_DETAILED)) == (DEBUG_MAIN | DEBUG_DETAILED)) printk +#else +#define dprintk if (0) printk +#define dpprintk if (0) printk +#define ddprintk if (0) printk +#endif + +#define nrprintk if (net_ratelimit()) printk + +/* + * If we are loaded module for flashing, ignore error in detection. + */ +int xpds_load_for_flash = 0; +MODULE_PARM(xpds_load_for_flash, "i"); + +/* + * For loopback testing only. + */ +int xpds_asic_loopback = 0; +MODULE_PARM(xpds_asic_loopback, "i"); +int xpds_external_loopback = 0; +MODULE_PARM(xpds_external_loopback, "i"); + +/* some motherboards have 6 PCI slots... */ +#define XPDS_DEFAULT_MAX 6 +int xpds_max_cards = XPDS_DEFAULT_MAX; +MODULE_PARM(xpds_max_cards, "i"); + +/* time to wait for SDSL physical layer to come up */ +#define XPDS_SDSL_TIMEOUT 300 +int xpds_sdsl_timeout = XPDS_SDSL_TIMEOUT; +MODULE_PARM(xpds_sdsl_timeout, "i"); + +int xpds_default_dlci = XPDS_DEFAULT_DLCI; +MODULE_PARM(xpds_default_dlci, "i"); + +int xpds_default_dlci_cr = XPDS_DEFAULT_DLCI_CR; +MODULE_PARM(xpds_default_dlci_cr, "i"); + +int xpds_default_dlci_lmi = XPDS_DLCI_LMI_LT_OR_NT; +MODULE_PARM(xpds_default_dlci_lmi, "i"); + +int xpds_default_bridged = 0; +MODULE_PARM(xpds_default_bridged, "i"); + +static char *xpds_dev_name = "dsl"; +MODULE_PARM(xpds_dev_name, "s"); + +/* + * At rates below 400 Kbps, the SDSL TX DMA does not work on some + * computers. + */ +#define LOW_BIT_RATE 404 +#define TX_DMA_LOW_RATE_BUG(card_num) \ + (xpds_data[card_num].is_sdsl && \ + xpds_data[card_num].has_tx_dma_low_rate_bug && \ + xpds_data[card_num].sdsl_speed < LOW_BIT_RATE) +#define RX_DMA_LOW_RATE_BUG(card_num) \ + (xpds_data[card_num].is_sdsl && \ + xpds_data[card_num].has_rx_dma_low_rate_bug && \ + xpds_data[card_num].sdsl_speed < LOW_BIT_RATE) + +#define PCI_VENDOR_ID_XPDS 0x14b3 +#define PCI_DEVICE_ID_XPDS_1 0x0000 + +#define ALLOW_OLD_PCI_VENDOR_ID 0 +#define PCI_VENDOR_ID_XPDS_OLD 0xeeee + +/* + * Set xpds_mode by insmod. + */ +#define XPDS_MODE_B1 1 +#define XPDS_MODE_B2 2 +#define XPDS_MODE_D 4 +#define XPDS_MODE_DEFAULT 7 + +int xpds_mode = XPDS_MODE_DEFAULT; +MODULE_PARM(xpds_mode, "i"); + +/* + * Guard time for the state machines. + */ +#define DEFAULT_GUARD_TIME 15 +int xpds_guard_time = DEFAULT_GUARD_TIME; +MODULE_PARM(xpds_guard_time, "i"); + +#define RXTX_BUFFER_SIZE 2048 + +/* + * Maximum packet length that is put into a hardware register. + * Packets received by the hardware are dropped if they are + * equal to or greater in length. + */ +#define DEFAULT_MAX_PACKET_LENGTH 0x600 +u16 xpds_max_packet_length = DEFAULT_MAX_PACKET_LENGTH; +MODULE_PARM(xpds_max_packet_length, "i"); + +#define RXTX_CONTROL__SWGO 0x80000000 +#define RXTX_CONTROL__HWGO 0x40000000 +#define RXTX_CONTROL__NEXT_VALID 0x20000000 +#define RXTX_CONTROL__PACKET_TAG_OFFSET 16 +#define RXTX_CONTROL__PACKET_TAG_MASK 0xf +#define RXTX_CONTROL__PACKET_LENGTH_MASK 0xffff + +#define NUM_MAIN_CONTROL_REGISTERS 16 +#define NUM_FIFO_CONTROL_REGISTERS 16 +#define NUM_DMA_CONTROL_REGISTERS 48 +#define NUM_FIFO_DATA_REGISTERS 32 +#define NUM_AUX_REGISTERS 4 + +#define NUM_FIFO 4 +#define FIFO_SIZE (NUM_FIFO_DATA_REGISTERS / NUM_FIFO) + +xpds_data_t *xpds_data = NULL; +static int num_xpds_found = 0; + +#define XPDS_MAIN 0 +#define XPDS_RX_FIFO 2 +#define XPDS_TX_FIFO 3 +#define XPDS_RX_DMA 4 +#define XPDS_TX_DMA 5 +#define XPDS_RX_FIFO_DATA 6 +#define XPDS_TX_FIFO_DATA 7 +#define XPDS_AUX 8 + +#define MAIN XPDS_MAIN +#define RX_FIFO XPDS_RX_FIFO +#define TX_FIFO XPDS_TX_FIFO +#define RX_DMA XPDS_RX_DMA +#define TX_DMA XPDS_TX_DMA +#define RX_FIFO_DATA XPDS_RX_FIFO_DATA +#define TX_FIFO_DATA XPDS_TX_FIFO_DATA +#define AUX XPDS_AUX + +#define NAME_SIZE 16 + +#define NUM_DESC 14 + +static int xpds_init (struct net_device *dev); + +static char *xpds_names = NULL; +struct net_device *xpds_devs = NULL; + +__inline__ static int +xpds_read_control_register_internal (int xpds_num, int register_number, + u32 *value, int which, int verbose) +{ + register_number >>= 2; + + if (verbose) dprintk (KERN_DEBUG "%s: ", xpds_devs[xpds_num].name); + switch (which) { + case MAIN: + if (register_number > NUM_MAIN_CONTROL_REGISTERS || + xpds_data[xpds_num].main_control_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].main_control_registers[register_number]; + if (verbose) { + dprintk ("main_ctl[%02x]->%08x ", + register_number, *value); + } + break; + case RX_FIFO: + if (register_number > NUM_FIFO_CONTROL_REGISTERS || + xpds_data[xpds_num].rx_fifo_control_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].rx_fifo_control_registers[register_number]; + if (verbose) dprintk ("rx_fifo_ctl[%02x]->%08x ", + register_number, *value); + break; + case TX_FIFO: + if (register_number > NUM_FIFO_CONTROL_REGISTERS || + xpds_data[xpds_num].tx_fifo_control_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].tx_fifo_control_registers[register_number]; + if (verbose) dprintk ("tx_fifo_ctl[%02x]->%08x ", + register_number, *value); + break; + case RX_DMA: + if (register_number > NUM_DMA_CONTROL_REGISTERS || + xpds_data[xpds_num].rx_dma_control_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].rx_dma_control_registers[register_number]; + if (verbose) dprintk ("rx_dma_ctl[%02x]->%08x ", + register_number, *value); + break; + case TX_DMA: + if (register_number > NUM_DMA_CONTROL_REGISTERS || + xpds_data[xpds_num].tx_dma_control_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].tx_dma_control_registers[register_number]; + if (verbose) dprintk ("tx_dma_ctl[%02x]->%08x ", + register_number, *value); + break; + case RX_FIFO_DATA: + if (register_number > NUM_FIFO_DATA_REGISTERS || + xpds_data[xpds_num].rx_fifo_data_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].rx_fifo_data_registers[register_number]; + if (verbose) dprintk ("rx_fifo_data[%02x]->%08x ", + register_number, *value); + break; + case TX_FIFO_DATA: + if (register_number > NUM_FIFO_DATA_REGISTERS || + xpds_data[xpds_num].tx_fifo_data_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].tx_fifo_data_registers[register_number]; + if (verbose) dprintk ("tx_fifo_data[%02x]->%08x ", + register_number, *value); + break; + case AUX: + if (register_number > NUM_AUX_REGISTERS || + xpds_data[xpds_num].aux_registers == NULL) { + return 4; + } + *value = xpds_data[xpds_num].aux_registers[register_number]; + if (verbose) dprintk ("aux[%02x]->%08x ", + register_number, *value); + break; + default: + if (verbose) dprintk ("\n"); + return 4; + } + if (verbose) dprintk ("\n"); + return 0; +} + +__inline__ int +xpds_read_control_register (int xpds_num, int register_number, + u32 *value, int which) +{ + return xpds_read_control_register_internal (xpds_num, register_number, + value, which, 0); +} + +__inline__ int +xpds_read_control_register_verbose (int xpds_num, int register_number, + u32 *value, int which) +{ + return xpds_read_control_register_internal (xpds_num, register_number, + value, which, 1); +} + +__inline__ int +xpds_read_control_register_quiet (int xpds_num, int register_number, + u32 *value, int which) +{ + return xpds_read_control_register_internal (xpds_num, register_number, + value, which, 0); +} + +__inline__ static int +xpds_write_control_register_internal (int xpds_num, int register_number, + u32 value, int which, int verbose) +{ + register_number >>= 2; + + if (verbose) dprintk (KERN_DEBUG "%s: ", xpds_devs[xpds_num].name); + + switch (which) { + case MAIN: + if (register_number > NUM_MAIN_CONTROL_REGISTERS) { + return 4; + } + xpds_data[xpds_num].main_control_registers[register_number] = value; + if (verbose) { + dprintk ("%08x->main_ctl[%02x] ", + value, register_number); + } + break; + case RX_FIFO: + if (register_number > NUM_FIFO_CONTROL_REGISTERS) { + return 4; + } + xpds_data[xpds_num].rx_fifo_control_registers[register_number] = value; + if (verbose) dprintk ("%08x->rx_fifo_ctl[%02x] ", + value, register_number); + break; + case TX_FIFO: + if (register_number > NUM_FIFO_CONTROL_REGISTERS) { + return 4; + } + xpds_data[xpds_num].tx_fifo_control_registers[register_number] = value; + if (verbose) dprintk ("%08x->tx_fifo_ctl[%02x] ", + value, register_number); + break; + case RX_DMA: + if (register_number > NUM_DMA_CONTROL_REGISTERS) { + return 4; + } + xpds_data[xpds_num].rx_dma_control_registers[register_number] = value; + if (verbose) dprintk ("%08x->rx_dma_ctl[%02x] ", + value, register_number); + break; + case TX_DMA: + if (register_number > NUM_DMA_CONTROL_REGISTERS) { + return 4; + } + xpds_data[xpds_num].tx_dma_control_registers[register_number] = value; + if (verbose) dprintk ("%08x->tx_dma_ctl[%02x] ", + value, register_number); + break; + case RX_FIFO_DATA: + if (register_number > NUM_FIFO_DATA_REGISTERS) { + return 4; + } + xpds_data[xpds_num].rx_fifo_data_registers[register_number] = value; + if (verbose) dprintk ("%08x->rx_fifo_data[%02x] ", + value, register_number); + break; + case TX_FIFO_DATA: + if (register_number > NUM_FIFO_DATA_REGISTERS) { + if (verbose) dprintk ("\n"); + return 4; + } + xpds_data[xpds_num].tx_fifo_data_registers[register_number] = value; + if (verbose) dprintk ("%08x->tx_fifo_data[%02x] ", + value, register_number); + break; + case AUX: + if (register_number > NUM_AUX_REGISTERS) { + if (verbose) dprintk ("\n"); + return 4; + } + xpds_data[xpds_num].aux_registers[register_number] = value; + if (verbose) dprintk ("%08x->aux[%02x] ", + value, register_number); + break; + default: + if (verbose) dprintk ("\n"); + return 4; + } + if (verbose) dprintk ("\n"); + return 0; +} + +__inline__ int +xpds_write_control_register (int xpds_num, int register_number, + u32 value, int which) +{ + return xpds_write_control_register_internal (xpds_num, register_number, + value, which, 0); +} + +__inline__ int +xpds_write_control_register_verbose (int xpds_num, int register_number, + u32 value, int which) +{ + return xpds_write_control_register_internal (xpds_num, register_number, + value, which, 1); +} + +__inline__ int +xpds_write_control_register_quiet (int xpds_num, int register_number, + u32 value, int which) +{ + return xpds_write_control_register_internal (xpds_num, register_number, + value, which, 0); +} + +/* + * Return 1 if the hardware version is >= major.minor, unless + * the hardware version is the uninitialized 0xff.0xff value, + * which is assumed to be the lowest revision. Return 0 otherwise. + */ +static int +xpds_is_hardware_version (int card_num, int major, int minor) +{ + if (xpds_data[card_num].serial_data.hardware_version[0] == 0xff && + xpds_data[card_num].serial_data.hardware_version[1] == 0xff) { + return 0; + } + if (xpds_data[card_num].serial_data.hardware_version[0] > major) { + return 1; + } + if (xpds_data[card_num].serial_data.hardware_version[0] == major && + xpds_data[card_num].serial_data.hardware_version[1] >= minor) { + return 1; + } + return 0; +} + +static int +xpds_init_descriptors (int card_num) +{ + u32 bus_addr; + + dprintk (KERN_DEBUG "xpds_init_descriptors (%d)\n", card_num); + /* + * lock? + */ + + /* + * Set maximum packet length + */ + dprintk (KERN_DEBUG "setting maximum packet length to %u (0x%x)\n", + xpds_max_packet_length, xpds_max_packet_length); + xpds_write_control_register (card_num, XPDS_MCR_PACKH, + (xpds_max_packet_length >> 8) & 0xff, MAIN); + xpds_write_control_register (card_num, XPDS_MCR_PACKL, + xpds_max_packet_length & 0xff, MAIN); + + /* + * Initialize descriptor + */ + { + volatile xpds_rxtx_list_t *rx_ptr, *tx_ptr; + int i; + + rx_ptr = xpds_data[card_num].rx_dma_list; + tx_ptr = xpds_data[card_num].tx_dma_list; + for (i = 0; i < NUM_DESC; i ++) { + rx_ptr->control = + RXTX_CONTROL__NEXT_VALID | RXTX_CONTROL__HWGO; + rx_ptr = rx_ptr->next; + tx_ptr->control = + RXTX_CONTROL__NEXT_VALID; + tx_ptr = tx_ptr->next; + } + } + + /* + * Initialize pointers to receive and transmit buffers + * that were allocated on module initialization (by + * allocate_rxtx_buffers() ). + */ + bus_addr = virt_to_bus (xpds_data[card_num].rx_dma_list); + dprintk (KERN_DEBUG "%s: writing RX DMA status address %p (bus address %08x)\n", xpds_devs[card_num].name, xpds_data[card_num].rx_dma_list, bus_addr); + xpds_write_control_register (card_num, XPDS_DMA_STAT_ADDR, + bus_addr, RX_DMA); + bus_addr = virt_to_bus (xpds_data[card_num].tx_dma_list); + dprintk (KERN_DEBUG "%s: writing TX DMA status address %p (bus address %08x)\n", xpds_devs[card_num].name, xpds_data[card_num].tx_dma_list, bus_addr); + xpds_write_control_register (card_num, XPDS_DMA_STAT_ADDR, + bus_addr, TX_DMA); + xpds_data[card_num].current_rx_dma = xpds_data[card_num].rx_dma_list; + xpds_data[card_num].current_tx_dma = xpds_data[card_num].tx_dma_list; + xpds_data[card_num].current_hw_tx_dma = xpds_data[card_num].tx_dma_list; + xpds_data[card_num].current_hw_rx_dma = xpds_data[card_num].rx_dma_list; + + /* + * release lock? + */ + + return 0; +} + +static int +xpds_dma_enable (int card_num) +{ + u32 value; + + dprintk (KERN_DEBUG "xpds_dma_enable (%d)\n", card_num); + + /* + * Check SDSL speed. If speed mode had been set to 0 + * (autonegotiation mode), then the speed needs to be + * read before the DMA is enabled, in order to determine + * DMA low rate bug is applicable. + */ + if (xpds_data[card_num].is_sdsl) { + u32 waituntil = jiffies + 90 * HZ; + + do { + u32 sdsl_mode, speed_mode; + int rc; + + rc = xpds_get_sdsl_mode (card_num, &sdsl_mode); + dprintk ("%s: SDSL mode is %08x\n", + xpds_devs[card_num].name, sdsl_mode); + speed_mode = sdsl_mode & XPDS_SDSL_MODE__SPEED_MASK; + dprintk ("%s: SDSL speed is %d\n", + xpds_devs[card_num].name, speed_mode << 3); + xpds_data[card_num].sdsl_speed = speed_mode << 3; + schedule_if_no_interrupt (card_num); + } while (xpds_data[card_num].sdsl_speed == 0 && + jiffies < waituntil); + printk ("%s: SDSL speed is %d kbps.\n", + xpds_devs[card_num].name, + xpds_data[card_num].sdsl_speed); + } + + /* + * Disable all interrupts + */ + xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK, + XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW | + XPDS_DMA_MASK__LONG | XPDS_DMA_MASK__ABORT | + XPDS_DMA_MASK__CRC, RX_DMA); + xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK, + XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW | + XPDS_DMA_MASK__LONG | XPDS_DMA_MASK__ABORT | + XPDS_DMA_MASK__CRC, TX_DMA); + xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR, + 0xff /* XPDS_MCR_MASK__RX_FIFO | XPDS_MCR_MASK__TX_FIFO */, MAIN); + + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + 0xff, MAIN); + + xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt mask is %02x\n", xpds_devs[card_num].name, value); + + /* + * Enable receive and transmit DMAs. The transmit DMA is only + * enabled if we do not encounter the low bit rate bug. + */ + if (! RX_DMA_LOW_RATE_BUG (card_num) ) { + if (! xpds_data[card_num].has_rx_dma_burst_bug) { + dprintk (KERN_INFO "%s: enabling burst on RX DMA\n", + xpds_devs[card_num].name); + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, + XPDS_DMA_CONFIG__BURST_ENABLE | XPDS_DMA_CONFIG__ENABLE, + RX_DMA); + } else { + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, + XPDS_DMA_CONFIG__ENABLE, RX_DMA); + } + } + if (! TX_DMA_LOW_RATE_BUG (card_num) ) { + if (! xpds_data[card_num].has_tx_dma_burst_bug) { + dprintk (KERN_INFO "%s: enabling burst on TX DMA\n", + xpds_devs[card_num].name); + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, + XPDS_DMA_CONFIG__BURST_ENABLE | XPDS_DMA_CONFIG__ENABLE, + TX_DMA); + } else { + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, + XPDS_DMA_CONFIG__ENABLE, TX_DMA); + } + } + + /* + * Enable DMA interrupts. The transmit DMA interrupt is only + * enabled if the low bit rate bug is not encountered. + */ + if (! RX_DMA_LOW_RATE_BUG (card_num) ) { + xpds_write_control_register (card_num, XPDS_DMA_SET_MASK, + XPDS_DMA_MASK__DONE, RX_DMA); + xpds_read_control_register (card_num, XPDS_DMA_SET_STAT, + &value, RX_DMA); + dprintk (KERN_DEBUG "%s: RX DMA status is %02x\n", + xpds_devs[card_num].name, value); + } + + if (! TX_DMA_LOW_RATE_BUG (card_num) ) { + xpds_write_control_register (card_num, XPDS_DMA_SET_MASK, + XPDS_DMA_MASK__DONE, TX_DMA); + xpds_read_control_register (card_num, XPDS_DMA_SET_STAT, + &value, TX_DMA); + dprintk (KERN_DEBUG "%s: TX DMA status is %02x\n", + xpds_devs[card_num].name, value); + } + + if (xpds_data[card_num].is_sdsl) { + u32 mask; + + mask = XPDS_MCR_MASK__EXT; + if (! TX_DMA_LOW_RATE_BUG (card_num)) { + mask |= XPDS_MCR_MASK__TX_DMA; + } + if (! RX_DMA_LOW_RATE_BUG (card_num)) { + mask |= XPDS_MCR_MASK__RX_DMA; + } else { + mask |= XPDS_MCR_MASK__RX_FIFO; + } + xpds_write_control_register (card_num, + XPDS_MCR_MASK_SET, mask, MAIN); + } else { + xpds_write_control_register (card_num, XPDS_MCR_MASK_SET, + XPDS_MCR_MASK__RX_DMA | XPDS_MCR_MASK__TX_DMA | + XPDS_MCR_MASK__RXCI, MAIN); + } + xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR, + &value, MAIN); +#if DEBUG + dprintk (KERN_DEBUG "%s: interrupt mask is %02x", xpds_devs[card_num].name, value); + if (value & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO"); + if (value & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO"); + if (value & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA"); + if (value & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA"); + if (value & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR"); + if (value & XPDS_MCR_MASK__EXT) dprintk (" EXT"); + if (value & XPDS_MCR_MASK__RXCI) dprintk (" RXCI"); + dprintk ("\n"); +#endif + + /* + * Let the RX DMA begin (write to hunt bit). + * If RX DMA bug, reset and unreset the RX FIFO instead. + */ + if (RX_DMA_LOW_RATE_BUG (card_num)) { + xpds_data[card_num].current_rx_fifo = 0; + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, RX_FIFO); + udelay (20); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + 0, RX_FIFO); + } else { + xpds_write_control_register (card_num, XPDS_DMA_GO, + XPDS_DMA_GO__HUNT, RX_DMA); + } + + /* + * Reset and unreset to enable TX FIFO mode instead of + * TX DMA to work around the TX DMA bug at < 400 Kbps. + */ + if (TX_DMA_LOW_RATE_BUG (card_num)) { + xpds_data[card_num].current_tx_fifo = 0; + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, TX_FIFO); + udelay (20); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + 0, TX_FIFO); + } + + return 0; +} + +static int +xpds_dma_disable (int card_num) +{ + u32 value; + + dprintk (KERN_DEBUG "xpds_dma_disable (%d)\n", card_num); + + /* + * Reset the DMAs + */ + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, + XPDS_DMA_CONFIG__RESET, RX_DMA); + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, + XPDS_DMA_CONFIG__RESET, TX_DMA); + + /* + * Disable the DMAs + */ + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, 0x0, RX_DMA); + xpds_write_control_register (card_num, XPDS_DMA_CONFIG, 0x0, TX_DMA); + /* + * Disable the DMA interrupts + */ + xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK, + XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW, RX_DMA); + xpds_write_control_register (card_num, XPDS_DMA_CLR_MASK, + XPDS_DMA_MASK__DONE | XPDS_DMA_MASK__FLOW, TX_DMA); + xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR, + XPDS_MCR_MASK__RX_DMA | XPDS_MCR_MASK__TX_DMA, MAIN); + xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt mask is %02x\n", xpds_devs[card_num].name, value); + + return 0; +} + +#define LED_OFF 0 +#define LED_ON 1 +/* + * Turn on/off the TX or activity LED + */ +__inline__ static void +xpds_tx_led (int card_num, int on) +{ + if (xpds_data[card_num].is_fpga) { + if (on) { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_FPGA_TX_LED, MAIN ); + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_FPGA_TX_LED, MAIN ); + } else { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_FPGA_TX_LED | + XPDS_MCR_GPIO__OE_FPGA_TX_LED, MAIN ); + } + } else if (xpds_data[card_num].is_sdsl) { + if (on) { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN); + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_SDSL_ACT_LED, MAIN); + } else { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_SDSL_ACT_LED | + XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN); + } + } else { + if (on) { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN); + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_ASIC_ACT_LED, MAIN); + } else { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_ASIC_ACT_LED | + XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN); + } + } +} + +/* + * Turn on/off the RX or activity LED + */ +__inline__ static void +xpds_rx_led (int card_num, int on) +{ + if (xpds_data[card_num].is_fpga) { + if (on) { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_FPGA_RX_LED, MAIN ); + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_FPGA_RX_LED, MAIN ); + } else { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_FPGA_RX_LED | + XPDS_MCR_GPIO__OE_FPGA_RX_LED, MAIN ); + } + } else if (xpds_data[card_num].is_sdsl) { + if (on) { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN); + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_SDSL_ACT_LED, MAIN); + } else { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_SDSL_ACT_LED | + XPDS_MCR_GPIO__OE_SDSL_ACT_LED, MAIN); + } + } else { + if (on) { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN); + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_ASIC_ACT_LED, MAIN); + } else { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_ASIC_ACT_LED | + XPDS_MCR_GPIO__OE_ASIC_ACT_LED, MAIN); + } + } +} + + +/* + * Turn on the link LED + */ +__inline__ static void +xpds_link_led (int card_num, int on) +{ + if (! xpds_data[card_num].is_fpga) { + if (on) { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_ASIC_LINK_LED, MAIN); + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_ASIC_LINK_LED, MAIN); + } else { + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_ASIC_LINK_LED | + XPDS_MCR_GPIO__OE_ASIC_LINK_LED, MAIN); + } + } +} + +/* + * Resets the XPDS card, including running the PEB 2091 state machine + * into transparent mode by calling xpds_fsm(). + */ +static int +xpds_reset (int card_num) +{ + int rc; + int i; + int speed_mode; + u32 mode; + u32 value; + + dprintk (KERN_DEBUG "%s: xpds_reset\n", xpds_devs[card_num].name); + + rc = xpds_dma_disable (card_num); + if (rc != 0) return rc; + + /* + * Reset the TX FIFO, then unreset it. + */ + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, TX_FIFO); + + /* + * For each FIFO, zero the status. + */ + for (i = 0; i < NUM_FIFO; i ++ ) { + xpds_write_control_register (card_num, XPDS_FCR_STAT, + 0, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_INC, + XPDS_FCR_INC__NEXT, TX_FIFO); + } + + /* + * Reset the TX FIFO, then unreset it. + */ + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, TX_FIFO); + + /* + * Reset the RX FIFO, then unreset it. + */ + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, RX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, RX_FIFO); + + /* + * For each FIFO, zero the status. + */ + for (i = 0; i < NUM_FIFO; i ++ ) { + xpds_write_control_register (card_num, XPDS_FCR_STAT, + 0, RX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_INC, + XPDS_FCR_INC__NEXT, RX_FIFO); + } + + /* + * Reset the RX FIFO, then unreset it. + */ + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, RX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, RX_FIFO); + + /* + * Enable TX and RX HDLC + */ + xpds_write_control_register (card_num, XPDS_MCR_TXCFG, + XPDS_MCR_TXCFG__ENABLE, MAIN); + if (xpds_data[card_num].has_last_byte_bug) { + xpds_write_control_register (card_num, XPDS_MCR_RXCFG, + (xpds_data[card_num].is_fpga ? + XPDS_MCR_RXCFG__ENABLE : + XPDS_MCR_RXCFG__ENABLE | XPDS_MCR_RXCFG__NO_CRC), + MAIN); + } else { + xpds_write_control_register (card_num, XPDS_MCR_RXCFG, + XPDS_MCR_RXCFG__ENABLE, MAIN); + } + + /* + * Set mode register to normal mode. + */ + if (xpds_asic_loopback) { + dprintk (KERN_INFO "%s: setting ASIC loopback\n", xpds_devs[card_num].name); + xpds_write_control_register (card_num, XPDS_MCR_CONFIG, + XPDS_MCR_CONFIG__MODE_LOOPBACK, MAIN); + } else { + xpds_write_control_register (card_num, XPDS_MCR_CONFIG, + XPDS_MCR_CONFIG__MODE_NORMAL, MAIN); + } + + /* + * Turn on activation LED + */ + xpds_write_control_register (card_num, XPDS_MCR_TEST, 1, MAIN); + + /* + * Clear all bits in GPIO + */ + xpds_write_control_register (card_num, XPDS_MCR_GPIO_CLR, 0xff, MAIN); + + /* + * Enable GPIO outputs + */ + xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_MASK, MAIN); + + /* + * Enable NT or LT mode + */ + if (xpds_data[card_num].is_fpga) { + xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET, + (xpds_data[card_num].is_lt ? + XPDS_MCR_GPIO__GP_FPGA_LT : + XPDS_MCR_GPIO__GP_FPGA_NT) | + XPDS_MCR_GPIO__OE_MASK, + MAIN); + } + + /* + * Turn off the LEDs + */ + if (xpds_data[card_num].is_fpga) { + xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_FPGA_TX_LED | + XPDS_MCR_GPIO__GP_FPGA_RX_LED | + XPDS_MCR_GPIO__OE_FPGA_TX_LED | + XPDS_MCR_GPIO__OE_FPGA_RX_LED, MAIN); + } else { + xpds_write_control_register (card_num, XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__GP_ASIC_ACT_LED | + XPDS_MCR_GPIO__GP_ASIC_LINK_LED | + XPDS_MCR_GPIO__OE_ASIC_ACT_LED | + XPDS_MCR_GPIO__OE_ASIC_LINK_LED, MAIN); + } + + /* + * Enable interrupt which notifies a change in the indication + * code of the PEB 2091 (RXCI) or the interrupt which indicates + * a change in the status of the SDSL (EXT). + */ + if (xpds_data[card_num].is_sdsl) { + xpds_write_control_register (card_num, XPDS_MCR_MASK_SET, + XPDS_MCR_MASK__EXT, MAIN); + } else { + xpds_write_control_register (card_num, XPDS_MCR_MASK_SET, + XPDS_MCR_MASK__RXCI, MAIN); + } + xpds_read_control_register (card_num, XPDS_MCR_MASK_SET, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt mask is %02x\n", + xpds_devs[card_num].name, value); + + rc = xpds_init_descriptors (card_num); + if (rc != 0) return rc; + + mode = 0; + if (xpds_data[card_num].is_sdsl) { + u32 sdsl_mode; + + /* + * Reset and unreset the SDSL, then get the SDSL mode. + */ + rc = xpds_reset_sdsl (card_num); + if (rc != 0) return rc; + rc = xpds_start_sdsl (card_num); + if (rc != 0) return rc; + + rc = xpds_get_sdsl_mode (card_num, &sdsl_mode); + dprintk ("%s: SDSL mode is %08x\n", xpds_devs[card_num].name, sdsl_mode); + speed_mode = sdsl_mode & XPDS_SDSL_MODE__SPEED_MASK; + dprintk ("%s: SDSL speed is %d\n", xpds_devs[card_num].name, speed_mode << 3); + xpds_data[card_num].sdsl_speed = speed_mode << 3; + } else { + /* + * Take the PEB 2091 out of reset (B1, B2, and D channels for + * 144k operation). Only for IDSL card. + */ + speed_mode = xpds_data[card_num].speed_mode; + if (speed_mode & XPDS_MODE_B1) { + if (speed_mode & XPDS_MODE_B2) { + if (speed_mode & XPDS_MODE_D) { + dprintk ("%s: selecting B1B2D (144k)\n", xpds_devs[card_num].name); + mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1B2D; + } else { + dprintk ("%s: selecting B1B2 (128k)\n", xpds_devs[card_num].name); + mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1B2; + } + } else { + dprintk ("%s: selecting B1 (64k)\n", xpds_devs[card_num].name); + mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1; + } + } else if (speed_mode & XPDS_MODE_B2) { + dprintk ("%s: selecting B2 (64k)\n", xpds_devs[card_num].name); + mode |= XPDS_MCR_TXCI__PMD_CONFIG_B2; + } else { + dprintk (KERN_ERR "%s: invalid mode %d\n", xpds_devs[card_num].name, speed_mode); + dprintk ("%s: selecting B1B2D (144k)\n", xpds_devs[card_num].name); + mode |= XPDS_MCR_TXCI__PMD_CONFIG_B1B2D; + } + xpds_write_control_register (card_num, XPDS_MCR_TXCI, mode, MAIN); + } + + /* + * Set the PMD enable bit. + */ + if (! xpds_data[card_num].is_sdsl) { + xpds_read_control_register (card_num, XPDS_MCR_TXCI, &mode, MAIN); + } + mode |= XPDS_MCR_TXCI__PMD_ENABLE | XPDS_MCR_TXCI__PMD_RESQ; + xpds_write_control_register (card_num, XPDS_MCR_TXCI, mode, MAIN); + + if (xpds_data[card_num].is_sdsl) { + rc = xpds_mailbox_write (card_num, XPDS_MBX_START_BITPUMP, 0); + DELAY_HZ (3 * HZ / 2, card_num); + if (xpds_external_loopback) { + xpds_sdsl_loopback (card_num); + DELAY (2, card_num); + } + } else { + /* + * need to control state machine for non-SDSL cards + */ + if (xpds_data[card_num].is_lt) { + rc = xpds_fsm_lt (card_num, mode, xpds_guard_time); + } else { + rc = xpds_fsm_nt (card_num, mode, xpds_guard_time); + } + if (rc != 0) return rc; + } + + /* + * Turn on the link LED + */ + if (! xpds_data[card_num].is_sdsl) xpds_link_led (card_num, 1); + + /* + * Reset the FIFOs. + */ + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, + XPDS_FCR_CONFIG__RESET, RX_FIFO); + + DELAY_HZ (1, card_num); + + /* + * For each FIFO, zero the status. + */ + for (i = 0; i < NUM_FIFO; i ++ ) { + xpds_write_control_register (card_num, XPDS_FCR_STAT, + 0, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_INC, + XPDS_FCR_INC__NEXT, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_STAT, + 0, RX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_INC, + XPDS_FCR_INC__NEXT, RX_FIFO); + } + + /* + * Unreset the FIFOs. + */ + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_CONFIG, 0, RX_FIFO); + + xpds_read_control_register (card_num, XPDS_FCR_CONFIG, &value, RX_FIFO); + dprintk (KERN_DEBUG "%s: RX FIFO config register is %08x\n", + xpds_devs[card_num].name, value); + + /* + * For IDSL, physical layer is up. + * For SDSL, wait until interrupt occurs to let us know. + */ + if (! xpds_data[card_num].is_sdsl) { + struct net_device *dev; + + printk ("%s: physical link came up\n", xpds_devs[card_num].name); + xpds_data[card_num].physical_up = 1; + rc = xpds_dma_enable (card_num); + dev = &(xpds_devs[card_num]); + netif_start_queue(dev); + if (rc != 0) return rc; + } + + return 0; +} + +/* + * Called from interrupt handler to receive a packet. + */ +static void +xpds_rx (struct net_device *dev, int len, volatile u8 *buf) +{ + struct sk_buff *skb; + int card_num; + struct frad_local *fp; + short dlci; + xpds_data_t *data_ptr; + int i; + + card_num = dev - xpds_devs; + dprintk (KERN_DEBUG "xpds_rx (%p (%d), %d, %p)\n", + dev, card_num, len, buf); + xpds_rx_led (card_num, LED_ON); + + data_ptr = dev->priv; + fp = &(data_ptr->frad_data); + dlci = data_ptr->dlci; + + ddprintk (KERN_DEBUG "data_ptr = %p, fp = %p\n", data_ptr, fp); + +#if DEBUG + { + int i, debuglen; + + debuglen = len; + if (debuglen > sizeof (struct frhdr)) { + debuglen = sizeof (struct frhdr); + } + dpprintk (KERN_DEBUG "frame header (%p) received:", buf); + for (i = 0; i < debuglen; i ++) { + dpprintk (" %02x", buf[i]); + } + dpprintk ("\n"); + } + { + int i, debuglen; + + debuglen = len; + if (debuglen > 256) debuglen = 256; + dpprintk (KERN_DEBUG "data (%p) received:", + buf + sizeof (struct frhdr)); + for (i = sizeof (struct frhdr); i < debuglen ; i ++) { + dpprintk (" %02x", buf[i]); + } + if (len > debuglen) dpprintk (" ..."); + dpprintk ("\n"); + } +#endif + + if (dlci == 0) { + data_ptr->stats.rx_errors ++; + nrprintk (KERN_ERR "xpds_rx failed -- DLCI 0???\n"); + xpds_rx_led (card_num, LED_OFF); + return; + } + + for (i = 0; i < CONFIG_DLCI_MAX; i ++) { + if (fp->dlci[i] == dlci) break; + } + if (i == CONFIG_DLCI_MAX) { + data_ptr->stats.rx_errors ++; + nrprintk (KERN_ERR "xpds_rx failed -- invalid DLCI %d\n", dlci); + xpds_rx_led (card_num, LED_OFF); + return; + } + ddprintk (KERN_DEBUG "dlci = %d, i = %d\n", dlci, i); + + skb = dev_alloc_skb (len); + if (skb == NULL) { + printk (KERN_ERR "%s: unable to allocate skb for packet reception\n", dev->name); + return; + } + memcpy (skb_put (skb, len), (void *)buf, len); + skb->dev = dev; + /* skb->protocol = eth_type_trans (skb, dev); */ + skb->ip_summed = CHECKSUM_NONE; /* software will do checksum */ + xpds_dlci_receive (skb, dev); + /* netif_rx (skb); */ + + data_ptr->stats.rx_packets ++; + data_ptr->stats.rx_bytes ++; + + dprintk (KERN_DEBUG "xpds_rx done\n"); + + dev->last_rx = jiffies; + xpds_rx_led (card_num, LED_OFF); +} + +static struct tq_struct *xpds_reset_bh_tasks; + +/* + * A bottom half function that is meant to be put on a task queue + * if the link goes down (i.e. PEB 2091 falls out of transparent mode) + * and either a transmit is attempted or an RXCI interrupt (indicating + * that the other side may be back up) is received. + */ +static void +xpds_reset_bh (void *p) +{ + int rc; + int card_num; + struct net_device *dev; + + dev = (struct net_device *)p; + + card_num = dev - xpds_devs; + + dprintk (KERN_DEBUG "%s: retrying physical link / state machine, calling xpds_reset\n", xpds_devs[card_num].name); + + /* + * The guard times should be different on LT vs. NT + * when retrying. Should the guard times change every + * retry? + */ + xpds_guard_time = xpds_data[card_num].is_lt ? 3 : 2; + rc = xpds_reset (card_num); + if (rc == 0) { + printk ("%s: physical link is up\n", xpds_devs[card_num].name); + if (! xpds_data[card_num].is_sdsl) xpds_link_led (card_num, 1); + netif_start_queue(dev); + } + xpds_data[card_num].physical_retrying = 0; +} + +#if DEBUG +static void +xpds_print_interrupt_type (int card_num, u32 interrupt) +{ + u32 value; + + xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt mask is %02x", xpds_devs[card_num].name, value); + if (value & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO"); + if (value & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO"); + if (value & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA"); + if (value & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA"); + if (value & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR"); + if (value & XPDS_MCR_MASK__EXT) dprintk (" EXT"); + if (value & XPDS_MCR_MASK__RXCI) dprintk (" RXCI"); + dprintk ("\n"); + dprintk (KERN_DEBUG "%s: received interrupt %02x", + xpds_devs[card_num].name, interrupt); + if (interrupt & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO"); + if (interrupt & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO"); + if (interrupt & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA"); + if (interrupt & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA"); + if (interrupt & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR"); + if (interrupt & XPDS_MCR_MASK__EXT) dprintk (" EXT"); + if (interrupt & XPDS_MCR_MASK__RXCI) dprintk (" RXCI"); + dprintk ("\n"); + xpds_read_control_register (card_num, XPDS_DMA_SET_MASK, + &value, RX_DMA); + dprintk (KERN_DEBUG "%s: RX DMA mask is %02x\n", xpds_devs[card_num].name, value); + xpds_read_control_register (card_num, XPDS_DMA_SET_MASK, + &value, TX_DMA); + dprintk (KERN_DEBUG "%s: TX DMA mask is %02x\n", xpds_devs[card_num].name, value); +} + +static void +xpds_print_fifo_data (int card_num, u32 interrupt) +{ + u32 value; + + if ((xpds_debug_level & (DEBUG_MAIN | DEBUG_DETAILED)) != (DEBUG_MAIN | DEBUG_DETAILED)) return; + + if (interrupt & XPDS_MCR_INT__RX_FIFO) { + int i, rc; + u8 *vptr; + const volatile xpds_rxtx_list_t *rxtx; + + ddprintk (KERN_DEBUG "RX FIFO control registers:"); + for (i = 0; i < NUM_FIFO_CONTROL_REGISTERS; i += 4) { + if (i % 16 == 0) { + ddprintk ("\n"); + ddprintk (KERN_DEBUG "%08x:", i); + } + rc = xpds_read_control_register (card_num, i, &value, RX_FIFO); + if (rc > 0) { + ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc); + } else { + vptr = (u8 *) &value; + ddprintk (" %02x %02x %02x %02x", + vptr[0], vptr[1], vptr[2], vptr[3]); + } + } + ddprintk ("\n"); + + ddprintk (KERN_DEBUG "RX FIFO data registers:"); + for (i = 0; i < NUM_FIFO_DATA_REGISTERS; i += 4) { + if (i % 16 == 0) { + ddprintk ("\n"); + ddprintk (KERN_DEBUG "%08x:", i); + } + rc = xpds_read_control_register (card_num, i, &value, RX_FIFO_DATA); + if (rc > 0) { + ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc); + } else { + vptr = (u8 *) &value; + ddprintk (" %02x %02x %02x %02x", + vptr[0], vptr[1], vptr[2], vptr[3]); + } + } + ddprintk ("\n"); + + ddprintk (KERN_DEBUG "TX FIFO control registers:"); + for (i = 0; i < NUM_FIFO_CONTROL_REGISTERS; i += 4) { + if (i % 16 == 0) { + ddprintk ("\n"); + ddprintk (KERN_DEBUG "%08x:", i); + } + rc = xpds_read_control_register (card_num, i, &value, TX_FIFO); + if (rc > 0) { + ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc); + } else { + vptr = (u8 *) &value; + ddprintk (" %02x %02x %02x %02x", + vptr[0], vptr[1], vptr[2], vptr[3]); + } + } + ddprintk ("\n"); + + ddprintk (KERN_DEBUG "TX FIFO data registers:"); + for (i = 0; i < NUM_FIFO_DATA_REGISTERS; i += 4) { + if (i % 16 == 0) { + ddprintk ("\n"); + ddprintk (KERN_DEBUG "%08x:", i); + } + rc = xpds_read_control_register (card_num, i, &value, TX_FIFO_DATA); + if (rc > 0) { + ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc); + } else { + vptr = (u8 *) &value; + ddprintk (" %02x %02x %02x %02x", + vptr[0], vptr[1], vptr[2], vptr[3]); + } + } + ddprintk ("\n"); + + ddprintk (KERN_DEBUG "RX DMA control registers:"); + for (i = 0; i < NUM_DMA_CONTROL_REGISTERS; i += 4) { + if (i % 16 == 0) { + ddprintk ("\n"); + ddprintk (KERN_DEBUG "%08x:", i); + } + rc = xpds_read_control_register (card_num, i, &value, RX_DMA); + if (rc > 0) { + ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc); + } else { + vptr = (u8 *) &value; + ddprintk (" %02x %02x %02x %02x", + vptr[0], vptr[1], vptr[2], vptr[3]); + } + } + ddprintk ("\n"); + + ddprintk (KERN_DEBUG "TX DMA control registers:"); + for (i = 0; i < NUM_DMA_CONTROL_REGISTERS; i += 4) { + if (i % 16 == 0) { + ddprintk ("\n"); + ddprintk (KERN_DEBUG "%08x:", i); + } + rc = xpds_read_control_register (card_num, i, &value, TX_DMA); + if (rc > 0) { + ddprintk (" E%d E%d E%d E%d", rc, rc, rc, rc); + } else { + vptr = (u8 *) &value; + ddprintk (" %02x %02x %02x %02x", + vptr[0], vptr[1], vptr[2], vptr[3]); + } + } + ddprintk ("\n"); + + for (i = 0, rxtx = xpds_data[card_num].current_rx_dma; + i < NUM_DESC; + i ++, rxtx = rxtx->next) { + ddprintk (KERN_DEBUG "rx[%d](%p)->control = %08x", + i, rxtx, rxtx->control); + if (rxtx->control & RXTX_CONTROL__SWGO) { + ddprintk (" SWGO"); + } + if (rxtx->control & RXTX_CONTROL__HWGO) { + ddprintk (" HWGO"); + } + if (rxtx->control & RXTX_CONTROL__NEXT_VALID) { + ddprintk (" NEXT_VALID"); + } + ddprintk ("\n"); + if (! (rxtx->control & RXTX_CONTROL__NEXT_VALID)) { + break; + } + } + for (i = 0, rxtx = xpds_data[card_num].current_tx_dma; + i < NUM_DESC; + i ++, rxtx = rxtx->next) { + ddprintk (KERN_DEBUG "tx[%d](%p)->control = %08x", + i, rxtx, rxtx->control); + if (rxtx->control & RXTX_CONTROL__SWGO) { + ddprintk (" SWGO"); + } + if (rxtx->control & RXTX_CONTROL__HWGO) { + ddprintk (" HWGO"); + } + if (rxtx->control & RXTX_CONTROL__NEXT_VALID) { + ddprintk (" NEXT_VALID"); + } + ddprintk ("\n"); + if (! (rxtx->control & RXTX_CONTROL__NEXT_VALID)) { + break; + } + } + } + xpds_read_control_register (card_num, XPDS_MCR_RXCFG, &value, MAIN); + ddprintk ("%s: RX HDLC config is %08x\n", xpds_devs[card_num].name, value); + xpds_read_control_register (card_num, XPDS_MCR_TXCFG, &value, MAIN); + ddprintk ("%s: TX HDLC config is %08x\n", xpds_devs[card_num].name, value); +} +#endif + +/* + * For SDSL cards with the TX DMA low rate bug, do the transfer from the + * TX DMA descriptor to the TX FIFO. The TX FIFO interrupt indicates that + * the TX FIFO is ready to receive up to 32 bytes of data; this function + * simulates the hardware's method of copying data from the TX DMA to the + * TX FIFO. + * + * Note that this function keep stuffing the TX FIFO as long as it is + * ready (i.e. the TX FIFO interrupt bit shows 1), since if there is + * too long a delay for the next piece of the packet to be put in the + * TX FIFO, the packet will be aborted. + */ +#define TX_FIFO_DO_MORE 1 +#define TX_FIFO_DONE 2 +__inline__ static int +xpds_tx_fifo_interrupt (int card_num) +{ + volatile u32 *tx_fifo_data_pointer; + volatile u8 *data; + int tx_len, copy_len, i; + u32 control, length, offset; + u32 value; + struct timeval tv1, tv2; + int tvdiff; + + /* + * If there is no data in TX DMA (i.e. no more packets to + * send), disallow the TX FIFO interrupt (which will be + * enabled the next time a packet is transmitted by + * xpds_hw_tx() ) and be done. + */ + control = xpds_data[card_num].current_hw_tx_dma->control; + if (! (control & RXTX_CONTROL__HWGO) ) { + xpds_write_control_register (card_num, + XPDS_MCR_MASK_CLR, XPDS_MCR_INT__TX_FIFO, MAIN); + return TX_FIFO_DONE; + } + + /* + * Check TX FIFO interrupt to see if hardware is + * ready for the next TX FIFO to be filled. + * If not, allow TX FIFO interrupts (so that when the + * TX FIFO is ready, we come back here) and be done. + */ + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + XPDS_MCR_INT__TX_FIFO, MAIN); + xpds_read_control_register (card_num, XPDS_MCR_INT_CLR, + &value, MAIN); + if (! (value & XPDS_MCR_INT__TX_FIFO)) { + dprintk (KERN_DEBUG "%s: TX FIFO interrupt not asserted\n", xpds_devs[card_num].name); + xpds_write_control_register (card_num, + XPDS_MCR_MASK_SET, XPDS_MCR_INT__TX_FIFO, MAIN); + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + XPDS_MCR_INT__TX_FIFO, MAIN); + return TX_FIFO_DONE; + } + do_gettimeofday (&tv1); + + /* + * Get needed information about the length, offset, + * and data pointer in the TX DMA descriptor. Note + * that the length in the control field is one less + * than the actual length; we add 1 here to get the + * true length. + */ + length = (control & RXTX_CONTROL__PACKET_LENGTH_MASK) + 1; + offset = xpds_data[card_num].current_hw_tx_dma->offset; + data = xpds_data[card_num].current_hw_tx_dma->buffer + offset; + +#if DEBUG + xpds_read_control_register (card_num, XPDS_FCR_CONFIG, + &value, TX_FIFO); + dprintk (KERN_DEBUG "%s: TX FIFO config is %02x\n", + xpds_devs[card_num].name, value); +#endif + + /* + * Put data in the appropriate TX FIFO. Data must be + * set / copied into the TX FIFO data registers in 32 + * bit chunks, not 8 bit chunks. + */ + tx_fifo_data_pointer = (volatile u32 *) (xpds_data[card_num].tx_fifo_data_registers + FIFO_SIZE * xpds_data[card_num].current_tx_fifo); + dprintk (KERN_DEBUG "%s: current_tx_fifo=%d, tx_fifo_data_pointer=%p\n", xpds_devs[card_num].name, xpds_data[card_num].current_tx_fifo, tx_fifo_data_pointer); + + if (length - offset > FIFO_SIZE * sizeof (u32)) { + tx_len = FIFO_SIZE * sizeof (u32); + } else { + tx_len = length - offset; + } + + copy_len = tx_len % 4 == 0 ? tx_len : (tx_len + 4) / 4 * 4; + for (i = 0; i < copy_len / 4; i ++) { + tx_fifo_data_pointer[i] = *((u32 *)data + i); + } + + dprintk (KERN_DEBUG "%s: transmitting %d bytes through FIFO (%d left)\n", xpds_devs[card_num].name, tx_len, length - offset); +#if DEBUG + dprintk (KERN_DEBUG "TX FIFO data (%p):", tx_fifo_data_pointer); + for (i = 0; i < tx_len; i ++) { + dprintk (" %02x", ((volatile u8 *)tx_fifo_data_pointer)[i]); + } + dprintk ("\n"); +#endif + + /* + * Increment the current TX FIFO number and data pointer. + * Decrement the length. + */ + xpds_data[card_num].current_tx_fifo ++; + xpds_data[card_num].current_tx_fifo %= NUM_FIFO; + offset += tx_len; + xpds_data[card_num].current_hw_tx_dma->offset = offset; + + /* + * Tell the hardware that the data is ready. Note that + * the length is reduced by 1 for the hardware. + */ + tx_len -= 1; + if (length - offset <= 0) { + tx_len |= XPDS_FCR_STAT__LAST; + xpds_data[card_num].current_hw_tx_dma->control &= + ~ RXTX_CONTROL__HWGO; + xpds_data[card_num].current_hw_tx_dma->control |= + RXTX_CONTROL__SWGO; + xpds_data[card_num].current_hw_tx_dma->offset = 0; + xpds_data[card_num].current_hw_tx_dma = + xpds_data[card_num].current_hw_tx_dma->next; + } + + /* + * Note that due to the bug, we cannot use the FIFO registers + * until at least 10 microseconds after the FIFO ready (interrupt) + * is set. + */ + do_gettimeofday (&tv2); + tvdiff = tv2.tv_usec - tv1.tv_usec + + (tv2.tv_sec - tv1.tv_sec) * 1000000; + if (tvdiff >= 0 && tvdiff < 10) { + udelay (10 - tvdiff); + } + + dprintk (KERN_DEBUG "%s: writing %02x to FIFO stat\n", + xpds_devs[card_num].name, tx_len); + xpds_write_control_register (card_num, XPDS_FCR_STAT, + tx_len, TX_FIFO); + xpds_write_control_register (card_num, XPDS_FCR_INC, + XPDS_FCR_INC__NEXT, TX_FIFO); + +#if DEBUG + xpds_read_control_register (card_num, XPDS_FCR_CONFIG, + &value, TX_FIFO); + dprintk (KERN_DEBUG "%s: TX FIFO config is %02x after FCR_INC\n", xpds_devs[card_num].name, value); + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + XPDS_MCR_INT__TX_FIFO, MAIN); + xpds_read_control_register (card_num, XPDS_MCR_INT_CLR, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt value is %02x\n", + xpds_devs[card_num].name, value); +#endif + return TX_FIFO_DO_MORE; +} + +/* + * For SDSL cards with the RX DMA low rate bug, do the transfer from the + * RX FIFO descriptor to the RX DMA. The RX FIFO interrupt indicates that + * there is data in the RX FIFO that should be copied to the RX DMA. + * + * Note that this function keep taking from the RX FIFO as long as it is + * ready (i.e. the RX FIFO interrupt bit shows 1), since if there is + * too long a delay, pieces of the packet may be lost. + */ +#define RX_FIFO_DO_MORE 1 +#define RX_FIFO_DONE 2 +__inline__ static int +xpds_rx_fifo_interrupt (int card_num) +{ + volatile u32 *rx_fifo_data_pointer; + volatile u8 *data; + int rx_len, rx_last, copy_len, i; + u32 control, length, offset; + u32 value; + struct timeval tv1, tv2; + int tvdiff; + + /* + * If the RX DMA buffer is not ready for the hardware, + * stop. The packet is likely to drop in this case... + */ + control = xpds_data[card_num].current_hw_rx_dma->control; + if (! (control & RXTX_CONTROL__HWGO) ) { + xpds_write_control_register (card_num, + XPDS_MCR_MASK_CLR, XPDS_MCR_INT__RX_FIFO, MAIN); + return RX_FIFO_DONE; + } + + /* + * Check RX FIFO interrupt to see if hardware hass + * filled the next RX FIFO. + * If not, allow RX FIFO interrupts (so that when the + * RX FIFO is ready, we come back here) and be done. + */ + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + XPDS_MCR_INT__RX_FIFO, MAIN); + xpds_read_control_register (card_num, XPDS_MCR_INT_CLR, + &value, MAIN); + if (! (value & XPDS_MCR_INT__RX_FIFO)) { + dprintk (KERN_DEBUG "%s: RX FIFO interrupt not asserted\n", xpds_devs[card_num].name); + /* + xpds_write_control_register (card_num, + XPDS_MCR_MASK_SET, XPDS_MCR_INT__RX_FIFO, MAIN); + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + XPDS_MCR_INT__RX_FIFO, MAIN); + */ + return RX_FIFO_DONE; + } + + do_gettimeofday (&tv1); + + /* + * Get needed information about the length, offset, + * and data pointer in the RX DMA descriptor. Note + * that the length in the control field is one less + * than the actual length; we add 1 here to get the + * true length. + */ + length = (control & RXTX_CONTROL__PACKET_LENGTH_MASK); + offset = xpds_data[card_num].current_hw_rx_dma->offset; + data = xpds_data[card_num].current_hw_rx_dma->buffer + offset; + + dprintk (KERN_DEBUG "%s: current RX DMA buffer = %p\n", + xpds_devs[card_num].name, + xpds_data[card_num].current_hw_rx_dma->buffer); + dprintk (KERN_DEBUG "%s: current RX DMA length = %d\n", + xpds_devs[card_num].name, length); + dprintk (KERN_DEBUG "%s: current RX DMA offset = %d\n", + xpds_devs[card_num].name, offset); + dprintk (KERN_DEBUG "%s: current RX DMA data pointer = %p\n", + xpds_devs[card_num].name, data); + + /* + * Copy data from the RX FIFO into the DMA buffer. Data + * must be set / copied in 32 bit chunks, not 8 bit chunks. + */ + rx_fifo_data_pointer = (volatile u32 *) (xpds_data[card_num].rx_fifo_data_registers + FIFO_SIZE * xpds_data[card_num].current_rx_fifo); + dprintk (KERN_DEBUG "%s: current_rx_fifo=%d, rx_fifo_data_pointer=%p\n", xpds_devs[card_num].name, xpds_data[card_num].current_rx_fifo, rx_fifo_data_pointer); + + /* + * Note that due to the bug, we cannot read the FIFO registers + * until at least 10 microseconds after the FIFO ready (interrupt) + * is set. + */ + do_gettimeofday (&tv2); + tvdiff = tv2.tv_usec - tv1.tv_usec + + (tv2.tv_sec - tv1.tv_sec) * 1000000; + if (tvdiff >= 0 && tvdiff < 10) { + udelay (10 - tvdiff); + } + + xpds_read_control_register (card_num, XPDS_FCR_STAT, + &value, RX_FIFO); + rx_len = value & XPDS_FCR_STAT__SIZE_MASK; + rx_len += 1; + rx_last = value & XPDS_FCR_STAT__LAST; + + if (length + rx_len > RXTX_BUFFER_SIZE) { + dprintk (KERN_ERR "%s: packet too long (length = %d, rx_len = %d)\n", xpds_devs[card_num].name, length, rx_len); + if (rx_last) { + control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK; + control |= (length - 1); + control &= ~ RXTX_CONTROL__HWGO; + control |= RXTX_CONTROL__SWGO; + control &= ~ XPDS_DMA_DESC__PACKET_TAG_MASK; + control |= XPDS_DMA_DESC__PACKET_TAG_LONG; + xpds_data[card_num].current_hw_rx_dma->control = control; + xpds_data[card_num].current_hw_rx_dma->offset = 0; + } + xpds_data[card_num].current_rx_fifo ++; + xpds_data[card_num].current_rx_fifo %= NUM_FIFO; + xpds_write_control_register (card_num, XPDS_FCR_INC, + XPDS_FCR_INC__NEXT, RX_FIFO); + return RX_FIFO_DO_MORE; + } + dprintk (KERN_DEBUG "%s: receiving %d bytes through FIFO (rx_last=%x)\n", xpds_devs[card_num].name, rx_len, rx_last); +#if DEBUG + dprintk (KERN_DEBUG "RX FIFO data (%p):", rx_fifo_data_pointer); + for (i = 0; i < rx_len; i ++) { + dprintk (" %02x", ((volatile u8 *)rx_fifo_data_pointer)[i]); + } + dprintk ("\n"); +#endif + + copy_len = (rx_len % 4 == 0) ? rx_len : (rx_len + 4) / 4 * 4; + dprintk (KERN_DEBUG "%s: RX DMA offset = %d, data = %p, copy_len = %d\n", xpds_devs[card_num].name, offset, data, copy_len); + for (i = 0; i < copy_len / 4; i ++) { + *((u32 *)data + i) = rx_fifo_data_pointer[i]; + } + + /* + * Increment the RX FIFO number and data pointer. + */ + xpds_data[card_num].current_rx_fifo ++; + xpds_data[card_num].current_rx_fifo %= NUM_FIFO; + xpds_write_control_register (card_num, XPDS_FCR_INC, + XPDS_FCR_INC__NEXT, RX_FIFO); + + /* + * Increment the length and offset in the RX DMA buffer. + * If this is the last piece of the packet, turn on + * SW_GO and turn off HW_GO in the descriptor. + */ + length += rx_len; + if (rx_last) { + u32 tag; + offset = 0; + /* + * Check for tags. + */ + xpds_read_control_register (card_num, XPDS_FCR_TAG, + &value, RX_FIFO); + tag = value & XPDS_FCR_TAG__MASK; + if (tag) { + dprintk (KERN_DEBUG "%s: RX FIFO received tag %x\n", + xpds_devs[card_num].name, tag); + } + + control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK; + control |= (length - 1); + control &= ~ RXTX_CONTROL__HWGO; + control |= RXTX_CONTROL__SWGO; + control &= ~ XPDS_DMA_DESC__PACKET_TAG_MASK; + control |= ((tag << 16) & XPDS_DMA_DESC__PACKET_TAG_MASK); + dprintk (KERN_DEBUG "%s: packet length is %d\n", + xpds_devs[card_num].name, length); + } else { + control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK; + control |= length; + offset += rx_len; + } + xpds_data[card_num].current_hw_rx_dma->control = control; + xpds_data[card_num].current_hw_rx_dma->offset = offset; + + if (rx_last) { + xpds_data[card_num].current_hw_rx_dma = xpds_data[card_num].current_hw_rx_dma->next; + if (! (control & RXTX_CONTROL__NEXT_VALID)) { + dprintk (KERN_ERR "%s: RX DMA next valid is not set\n", xpds_devs[card_num].name); + } + } + return RX_FIFO_DO_MORE; +} + +/* + * If the RX or TX low rate bugs exist and the + * RX or TX FIFOs are ready, do the FIFO manipulations. + */ +__inline__ static void +xpds_fifo_interrupts (int card_num, u32 interrupt) +{ + int rx_rc = RX_FIFO_DONE, tx_rc = TX_FIFO_DONE, do_more; + + dprintk (KERN_DEBUG "%s: xpds_fifo_interrupts(%d,%02x) called\n", + xpds_devs[card_num].name, card_num, interrupt); + if ((interrupt & XPDS_MCR_INT__RX_FIFO) && + RX_DMA_LOW_RATE_BUG (card_num)) { + rx_rc = xpds_rx_fifo_interrupt (card_num); + } + if ((interrupt & XPDS_MCR_INT__TX_FIFO) && + TX_DMA_LOW_RATE_BUG (card_num)) { + tx_rc = xpds_tx_fifo_interrupt (card_num); + } + do_more = rx_rc == RX_FIFO_DO_MORE || tx_rc == TX_FIFO_DO_MORE; + while (do_more) { + int i, rc; + + do_more = 0; + for (i = 0; i < xpds_max_cards; i ++) { + if (xpds_data[i].rxtx_mem_allocated == NULL) continue; + if (RX_DMA_LOW_RATE_BUG (i)) { + rc = xpds_rx_fifo_interrupt (i); + if (rc == RX_FIFO_DO_MORE) do_more = 1; + } + if (TX_DMA_LOW_RATE_BUG (i)) { + rc = xpds_tx_fifo_interrupt (i); + if (rc == TX_FIFO_DO_MORE) do_more = 1; + } + } + } +} + +/* + * Handle RXCI interrupt for IDSL, indicating possible physical + * layer state change. + */ +__inline__ static void +xpds_rxci_interrupt (int card_num, struct net_device *dev) +{ + int ind_ai; + u32 value; + + /* + * Get correct IND_AI to look for. + */ + ind_ai = xpds_data[card_num].is_lt ? LT_IND_AI : NT_IND_AI; + + xpds_data[card_num].rxci_interrupt_received = 1; + xpds_read_control_register (card_num, XPDS_MCR_RXCI, + &value, MAIN); + + /* + * If network interface is up, check to see if PEB 2091 + * fell out of transparent mode. + */ + if (xpds_if_busy(dev) && (value & XPDS_MCR_RXCI__MASK) != ind_ai) { + dprintk (KERN_DEBUG "%s: RXCI status change to 0x%02x\n", xpds_devs[card_num].name, value); + printk (KERN_NOTICE "%s: physical link went down\n", xpds_devs[card_num].name); + if (! xpds_data[card_num].is_sdsl) xpds_link_led (card_num, 0); + netif_stop_queue(dev); + xpds_if_down(dev); + xpds_data[card_num].physical_up = 0; + xpds_data[card_num].physical_retrying = 0; + memset (xpds_data[card_num].frad_data.pvc_active, 0, + sizeof (xpds_data[card_num].frad_data.pvc_active)); + memset (xpds_data[card_num].frad_data.pvc_new, 0, + sizeof (xpds_data[card_num].frad_data.pvc_new)); + } else { + dprintk (KERN_DEBUG "%s: RXCI status change to 0x%02x\n", xpds_devs[card_num].name, value); + } +} + +/* + * Handle external interrupt for SDSL, indicating possible physical + * layer state change. + */ +__inline__ static void +xpds_ext_interrupt (int card_num, struct net_device *dev) +{ + u8 irq_type; + int rc; + + /* unmask external interrupt */ + xpds_write_control_register (card_num, XPDS_MCR_MASK_SET, + XPDS_MCR_INT__EXT, MAIN); + + /* get IRQ type */ + rc = xpds_mailbox_read (card_num, XPDS_MBX_WRITE_IRQTYPE, + &irq_type); + if (rc > 0) { + printk (KERN_ERR "%s: mailbox read (WRITE_IRQTYPE) failed (%d)\n", xpds_devs[card_num].name, rc); + } else if (irq_type == XPDS_SDSL_IRQTYPE_STATE_CHANGE) { + u8 state; + + rc = xpds_mailbox_read (card_num, + XPDS_MBX_READ_PHYS_STATE, &state); + if (rc > 0) { + printk (KERN_ERR "%s: mailbox read (READ_PHYS_STATE) failed (%d)\n", xpds_devs[card_num].name, rc); + } else { + if (state & XPDS_SDSL_STATE_LINKUP) { + int rc; + + printk (KERN_NOTICE "%s: physical link came up (state=%02x)\n", xpds_devs[card_num].name, state); + netif_start_queue(dev); + if (! xpds_data[card_num].physical_up) { + xpds_data[card_num].physical_up = 1; + xpds_data[card_num].physical_retrying = 0; + + /* + * Need to re-enable the DMA which was + * disabled when the link went down. + */ + rc = xpds_init_descriptors (card_num); + if (rc) printk (KERN_ERR "%s: xpds_init_descriptors(%d) failed\n", xpds_devs[card_num].name, card_num); + rc = xpds_dma_enable (card_num); + if (rc) printk (KERN_ERR "%s: xpds_dma_enable(%d) failed\n", xpds_devs[card_num].name, card_num); + } + + } else { + printk (KERN_NOTICE "%s: physical link went down (state=%02x)\n", xpds_devs[card_num].name, state); + netif_stop_queue(dev); + xpds_if_down(dev); + if (xpds_data[card_num].physical_up) { + u32 sdsl_mode, speed_mode; + int rc; + + xpds_data[card_num].physical_up = 0; + xpds_data[card_num].physical_retrying = 1; + + /* + * DMA can get jammed up with junk + * packets when link goes down and + * up. Need to disable the DMA here + * to get the ASIC unstuck. + */ + rc = xpds_dma_disable (card_num); + if (rc) printk (KERN_ERR "%s: xpds_dma_disable(%d) failed\n", xpds_devs[card_num].name, card_num); + + /* + * Reset speed mode (in case it is 0, + * need it set that way for mailbox + * timeouts). + */ + rc = xpds_get_sdsl_mode (card_num, + &sdsl_mode); + speed_mode = sdsl_mode & XPDS_SDSL_MODE__SPEED_MASK; + xpds_data[card_num].sdsl_speed = + speed_mode << 3; + + } + } + } + } +} + +#define PACKET_READ 0 +#define RX_DMA_NOT_READY 1 + +/* + * Handle an RX DMA interrupt. Return PACKET_READ if a packet was + * read (erroneous or otherwise), and RX_DMA_NOT_READY if SW_GO is + * not set in the next descriptor. + */ +__inline__ static int +xpds_rx_dma_interrupt (struct net_device *dev, int card_num) +{ + volatile xpds_rxtx_list_t *current_rx; + int len; + int packet_good; +#if DEBUG + u32 value; +#endif + + current_rx = xpds_data[card_num].current_rx_dma; + + dprintk (KERN_DEBUG "%s: xpds_rx_dma_interrupt() called\n", xpds_devs[card_num].name); + dprintk (KERN_DEBUG "%s: current_rx = %p\n", xpds_devs[card_num].name, current_rx); + dprintk (KERN_DEBUG "%s: current_rx->control = %08x\n", xpds_devs[card_num].name, current_rx->control); + dprintk (KERN_DEBUG "%s: current_rx->buffer = %p\n", xpds_devs[card_num].name, current_rx->buffer); + dprintk (KERN_DEBUG "%s: current_rx->next = %p\n", xpds_devs[card_num].name, current_rx->next); + dprintk (KERN_DEBUG "%s: current_rx->prev = %p\n", xpds_devs[card_num].name, current_rx->prev); + { + volatile xpds_rxtx_list_t *rx; + + for (rx = current_rx->next; rx != current_rx; rx = rx->next) { + ddprintk (KERN_DEBUG "rx = %p\n", rx); + ddprintk (KERN_DEBUG "rx->control = %08x\n", rx->control); + ddprintk (KERN_DEBUG "rx->buffer = %p\n", rx->buffer); + ddprintk (KERN_DEBUG "rx->next = %p\n", rx->next); + ddprintk (KERN_DEBUG "rx->prev = %p\n", rx->prev); + } + } + +#if DEBUG + xpds_read_control_register (card_num, XPDS_DMA_CLR_STAT, + &value, RX_DMA); + ddprintk (KERN_DEBUG "%s: RX DMA status is %02x\n", + xpds_devs[card_num].name, value); +#endif + +#if DEBUG + xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR, + &value, MAIN); + ddprintk (KERN_DEBUG "%s: interrupt mask is %02x\n", xpds_devs[card_num].name, value); + xpds_read_control_register (card_num, XPDS_MCR_INT_CLR, + &value, MAIN); + ddprintk (KERN_DEBUG "%s: interrupt is %02x\n", xpds_devs[card_num].name, value); +#endif + + /* + * Hardware should have set the software-go bit. + */ + if (! (current_rx->control & RXTX_CONTROL__SWGO) ) { + dprintk (KERN_DEBUG "%s: xpds_rx_dma_interrupt() done, not ready\n", xpds_devs[card_num].name); + return RX_DMA_NOT_READY; + } + + /* + * Packet is good unless proven otherwise... + */ + packet_good = 1; + + /* + * Check the packet tag. If not OK, mark the packet as not good. + */ + { + u32 packet_tag; + const char *tag_str; + + packet_tag = current_rx->control & XPDS_DMA_DESC__PACKET_TAG_MASK; + if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_CRC) { + tag_str = "CRC error"; + } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_BOUNDARY_VIOLATION) { + tag_str = "boundary violation"; + } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_LONG) { + tag_str = "long frame"; + } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_ABORT) { + tag_str = "abort received"; + } else if (packet_tag == XPDS_DMA_DESC__PACKET_TAG_OK) { + tag_str = "OK"; + } else if (packet_tag & 0x80000) { + tag_str = "overflow/underflow"; + } else { + tag_str = "unlisted error"; + } + if (packet_tag != XPDS_DMA_DESC__PACKET_TAG_OK) { + len = current_rx->control & + RXTX_CONTROL__PACKET_LENGTH_MASK; + len ++; + dprintk (KERN_ERR "%s: received packet of length %d with tag %05x (%s)\n", xpds_devs[card_num].name, len, packet_tag, tag_str); + packet_good = 0; + } + } + + /* + * Get and check length of packet. + */ + len = current_rx->control & RXTX_CONTROL__PACKET_LENGTH_MASK; + len ++; + /* buggy ASIC has packet length 2 too large */ + if (xpds_data[card_num].has_last_byte_bug) { + len -= 2; + if (len < 0) len = 0; + } + if (len > RXTX_BUFFER_SIZE) { + dprintk (KERN_ERR "%s: receiving packet of length %d -- too large\n", xpds_devs[card_num].name, len); + packet_good = 0; + } else if (len < 1) { + dprintk (KERN_ERR "%s: receiving packet of length %d -- too small\n", xpds_devs[card_num].name, len); + packet_good = 0; + } else { + dprintk (KERN_DEBUG "%s: receiving packet of length %d\n", + xpds_devs[card_num].name, len); + } + + /* + * Receive the packet (i.e. copy it to where the kernel + * deals with it) if the packet is ok. + */ + if (packet_good) { + xpds_rx (dev, len, current_rx->buffer); + } + + /* + * Zero the packet length. + */ + ddprintk (KERN_DEBUG "%s: zeroing packet length\n", xpds_devs[card_num].name); + current_rx->control &= ~ (RXTX_CONTROL__PACKET_LENGTH_MASK | (RXTX_CONTROL__PACKET_TAG_MASK << RXTX_CONTROL__PACKET_TAG_OFFSET)); + + /* + * Turn off software-go, then turn on hardware-go to let the + * hardware know that it is ok to reuse the buffer. + */ + current_rx->control &= ~ RXTX_CONTROL__SWGO; + current_rx->control |= RXTX_CONTROL__HWGO; + + /* + * Advance the current to the next descriptor. + */ + xpds_data[card_num].current_rx_dma = current_rx->next; + + /* + * Increment the counters. + */ + if (packet_good) { + xpds_data[card_num].stats.rx_packets ++; + } else { + xpds_data[card_num].stats.rx_errors ++; + } + + dprintk (KERN_DEBUG "%s: xpds_rx_dma_interrupt() done, packet read\n", xpds_devs[card_num].name); + + return PACKET_READ; +} + +typedef struct { + struct net_device *dev; + u32 interrupt; +} interrupt_bh_data_t; + +static struct tq_struct *xpds_interrupt_bh_tasks; + +static void xpds_interrupt_bh (void *p); + +/* + * The interrupt handler for the card. Interrupts may happen due + * to receiving a packet, or due to an RXCI status change (which + * occurs while the state machines on the LT and NT sides are + * negotiating each other into transparent mode). + */ +static void +xpds_interrupt (int irq __attribute__((unused)), void *dev_instance, + struct pt_regs *regs __attribute__((unused))) +{ + struct net_device *dev; + int card_num; + u32 interrupt, bh_interrupts; + + dprintk (KERN_DEBUG "xpds_interrupt (%d, %p, %p)\n", irq, dev_instance, regs); + + dev = (struct net_device *)dev_instance; + + if (dev == NULL) return; + + /* + * Lock. + */ +#ifdef __SMP__ + if (test_and_set_bit(0, (void*)&dev->interrupt)) { + dprintk (KERN_DEBUG "%s: Duplicate entry of the interrupt handler by processor %d.\n", + dev->name, hard_smp_processor_id()); + dev->interrupt = 0; + return; + } +#else +/* if (dev->interrupt) { + dprintk (KERN_DEBUG "%s: Re-entering the interrupt handler.\n", dev->name); + return; + } + dev->interrupt = 1; */ +#endif + + card_num = dev - xpds_devs; + + /* + * Get the interrupt type. + */ + xpds_read_control_register (card_num, XPDS_MCR_INT_SET, + &interrupt, MAIN); +#if DEBUG + xpds_print_interrupt_type (card_num, interrupt); +#endif + + if (RX_DMA_LOW_RATE_BUG (card_num)) { + xpds_write_control_register (card_num, + XPDS_MCR_MASK_CLR, XPDS_MCR_INT__RX_FIFO, MAIN); + } + if (TX_DMA_LOW_RATE_BUG (card_num)) { + xpds_write_control_register (card_num, + XPDS_MCR_MASK_CLR, XPDS_MCR_INT__TX_FIFO, MAIN); + } + + /* + * Tell the hardware to stop generating this interrupt. + * For SDSL, clear the physical layer interrupt first. + * For all cards, clear the interrupt in the MCR. + */ + if ((interrupt & XPDS_MCR_INT__EXT) && xpds_data[card_num].is_sdsl) { + int rc; + + rc = xpds_mailbox_write (card_num, XPDS_MBX_CLEAR_IRQ, 0); + if (rc > 0) printk (KERN_ERR "%s: mailbox write (CLEAR_IRQ, 0) failed\n", xpds_devs[card_num].name); + + /* mask external interrupt */ + xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR, + XPDS_MCR_INT__EXT, MAIN); + } + + if (interrupt & XPDS_MCR_INT__RX_DMA) { + xpds_write_control_register (card_num, XPDS_DMA_CLR_STAT, + 0xff /* XPDS_DMA_STAT__DONE */, RX_DMA); + } + + /* clear the interrupt in the MCR */ + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + 0xff, MAIN); + + /* read the interrupt in the MCR */ + if (xpds_debug_level) { + u32 value; + xpds_read_control_register (card_num, XPDS_MCR_INT_SET, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt register is %02x after clearing\n", xpds_devs[card_num].name, value); + } + + /* + * If the RX or TX low rate bugs exist and the + * RX or TX FIFOs are ready, do the FIFO manipulations. + */ + xpds_fifo_interrupts (card_num, interrupt); + +#if DEBUG + xpds_print_fifo_data (card_num, interrupt); +#endif + + /* + * If it is a TX DMA interrupt, clear the HW_GO and SW_GO bits + * in any descriptors where both are set, and clear the interrupt. + */ + if (interrupt & XPDS_MCR_INT__TX_DMA) { + volatile xpds_rxtx_list_t *tx_desc; + int i; + + tx_desc = xpds_data[card_num].current_tx_dma; + for (i = 0; i < NUM_DESC; i ++) { + if ((tx_desc->control & (XPDS_DMA_DESC__HW_GO | XPDS_DMA_DESC__SW_GO)) == (XPDS_DMA_DESC__HW_GO | XPDS_DMA_DESC__SW_GO)) { + tx_desc->control &= ~ (XPDS_DMA_DESC__HW_GO | XPDS_DMA_DESC__SW_GO); + } + tx_desc = tx_desc->next; + } + + ddprintk (KERN_DEBUG "%s: clearing TX DMA interrupt\n", xpds_devs[card_num].name); + xpds_write_control_register (card_num, + XPDS_DMA_CLR_STAT, + 0xff /* XPDS_DMA_STAT__DONE */, TX_DMA); + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + XPDS_MCR_INT__TX_DMA, MAIN); + + xpds_tx_led (card_num, LED_OFF); + } + + /* + * Check to see if the hardware has caught up with the + * software. If it has the software-go bit set, then + * reset and start the DMA again. + */ + if (xpds_data[card_num].current_rx_dma->prev->control & RXTX_CONTROL__SWGO) { + if (! RX_DMA_LOW_RATE_BUG (card_num)) { + printk (KERN_INFO "%s: RX DMA overrun -- restarting RX DMA\n", xpds_devs[card_num].name); + xpds_dma_disable (card_num); + xpds_init_descriptors (card_num); + xpds_dma_enable (card_num); + } + } + + mark_bh (NET_BH); + + bh_interrupts = XPDS_MCR_INT__EXT | XPDS_MCR_INT__RXCI | XPDS_MCR_INT__RX_DMA; + if (RX_DMA_LOW_RATE_BUG (card_num) || TX_DMA_LOW_RATE_BUG (card_num)) { + bh_interrupts |= XPDS_MCR_INT__RX_FIFO | XPDS_MCR_INT__TX_FIFO; + } + + if (interrupt & bh_interrupts) { + dprintk (KERN_DEBUG "queuing a bottom half task (dev = %p (%d), interrupt = %02x)\n", dev, card_num, interrupt); + ((interrupt_bh_data_t *)(xpds_interrupt_bh_tasks[card_num].data))->dev = dev; + ((interrupt_bh_data_t *)(xpds_interrupt_bh_tasks[card_num].data))->interrupt = interrupt; + queue_task (&(xpds_interrupt_bh_tasks[card_num]), &tq_immediate); + mark_bh (IMMEDIATE_BH); + } +#if defined(__i386__) +/* clear_bit(0, (void*)&dev->interrupt); */ +#else +/* dev->interrupt = 0; */ +#endif +} + +static void +xpds_interrupt_bh (void *p) +{ + interrupt_bh_data_t *data; + struct net_device *dev; + int card_num; + u32 interrupt; + + dprintk (KERN_DEBUG "xpds_interrupt_bh(%p) started\n", p); + + data = p; + dev = data->dev; + card_num = dev - xpds_devs; + interrupt = data->interrupt; + + dprintk (KERN_DEBUG "card_num = %d, interrupt = %02x\n", + card_num, interrupt); + + /* + * If it is an RX DMA interrupt, need to get the packet + * from the buffer that hardware wrote into. Keep doing + * this until there are no more descriptors to read, + * because there may be multiple descriptors filled + * during one interrupt. + * + * Note that if we have the TX DMA low bit rate bug, we + * need to check see if we can push more data into the TX + * FIFO each time we receive a packet; if this isn't done, + * the TX FIFOs may get starved. + */ + if ((interrupt & XPDS_MCR_INT__RX_DMA) || + ((interrupt & XPDS_MCR_INT__RX_FIFO) && + RX_DMA_LOW_RATE_BUG (card_num)) ) { + int rc; + do { + xpds_fifo_interrupts (card_num, interrupt); + rc = xpds_rx_dma_interrupt (dev, card_num); + } while (rc == PACKET_READ); + } + + /* + * Turn on RX FIFO interrupts if necessary. + */ + if (RX_DMA_LOW_RATE_BUG (card_num)) { + xpds_write_control_register (card_num, + XPDS_MCR_MASK_SET, XPDS_MCR_INT__RX_FIFO, MAIN); + } + + /* + * If it is an RXCI interrupt, clear it, handle it, and go on. + * The RXCI interrupt is only used for IDSL cards. + */ + if ((interrupt & XPDS_MCR_INT__RXCI) && ! xpds_data[card_num].is_sdsl) { + xpds_rxci_interrupt (card_num, dev); + } + + /* + * If it is an external interrupt, clear it, handle it, and go on. + * The external interrupt is only used for SDSL cards. + */ + if ((interrupt & XPDS_MCR_INT__EXT) && xpds_data[card_num].is_sdsl) { + xpds_ext_interrupt (card_num, dev); + } + + dprintk (KERN_DEBUG "xpds_interrupt_bh() finished\n"); +} + + +/* + * Called when "ifconfig xpds0 up" or some such is done. + * Tries to bring up and reset the device. Needs to have + * the other side also trying to get to transparent mode. + */ +static int +xpds_open (struct net_device *dev) +{ + int card_num, rc, flags; + u32 value; + + dprintk (KERN_DEBUG "xpds_open (%p (%d))\n", dev, dev - xpds_devs); + + card_num = dev - xpds_devs; + + /* + * Disable all interrupts. + */ + xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR, + 0xff, MAIN); + xpds_write_control_register (card_num, XPDS_MCR_INT_CLR, + 0xff, MAIN); + xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt mask is %08x\n", xpds_devs[card_num].name, value); + + /* + * Request the IRQ. + */ + dev->irq = xpds_data[card_num].pci_dev->irq; + + flags = SA_SHIRQ; + + dprintk (KERN_DEBUG "%s: request_irq (%d, %p, %08x, %s, %p)\n", + dev->name, dev->irq, xpds_interrupt, flags, dev->name, dev); + /* DELAY (2, card_num); */ + rc = request_irq (dev->irq, &xpds_interrupt, flags, dev->name, dev); + if (rc != 0) { + dprintk (KERN_DEBUG "%s: unable to get IRQ %d (rc=%d)\n", + dev->name, dev->irq, rc); + free_irq (dev->irq, dev); + return -EAGAIN; + } + + dprintk (KERN_DEBUG "%s: %s got interrupt %d\n", dev->name, dev->name, dev->irq); + + /* dev->dev_addr = ??? ; */ + + rc = xpds_reset (card_num); + + xpds_dlci_install_lmi_timer (0, dev); + + MOD_INC_USE_COUNT; + + return 0; +} + +/* + * Called when "ifconfig xpds0 down" or some such is done. + * Brings down the device. + */ +static int +xpds_stop (struct net_device *dev) +{ + int card_num; + int rc; + u32 value; + + card_num = dev - xpds_devs; + + dprintk (KERN_DEBUG "%s: xpds_stop(%p)\n", xpds_devs[card_num].name, dev); + printk (KERN_DEBUG "%s: going down\n", xpds_devs[card_num].name); + + xpds_dlci_remove_lmi_timer (0, dev); + + rc = xpds_dma_disable (card_num); + if (rc != 0) return rc; + + /* + * Turn off link LED, or put the SDSL in reset. + */ + if (! xpds_data[card_num].is_sdsl) { + xpds_link_led (card_num, 0); + } else { + xpds_reset_sdsl (card_num); + } + + /* + * Bring physical layer down. + */ + if (xpds_data[card_num].is_sdsl) { + xpds_reset_sdsl (card_num); + } else { + xpds_read_control_register (card_num, XPDS_MCR_TXCI, &value, + MAIN); + value &= (XPDS_MCR_TXCI__MASK | XPDS_MCR_TXCI__PMD_CONFIG_B1B2D); + xpds_write_control_register (card_num, XPDS_MCR_TXCI, value, + MAIN); + } + xpds_data[card_num].physical_up = 0; + xpds_data[card_num].physical_retrying = 0; + + /* + * Disable interrupts + */ + xpds_write_control_register (card_num, XPDS_MCR_MASK_CLR, 0xff, MAIN); + + /* + * Mark the device as off and busy. + */ + netif_stop_queue(dev); + xpds_if_down(dev); + + MOD_DEC_USE_COUNT; + + free_irq (dev->irq, dev); + + return 0; +} + +/* + * Does the hardware control part of the packet transmission. + */ +static int +xpds_hw_tx (char *data, int len, struct net_device *dev) +{ + int card_num; + volatile xpds_rxtx_list_t *current_tx; + u32 control; + + card_num = dev - xpds_devs; +#if DEBUG + { + u32 value; + + xpds_read_control_register (card_num, XPDS_MCR_MASK_CLR, + &value, MAIN); + dprintk (KERN_DEBUG "%s: interrupt mask is %02x", xpds_devs[card_num].name, value); + if (value & XPDS_MCR_MASK__RX_FIFO) dprintk (" RX_FIFO"); + if (value & XPDS_MCR_MASK__TX_FIFO) dprintk (" TX_FIFO"); + if (value & XPDS_MCR_MASK__RX_DMA) dprintk (" RX_DMA"); + if (value & XPDS_MCR_MASK__TX_DMA) dprintk (" TX_DMA"); + if (value & XPDS_MCR_MASK__PCI_ERROR) dprintk (" PCI_ERROR"); + if (value & XPDS_MCR_MASK__EXT) dprintk (" EXT"); + if (value & XPDS_MCR_MASK__RXCI) dprintk (" RXCI"); + dprintk ("\n"); + } +#endif + + dprintk (KERN_DEBUG "%s: transmitting packet of length %d\n", + xpds_devs[card_num].name, len); + + /* + * Make sure data is not too big. We are assuming that the + * other end has the same maximum packet length limitation. + * Is this necessarily correct? + */ + if (len > xpds_max_packet_length) { + xpds_data[card_num].stats.tx_errors ++; + printk (KERN_ERR "packet size %d is too large (maximum %d)\n", + len, xpds_max_packet_length); + return -E2BIG; + } + + /* + * Get control information for the descriptor. + */ + control = xpds_data[card_num].current_tx_dma->control; + + /* + * Check current descriptor to see if it is available. + * If software-go flag is not set, then the buffer is still + * waiting for the hardware to empty it. + */ + if (! (control & RXTX_CONTROL__SWGO) && (control & RXTX_CONTROL__HWGO) ) { + dprintk (KERN_DEBUG "%s: unable to transmit (SWGO == 0 && HWGO == 1)\n", xpds_devs[card_num].name); + /* xpds_data[card_num].stats.tx_errors ++; */ + return -EBUSY; + } + + /* + * Indicate the time a transmission started. + */ + dev->trans_start = jiffies; + + /* + * Fill in current transmit buffer. + */ + ddprintk (KERN_DEBUG "%s: filling current transmit buffer\n", xpds_devs[card_num].name); + memcpy ((void *)(xpds_data[card_num].current_tx_dma->buffer), data, len); + + /* + * Set up the length in the current descriptor. + */ + ddprintk (KERN_DEBUG "%s: setting length in descriptor\n", xpds_devs[card_num].name); + control &= ~ RXTX_CONTROL__PACKET_LENGTH_MASK; + control |= ((len - 1) & RXTX_CONTROL__PACKET_LENGTH_MASK); + + /* + * Clear the software-go flag and set the hardware-go flag + * in the current descriptor. + */ + ddprintk (KERN_DEBUG "%s: clearing SWGO and setting HWGO\n", xpds_devs[card_num].name); + control &= ~ RXTX_CONTROL__SWGO; + control |= RXTX_CONTROL__HWGO; + + /* + * Put changed control back in the TX descriptor. + */ + xpds_data[card_num].current_tx_dma->control = control; + + /* + * Print out the current TX descriptor. + */ + current_tx = xpds_data[card_num].current_tx_dma; + + /* + * Write a 1 to the hunt bit of the DMA go register for + * the transmit DMA to cause it to fetch the next descriptor. + */ + ddprintk (KERN_DEBUG "%s: setting hunt bit\n", xpds_devs[card_num].name); + xpds_write_control_register (card_num, XPDS_DMA_GO, + XPDS_DMA_GO__HUNT, TX_DMA); + + /* + * Set current transmit buffer to the next one in the + * circular list, after setting the offset to 0 in case + * of the TX DMA bug. + */ + xpds_data[card_num].current_tx_dma->offset = 0; + ddprintk (KERN_DEBUG "%s: setting current transmit buffer to next\n", xpds_devs[card_num].name); + xpds_data[card_num].current_tx_dma = + xpds_data[card_num].current_tx_dma->next; + + /* + * Increment the counters. + */ + xpds_data[card_num].stats.tx_packets ++; + xpds_data[card_num].stats.tx_bytes += len; + + dprintk (KERN_DEBUG "%s: transmitted packet %ld\n", + xpds_devs[card_num].name, (long) (xpds_data[card_num].stats.tx_packets)); + + /* + * If we have the TX DMA bug we need to enable the TX FIFO + * interrupt so that when the TX FIFO is ready, we can simulate + * the hardware DMA->FIFO transfer in the driver. + */ + if (TX_DMA_LOW_RATE_BUG (card_num)) { + xpds_write_control_register (card_num, + XPDS_MCR_MASK_SET, XPDS_MCR_INT__TX_FIFO, MAIN); + } + + dprintk (KERN_DEBUG "%s: xpds_hw_tx () done\n", xpds_devs[card_num].name); + + return 0; +} + +/* + * Called whenever a packet needs to be transmitted. + * Note that if the physical link is down (not in transparent + * mode), a bottom half to reset the device is placed on the + * scheduler queue. + */ +int +xpds_tx (u8 *data, unsigned int len, struct net_device *dev) +{ + int card_num; + int rc; + u32 control; + + card_num = dev - xpds_devs; + + xpds_tx_led (card_num, LED_ON); + + dprintk (KERN_DEBUG "%s: xpds_tx (%p, %u, %p)\n", xpds_devs[card_num].name, + data, len, dev); + +#if DEBUG + { + int i, debuglen; + + debuglen = len; + if (debuglen > sizeof (struct frhdr)) { + debuglen = sizeof (struct frhdr); + } + dpprintk (KERN_DEBUG "frame header sent:"); + for (i = 0; i < sizeof (struct frhdr); i ++) { + dpprintk (" %02x", data[i]); + } + dpprintk ("\n"); + } + { + int i, debuglen; + + /* debuglen = ETH_ZLEN < len ? len : ETH_ZLEN; */ + debuglen = len; + if (debuglen > 256) debuglen = 256; + dpprintk (KERN_DEBUG "data sent:"); + for (i = sizeof (struct frhdr); i < debuglen ; i ++) { + dpprintk (" %02x", data[i]); + } + if (len > debuglen) dpprintk (" ..."); + dpprintk ("\n"); + } +#endif + if (! xpds_data[card_num].physical_up) { + dprintk (KERN_DEBUG "%s: physical link is down\n", xpds_devs[card_num].name); + if (xpds_data[card_num].is_sdsl) { + return -EBUSY; + } + if (! xpds_data[card_num].physical_retrying) { + xpds_data[card_num].physical_retrying = 1; + + xpds_reset_bh_tasks[card_num].next = NULL; + xpds_reset_bh_tasks[card_num].sync = 0; + xpds_reset_bh_tasks[card_num].routine = xpds_reset_bh; + xpds_reset_bh_tasks[card_num].data = dev; + + queue_task (&(xpds_reset_bh_tasks[card_num]), + &tq_scheduler); + } + xpds_tx_led (card_num, LED_OFF); + return -EBUSY; + } + + /* + * Atomically test and set (bit 0 of) the busy flag. + * If busy, return BUSY. + */ + if (xpds_if_busy(dev)) { + dprintk (KERN_DEBUG "%s: busy\n", xpds_devs[card_num].name); + xpds_tx_led (card_num, LED_OFF); + /* xpds_data[card_num].stats.tx_errors ++; */ + + return -EBUSY; + } + netif_stop_queue(dev); + + /* len = ETH_ZLEN < len ? len : ETH_ZLEN; */ + dev->trans_start = jiffies; + + rc = xpds_hw_tx (data, len, dev); + + if (rc == 0) { + /* dev_kfree_skb (skb, FREE_WRITE); */ + } else { + xpds_tx_led (card_num, LED_OFF); + } + + /* + * Get control information for the descriptor (after + * the one that we just wrote into). + */ + control = xpds_data[card_num].current_tx_dma->control; + + /* + * Atomically clear the busy bit. + */ +/* if (test_and_clear_bit (0, (void *)&(dev->tbusy)) == 0) { + printk (KERN_ERR "%s: test_and_clear_bit(0, &(dev->tbusy)) in xpds_tx() found bit already clear\n", xpds_devs[card_num].name); + } */ + netif_wake_queue(dev); + + /* + * Return OK if xpds_tx returned 0 (OK), BUSY if -EBUSY, + * ERR otherwise. + */ + return rc; +} + +struct net_device_stats * +xpds_get_stats (struct net_device *dev) +{ + xpds_data_t *data_ptr; + + data_ptr = dev->priv; + return &(data_ptr->stats); +} + +static int +xpds_set_config (struct net_device *dev, + struct ifmap *map __attribute__ ((unused)) ) +{ + dprintk (KERN_DEBUG "%s: xpds_set_config() called\n", + dev->name); + + if (dev->flags & IFF_UP) return -EBUSY; + + /* nothing */ + + return 0; +} + +static void +xpds_reboot_sdsl_physical_layer (int card_num) +{ + if (xpds_data[card_num].physical_up || + xpds_data[card_num].physical_retrying) { + xpds_reset_sdsl (card_num); + xpds_start_sdsl (card_num); + } +} + +static int xpds_init_frad_data (struct frad_local *fp, short dlci); + +static int +xpds_ioctl (struct net_device *dev, struct ifreq *rq, + int cmd) +{ + xpds_data_t *data_ptr; + int val, card_num, rc = 0; + + if (! suser ()) return -EACCES; + + data_ptr = dev->priv; + card_num = data_ptr - xpds_data; + val = (int)(rq->ifr_data); + if (cmd == XPDS_IOCTL_SET_DEBUG) { +#if DEBUG + int i; + + printk ("XPDS driver debug level set to %d\n", val); + xpds_debug_level = val; + for (i = 0; i < xpds_max_cards; i ++) { + xpds_devs[i].flags &= ~ IFF_DEBUG; + xpds_devs[i].flags |= val ? IFF_DEBUG : 0; + } +#else + printk (KERN_ERR "This version of the XPDS driver does not have debug capability.\n"); +#endif + } else if (cmd == XPDS_IOCTL_SET_LT) { + printk ("%s: set to %s\n", + xpds_devs[card_num].name, + val ? "LT (line termination)" : + "NT (network termination)"); + val = (val != 0); + data_ptr->is_lt = val; + data_ptr->frad_data.no_initiate_lmi = val; + if (data_ptr->is_sdsl) { + u32 sdsl_mode; + u8 byte; + + xpds_get_flash_sdsl_mode (card_num, &sdsl_mode); + printk (KERN_DEBUG "%s: sdsl_mode = %08x\n", + xpds_devs[card_num].name, sdsl_mode); + sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED; + sdsl_mode &= ~ XPDS_SDSL_MODE__NT; + sdsl_mode |= data_ptr->is_lt ? 0 : XPDS_SDSL_MODE__NT; + printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode); + rc = xpds_set_sdsl_mode (card_num, sdsl_mode); + if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name); + rc = xpds_get_sdsl_exit_code (card_num, &byte); + if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) { + printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte); + rc = -EBUSY; + } + } + } else if (cmd == XPDS_IOCTL_SET_IDSL_MODE) { + if (! data_ptr->is_sdsl) { + printk ("%s: set to mode %d\n", xpds_devs[card_num].name, val); + data_ptr->speed_mode = val; + } else { + printk (KERN_ERR "Setting the IDSL mode is only applicable to IDSL.\n"); + rc = -EINVAL; + } + } else if (cmd == XPDS_IOCTL_SET_SDSL_SPEED) { + if (data_ptr->is_sdsl) { + u32 sdsl_mode; + u8 byte; + + printk ("%s: SDSL speed set to %d\n", + xpds_devs[card_num].name, + ((val >> 3) & XPDS_SDSL_MODE__SPEED_MASK) << 3); + rc = xpds_get_flash_sdsl_mode (card_num, &sdsl_mode); + if (rc > 0) printk (KERN_ERR "%s: xpds_get_flash_sdsl_mode() failed\n", xpds_devs[card_num].name); + printk (KERN_DEBUG "%s: sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode); + sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED; + sdsl_mode &= ~ XPDS_SDSL_MODE__SPEED_MASK; + sdsl_mode |= (val >> 3) & XPDS_SDSL_MODE__SPEED_MASK; + printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode); + rc = xpds_set_sdsl_mode (card_num, sdsl_mode); + if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name); + rc = xpds_get_sdsl_exit_code (card_num, &byte); + if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) { + printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte); + rc = -EBUSY; + } + + xpds_reboot_sdsl_physical_layer (card_num); + + if ((xpds_data[card_num].has_tx_dma_low_rate_bug || + xpds_data[card_num].has_rx_dma_low_rate_bug) && + xpds_data[card_num].physical_up) { + if ((xpds_data[card_num].sdsl_speed < LOW_BIT_RATE && val >= LOW_BIT_RATE) || (xpds_data[card_num].sdsl_speed >= LOW_BIT_RATE && val < LOW_BIT_RATE)) { + /* + * If card has the low bit rate bug, + * and the speed change moved across + * the value that triggers the bug, + * need to reset the DMA / FIFO. + */ + xpds_dma_disable (card_num); + xpds_dma_enable (card_num); + } + } + xpds_data[card_num].sdsl_speed = val; + } else { + printk (KERN_ERR "Setting the SDSL speed is only applicable to SDSL.\n"); + rc = -EINVAL; + } + } else if (cmd == XPDS_IOCTL_SET_SDSL_INVERT) { + if (data_ptr->is_sdsl) { + u32 sdsl_mode; + u8 byte; + + printk ("%s: SDSL invert set to %d\n", + xpds_devs[card_num].name, val ? 1 : 0); + rc = xpds_get_flash_sdsl_mode (card_num, &sdsl_mode); + if (rc > 0) printk (KERN_ERR "%s: xpds_get_flash_sdsl_mode() failed\n", xpds_devs[card_num].name); + printk (KERN_DEBUG "%s: sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode); + sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED; + sdsl_mode &= ~ XPDS_SDSL_MODE__INVERT; + sdsl_mode |= (val ? XPDS_SDSL_MODE__INVERT : 0); + printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode); + xpds_set_sdsl_mode (card_num, sdsl_mode); + if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name); + rc = xpds_get_sdsl_exit_code (card_num, &byte); + if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) { + printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte); + rc = -EBUSY; + } + xpds_reboot_sdsl_physical_layer (card_num); + } else { + printk (KERN_ERR "Setting the invert is only applicable to SDSL.\n"); + rc = -EINVAL; + } + } else if (cmd == XPDS_IOCTL_SET_SDSL_SWAP) { + if (data_ptr->is_sdsl) { + u32 sdsl_mode; + u8 byte; + + printk ("%s: SDSL swap set to %d\n", + xpds_devs[card_num].name, val ? 1 : 0); + rc = xpds_get_flash_sdsl_mode (card_num, &sdsl_mode); + if (rc > 0) printk (KERN_ERR "%s: xpds_get_flash_sdsl_mode() failed\n", xpds_devs[card_num].name); + printk (KERN_DEBUG "%s: sdsl_mode = %08x\n", + xpds_devs[card_num].name, sdsl_mode); + sdsl_mode &= ~ XPDS_SDSL_MODE__UNUSED; + sdsl_mode &= ~ XPDS_SDSL_MODE__SWAP; + sdsl_mode |= (val ? XPDS_SDSL_MODE__SWAP : 0); + printk (KERN_DEBUG "%s: changed sdsl_mode = %08x\n", xpds_devs[card_num].name, sdsl_mode); + rc = xpds_set_sdsl_mode (card_num, sdsl_mode); + if (rc > 0) printk (KERN_ERR "%s: xpds_set_sdsl_mode() failed\n", xpds_devs[card_num].name); + rc = xpds_get_sdsl_exit_code (card_num, &byte); + if (rc > 0 || byte != XPDS_SDSL_CMD_COMPLETED) { + printk (KERN_ERR "%s: SDSL exit code indicated failure (rc=%d, ec=%d)\n", xpds_devs[card_num].name, rc, byte); + rc = -EBUSY; + } + xpds_reboot_sdsl_physical_layer (card_num); + } else { + printk (KERN_ERR "Setting the swap is only applicable to SDSL.\n"); + rc = -EINVAL; + } + } else if (cmd == XPDS_IOCTL_INSTALL_FLASH) { + rc = xpds_install_flash_image (card_num, + (xpds_flash_image_t *)(rq->ifr_data)); + if (rc > 0) rc = -EBUSY; + } else if (cmd == XPDS_IOCTL_GET_SDSL_INFO) { + if (data_ptr->is_sdsl) { + printk ("%s: getting SDSL serial info for user process\n", xpds_devs[card_num].name); + copy_to_user ((void *)(rq->ifr_data), + &(data_ptr->serial_data), + sizeof (data_ptr->serial_data)); + } else { + printk (KERN_ERR "%s: cannot get SDSL info on IDSL card\n", xpds_devs[card_num].name); + rc = -EINVAL; + } + } else if (cmd == XPDS_IOCTL_SET_SDSL_INFO) { + if (data_ptr->is_sdsl) { + printk ("%s: setting SDSL serial info from user process\n", xpds_devs[card_num].name); + copy_from_user (&(data_ptr->serial_data), + (void *)(rq->ifr_data), + sizeof (data_ptr->serial_data)); + rc = xpds_set_sdsl_info (card_num); + if (rc > 0) { + printk (KERN_ERR "%s: unable to set SDSL info\n", xpds_devs[card_num].name); + rc = -EBUSY; + } + } else { + printk (KERN_ERR "%s: cannot set SDSL info on IDSL card\n", xpds_devs[card_num].name); + rc = -EINVAL; + } + } else if (cmd == XPDS_IOCTL_GET_SDSL_STATE) { + if (data_ptr->is_sdsl) { + u8 state; + rc = xpds_sdsl_get_state (card_num, &state); + if (rc != 0) { + printk (KERN_ERR "%s: get SDSL state failed, rc = %d\n", xpds_devs[card_num].name, rc); + state = -1; + rc = -EBUSY; + } else { + printk (KERN_NOTICE "%s: SDSL state is 0x%02x\n", xpds_devs[card_num].name, state); + } + copy_to_user (rq->ifr_data, &state, 1); + } else { + printk (KERN_ERR "%s: cannot set SDSL state on IDSL card\n", xpds_devs[card_num].name); + rc = -EINVAL; + } + } else if (cmd == XPDS_IOCTL_SET_LOOPBACK) { + xpds_loopback_parameters_t loopback_params; + copy_from_user (&loopback_params, + (void *)(rq->ifr_data), + sizeof (loopback_params)); + if (loopback_params.loopback_type == XPDS_ASIC_LOOPBACK) { + if (loopback_params.on) { + printk (KERN_NOTICE "%s: setting ASIC loopback\n", xpds_devs[card_num].name); + xpds_write_control_register (card_num, XPDS_MCR_CONFIG, + XPDS_MCR_CONFIG__MODE_LOOPBACK, MAIN); + netif_start_queue(dev); + xpds_data[card_num].physical_up = 1; + } else { + printk (KERN_NOTICE "%s: unsetting ASIC loopback\n", xpds_devs[card_num].name); + xpds_write_control_register (card_num, XPDS_MCR_CONFIG, + XPDS_MCR_CONFIG__MODE_NORMAL, MAIN); + netif_stop_queue(dev); + xpds_if_down(dev); + xpds_data[card_num].physical_up = 0; + } + } else if (loopback_params.loopback_type == XPDS_SDSL_LOOPBACK) { + if (data_ptr->is_sdsl) { + printk (KERN_NOTICE "%s: setting SDSL external loopback\n", xpds_devs[card_num].name); + rc = xpds_sdsl_loopback (card_num); + if (rc != 0) { + printk (KERN_ERR "%s: setting SDSL external loopback failed, rc = %d\n", xpds_devs[card_num].name, rc); + rc = -EBUSY; + } + } else { + printk (KERN_ERR "%s: cannot set SDSL external loopback on IDSL card\n", xpds_devs[card_num].name); + rc = -EINVAL; + } + } else { + printk (KERN_ERR "%s: invalid loopback type %d\n", + xpds_devs[card_num].name, loopback_params.loopback_type); + } + } else if (cmd == XPDS_IOCTL_SET_BRIDGED_ETHERNET) { + /* + * 1 for bridged ethernet mode, 0 otherwise. + */ + printk ("%s: bridged ethernet set to %d (%s)\n", xpds_devs[card_num].name, + val, val ? "on" : "off"); + xpds_data[card_num].bridged_ethernet = val; + } else if (cmd == XPDS_IOCTL_SET_DLCI_CR) { + /* + * Should be 2, except for buggy Ascends which need 0. + */ + printk ("%s: DLCI CR set to %d\n", xpds_devs[card_num].name, val); + xpds_data[card_num].dlci_cr = val; + } else if (cmd == XPDS_IOCTL_SET_DLCI_LMI) { + /* + * 0 LMI off + * 1 LMI in LT mode (responds to LMI messages) + * 2 LMI in NT mode (generates LMI messages) + * 3 LMI in NT bidirectional mode (generates and + * responds to LMI messages) + */ + printk ("%s: DLCI LMI set to %d\n", xpds_devs[card_num].name, val); + xpds_data[card_num].dlci_lmi = val; + } else if (cmd == XPDS_IOCTL_SET_DLCI) { + printk ("%s: DLCI set to %d\n", xpds_devs[card_num].name, val); + xpds_data[card_num].dlci = val; + xpds_init_frad_data (&(xpds_data[card_num].frad_data), val); + } else { + printk (KERN_ERR "%s: received cmd = %d, data = %d\n", + xpds_devs[card_num].name, cmd, val); + rc = -EINVAL; + } + return rc; +} + +static int +xpds_init_frad_data (struct frad_local *fp, short dlci) +{ + memset (&(fp->dlci), 0, sizeof (fp->dlci)); + fp->dlci[0] = dlci; + + return 0; +} + +static int +xpds_init (struct net_device *dev) +{ + xpds_data_t *data_ptr; + int card_num; + + card_num = dev - xpds_devs; + + dprintk (KERN_DEBUG "xpds_init (%p (%d))\n", dev, card_num); + + netif_stop_queue(dev); + xpds_if_down(dev); + + ether_setup (dev); + dev->open = xpds_open; + dev->stop = xpds_stop; + dev->hard_start_xmit = /* xpds_tx */ xpds_dlci_transmit; + dev->get_stats = xpds_get_stats; + dev->set_config = xpds_set_config; + /* dev->set_mac_address = xpds_set_mac_addr; */ + /* dev->rebuild_header = xpds_rebuild_header; */ + dev->do_ioctl = xpds_ioctl; + /* dev->change_mtu = xpds_change_mtu; */ + dev->priv = &(xpds_data[card_num]); +#if DEBUG + if (xpds_debug_level) dev->flags |= IFF_DEBUG; +#endif + dev->flags &= ~ (IFF_BROADCAST | IFF_MULTICAST); + + data_ptr = dev->priv; + memset (&(data_ptr->stats), 0, sizeof (data_ptr->stats)); + + /* memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); */ + memcpy(dev->dev_addr, + xpds_data[dev - xpds_devs].serial_data.mac_address, + sizeof(dev->dev_addr)); + /* dev->hard_header_len = sizeof (struct frhdr); */ + + /* + * Make sure that the payload cannot be equal to or + * greater than the maximum packet length minus headers. + * For some reason, it must be 2 less, not 1 less??? + * If dev->mtu from ether_setup() is already smaller, + * leave it alone. + */ + if (dev->mtu > xpds_max_packet_length - sizeof (struct frhdr) - 2) { + dev->mtu = xpds_max_packet_length - sizeof (struct frhdr) - 2; + dprintk (KERN_DEBUG "dev->mtu set to %d\n", dev->mtu); + } + + xpds_init_frad_data (&(xpds_data[card_num].frad_data), + xpds_default_dlci); + + /* + * Should be set by ioctls... + */ + xpds_data[card_num].bridged_ethernet = xpds_default_bridged; + xpds_data[card_num].dlci = xpds_default_dlci; + /* dlci_cr needs to be 0 for buggy Ascends */ + xpds_data[card_num].dlci_cr = xpds_default_dlci_cr; + if (xpds_default_dlci_lmi == XPDS_DLCI_LMI_LT_OR_NT) { + if (xpds_data[card_num].is_lt) { + xpds_data[card_num].dlci_lmi = XPDS_DLCI_LMI_LT; + } else { + xpds_data[card_num].dlci_lmi = XPDS_DLCI_LMI_NT; + } + } else { + xpds_data[card_num].dlci_lmi = xpds_default_dlci_lmi; + } + + dprintk (KERN_INFO "%s: bridged ethernet mode is %d (%s)\n", + xpds_devs[card_num].name, xpds_data[card_num].bridged_ethernet, + xpds_data[card_num].bridged_ethernet ? "on" : "off"); + dprintk (KERN_INFO "%s: DLCI = %d\n", + xpds_devs[card_num].name, xpds_data[card_num].dlci); + dprintk (KERN_INFO "%s: DLCI CR = %d\n", + xpds_devs[card_num].name, xpds_data[card_num].dlci_cr); + dprintk (KERN_INFO "%s: DLCI LMI = %d\n", + xpds_devs[card_num].name, xpds_data[card_num].dlci_lmi); + + dprintk (KERN_DEBUG "xpds_init done\n"); + + return 0; +} + +#define SEPROM_SIZE 17 + +#define SEPROM_WRITE_OPCODE 0x5 +#define SEPROM_READ_OPCODE 0x6 +#define SEPROM_ERASE_OPCODE 0x7 + +#define SEPROM_READ_OPERAND_LEN 9 +#define SEPROM_READ_DATA_LEN 17 + +/* + * Read the given address out of the serial EPROM from an IDSL card. + */ +static u16 +read_seprom_data (int card_num, int address) +{ + int i; + u16 value = 0; + int opcode; + + if (address < 0 || address >= SEPROM_SIZE) { + printk (KERN_ERR "%s: read_seprom_data (%d (invalid))\n", + xpds_devs[card_num].name, address); + return 0; + } + + opcode = (SEPROM_READ_OPCODE << 6) | address; + + /* + * Clear the GPIO. + */ + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, 0xff, MAIN ); + + /* + * Enable the SK, DI, and CS bits in the GPIO, + * and set the CS. + */ + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, + XPDS_MCR_GPIO__OE_SEPROM_SK | + XPDS_MCR_GPIO__OE_SEPROM_DI | + XPDS_MCR_GPIO__GP_SEPROM_CS | + XPDS_MCR_GPIO__OE_SEPROM_CS, + MAIN ); + /* + * Give the address to the serial SEPROM. + */ + for (i = 0; i < SEPROM_READ_OPERAND_LEN; i ++) { + int bit; + + bit = opcode >> ((SEPROM_READ_OPERAND_LEN - 1) - i); + bit &= 0x1; + bit = bit ? XPDS_MCR_GPIO__GP_SEPROM_DI : 0; + /* 0 -> SK, DI */ + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, + XPDS_MCR_GPIO__GP_SEPROM_SK | + XPDS_MCR_GPIO__GP_SEPROM_DI, + MAIN); + udelay (3); + /* bit -> DI */ + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, bit, MAIN); + /* setup time */ + udelay (3); + /* 1 -> SK */ + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, XPDS_MCR_GPIO__GP_SEPROM_SK, MAIN); + /* hold time */ + udelay (3); + } + /* + * Get the data from the serial SEPROM. + */ + for (i = 0; i < SEPROM_READ_DATA_LEN; i ++) { + u32 bit; + + /* 0 -> SK */ + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_CLR, XPDS_MCR_GPIO__GP_SEPROM_SK, MAIN); + /* setup time */ + udelay (3); + /* 1 -> SK */ + xpds_write_control_register (card_num, + XPDS_MCR_GPIO_SET, XPDS_MCR_GPIO__GP_SEPROM_SK, MAIN); + /* hold time */ + udelay (3); + + /* read bit */ + xpds_read_control_register (card_num, XPDS_MCR_GPIO_SET, + &bit, MAIN); + bit &= XPDS_MCR_GPIO__GP_SEPROM_DO; + bit = bit ? 1 : 0; + value <<= 1; + value |= bit; + } + value >>= 1; + + /* + dprintk (KERN_DEBUG "%s: read_seprom (%d) -> %x\n", + xpds_devs[card_num].name, address, value); + */ + + return value; +} + +#define SEPROM_REVISION 0 +#define SEPROM_HARDWARE_VERSION 1 +#define SEPROM_SOFTWARE_VERSION 2 +#define SEPROM_FIRMWARE_VERSION 2 +#define SEPROM_MFG_DATE_HI 4 +#define SEPROM_MFG_DATE_LO 5 +#define SEPROM_MAC_ADDR_0_1 6 +#define SEPROM_MAC_ADDR_2_3 7 +#define SEPROM_MAC_ADDR_4_5 8 +#define SEPROM_SERIAL_0 9 +#define SEPROM_SERIAL_1 10 +#define SEPROM_SERIAL_2 11 +#define SEPROM_SERIAL_3 12 +#define SEPROM_SERIAL_4 13 +#define SEPROM_SERIAL_5 14 +#define SEPROM_SERIAL_6 15 +#define SEPROM_SERIAL_7 16 + +/* + * Determine if the card is an IDSL or SDSL card. Only the IDSL + * card has the serial EPROM, so garbage indicates an SDSL card. + * Note: an FPGA card will have is_sdsl set to 1; read_sdsl_info() + * will set is_sdsl back to 0 if it appears to be an IDSL FPGA card. + * If IDSL, determine if it has the last byte bug. + */ +static void +read_seprom_info (int card_num) +{ + u16 value1, value2, value3, value4; + xpds_serial_data_t *sdata; + + if (xpds_data[card_num].is_fpga) { + /* + * FPGA card may be SDSL, so set is_sdsl so that + * read_sdsl_info() is called. read_sdsl_info() + * will unset if unable to get SDSL information. + */ + xpds_data[card_num].is_sdsl = 1; + dprintk (KERN_INFO "No serial EPROM for FPGA device.\n"); + return; + } + + sdata = &(xpds_data[card_num].serial_data); + + value1 = read_seprom_data (card_num, SEPROM_SERIAL_0); + value2 = read_seprom_data (card_num, SEPROM_SERIAL_1); + value3 = read_seprom_data (card_num, SEPROM_SERIAL_2); + value4 = read_seprom_data (card_num, SEPROM_SERIAL_3); + if (value1 != 0x5854 /* 'XT' */ || value2 != 0x414e /* 'AN' */ || + value3 != 0x3230 /* '20' */ || (value4 >> 8) != '0') { + dprintk (KERN_DEBUG "Serial EPROM serial number does not begin with XTAN200; not an IDSL card.\n"); + xpds_data[card_num].is_sdsl = 1; + return; + } + + value1 = read_seprom_data (card_num, SEPROM_REVISION); + dprintk (KERN_DEBUG "Serial EPROM revision %d\n", value1); + sdata->seprom_revision = value1; + + value1 = read_seprom_data (card_num, SEPROM_HARDWARE_VERSION); + dprintk (KERN_DEBUG "Hardware version %d.%d\n", + value1 >> 8, value1 & 0xff); + sdata->hardware_version[0] = value1 >> 8; + sdata->hardware_version[1] = value1 & 0xff; + + value1 = read_seprom_data (card_num, SEPROM_SOFTWARE_VERSION); + dprintk (KERN_DEBUG "Software version %d.%d\n", + value1 >> 8, value1 & 0xff); + sdata->software_version[0] = value1 >> 8; + sdata->software_version[1] = value1 & 0xff; + + value1 = read_seprom_data (card_num, SEPROM_FIRMWARE_VERSION); + dprintk (KERN_DEBUG "Firmware version %d.%d\n", + value1 >> 8, value1 & 0xff); + sdata->firmware_version[0] = value1 >> 8; + sdata->firmware_version[1] = value1 & 0xff; + + value1 = read_seprom_data (card_num, SEPROM_MFG_DATE_HI); + value2 = read_seprom_data (card_num, SEPROM_MFG_DATE_LO); + dprintk (KERN_DEBUG "Manufacturing date %d.%d.%d\n", + value1, value2 >> 8, value2 & 0xff); + sdata->mfg_date[0] = value1 >> 8; + sdata->mfg_date[1] = value1 & 0xff; + sdata->mfg_date[2] = value2 >> 8; + sdata->mfg_date[3] = value2 & 0xff; + + value1 = read_seprom_data (card_num, SEPROM_MAC_ADDR_0_1); + value2 = read_seprom_data (card_num, SEPROM_MAC_ADDR_2_3); + value3 = read_seprom_data (card_num, SEPROM_MAC_ADDR_4_5); + dprintk (KERN_DEBUG "MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + value1 >> 8, value1 & 0xff, value2 >> 8, value2 & 0xff, + value3 >> 8, value3 & 0xff); + sdata->mac_address[0] = value1 >> 8; + sdata->mac_address[1] = value1 & 0xff; + sdata->mac_address[2] = value2 >> 8; + sdata->mac_address[3] = value2 & 0xff; + sdata->mac_address[4] = value3 >> 8; + sdata->mac_address[5] = value3 & 0xff; + + dprintk (KERN_DEBUG "Serial number "); + value1 = read_seprom_data (card_num, SEPROM_SERIAL_0); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[0] = value1 >> 8; + sdata->serial_number[1] = value1 & 0xff; + value1 = read_seprom_data (card_num, SEPROM_SERIAL_1); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[2] = value1 >> 8; + sdata->serial_number[3] = value1 & 0xff; + value1 = read_seprom_data (card_num, SEPROM_SERIAL_2); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[4] = value1 >> 8; + sdata->serial_number[5] = value1 & 0xff; + value1 = read_seprom_data (card_num, SEPROM_SERIAL_3); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[6] = value1 >> 8; + sdata->serial_number[7] = value1 & 0xff; + value1 = read_seprom_data (card_num, SEPROM_SERIAL_4); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[8] = value1 >> 8; + sdata->serial_number[9] = value1 & 0xff; + value1 = read_seprom_data (card_num, SEPROM_SERIAL_5); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[10] = value1 >> 8; + sdata->serial_number[11] = value1 & 0xff; + value1 = read_seprom_data (card_num, SEPROM_SERIAL_6); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[12] = value1 >> 8; + sdata->serial_number[13] = value1 & 0xff; + value1 = read_seprom_data (card_num, SEPROM_SERIAL_7); + dprintk ("%c%c", value1 >> 8, value1 & 0xff); + sdata->serial_number[14] = value1 >> 8; + sdata->serial_number[15] = value1 & 0xff; + dprintk ("\n"); +} + +/* + * Read information from the SDSL card (previously identified + * because the serial EPROM did not exist). + * Note that if the mailbox reads fail, it is probably an IDSL + * FPGA card. + */ +static int +read_sdsl_info (int card_num) +{ + u8 byte, byte1, byte2; + int i, rc, rval = 0; + xpds_serial_data_t *sdata; + + if (! xpds_data[card_num].is_sdsl) return 1; + + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_HWVER, &byte1); + if (rc) rval = 1; + + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_HWVER, &byte2); + if (rc) rval = 1; + + if (rval) { + /* IDSL FPGA card */ + xpds_data[card_num].is_sdsl = 0; + return rval; + } + + sdata = &(xpds_data[card_num].serial_data); + + dprintk (KERN_INFO "Hardware version "); + dprintk ("%d.", byte1); + dprintk ("%d\n", byte2); + + sdata->hardware_version[0] = byte1; + sdata->hardware_version[1] = byte2; + + dprintk (KERN_INFO "Firmware version "); + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_FWVER, &byte); + dprintk ("%d.", byte); + if (rc) rval = 1; + sdata->firmware_version[0] = byte; + + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_FWVER, &byte); + dprintk ("%d\n", byte); + if (rc) rval = 1; + sdata->firmware_version[1] = byte; + + if (rval) return rval; + + dprintk (KERN_INFO "Manufacturing date "); + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte1); + if (rc) rval = 1; + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte2); + if (rc) rval = 1; + dprintk ("%d.", (byte1 << 8) + byte2); + sdata->mfg_date[0] = byte1; + sdata->mfg_date[1] = byte2; + + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte); + if (rc) rval = 1; + dprintk ("%d.", byte); + sdata->mfg_date[2] = byte; + + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MFGDATE, &byte); + if (rc) rval = 1; + dprintk ("%d\n", byte); + sdata->mfg_date[3] = byte; + + if (rval) return rval; + + dprintk (KERN_INFO "MAC address "); + for (i = 0; i < 6; i ++) { + if (i != 0) dprintk (":"); + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_MACADDR, &byte); + dprintk ("%02x", byte); + if (rc) rval = 1; + sdata->mac_address[i] = byte; + } + dprintk ("\n"); + + if (rval) return rval; + + dprintk (KERN_INFO "Serial number "); + for (i = 0; i < 16; i ++) { + rc = xpds_mailbox_read (card_num, XPDS_MBX_READ_SERIALNUMBER, &byte); + dprintk ("%c", byte); + if (rc) rval = 1; + sdata->serial_number[i] = byte; + } + dprintk ("\n"); + + return rval; +} + +static int +get_pci_config (struct pci_dev *dev, volatile void **config_mem) +{ + u32 value; + int rc; + + rc = pci_read_config_dword (dev, PCI_BASE_ADDRESS_0, &value); + + if (rc != PCIBIOS_SUCCESSFUL) { + printk (KERN_ERR "unable to read PCI configuration register 4, error = %d\n", rc); + return -EIO; + } + + dprintk (KERN_DEBUG "PCI config register 4 value=%08x\n", value); + + value &= PCI_BASE_ADDRESS_IO_MASK; + + *config_mem = ioremap (value, 32768); + + dprintk (KERN_DEBUG "remapped hw_config_mem=%08x\n", (u32) *config_mem); +#if (LINUX_VERSION_CODE < 0x02030d) + dprintk (KERN_DEBUG "dev->base_address[0]=%08x\n", (u32) dev->base_address[0]); + dprintk (KERN_DEBUG "dev->base_address[1]=%08x\n", (u32) dev->base_address[1]); + dprintk (KERN_DEBUG "dev->base_address[2]=%08x\n", (u32) dev->base_address[2]); + dprintk (KERN_DEBUG "dev->base_address[3]=%08x\n", (u32) dev->base_address[3]); + dprintk (KERN_DEBUG "dev->base_address[4]=%08x\n", (u32) dev->base_address[4]); + dprintk (KERN_DEBUG "dev->base_address[5]=%08x\n", (u32) dev->base_address[5]); +#else + dprintk (KERN_DEBUG "dev->base_address[0]=%08x\n", (u32) dev->resource[0].start); + dprintk (KERN_DEBUG "dev->base_address[1]=%08x\n", (u32) dev->resource[1].start); + dprintk (KERN_DEBUG "dev->base_address[2]=%08x\n", (u32) dev->resource[2].start); + dprintk (KERN_DEBUG "dev->base_address[3]=%08x\n", (u32) dev->resource[3].start); + dprintk (KERN_DEBUG "dev->base_address[4]=%08x\n", (u32) dev->resource[4].start); + dprintk (KERN_DEBUG "dev->base_address[5]=%08x\n", (u32) dev->resource[5].start); +#endif + + return config_mem == NULL ? -ENOMEM : 0; +} + +#define TRIES 8 + +static int +allocate_rxtx_buffers (int xpds_num, int num_rxtx, volatile void **rxtx_mem, + volatile xpds_rxtx_list_t **rx_list, + volatile xpds_rxtx_list_t **tx_list) +{ + int size, i, j; + volatile u8 *rx_buffer, *tx_buffer; + volatile xpds_rxtx_list_t *rx_ptr, *tx_ptr; + volatile void *old_mem[TRIES]; + + size = (num_rxtx + num_rxtx) * sizeof (xpds_rxtx_list_t) + + (num_rxtx + num_rxtx) * RXTX_BUFFER_SIZE; + + /* + * Prevent RX/TX memory from crossing a 16 bit page (64k + * byte) boundary. This is due to a hardware limitation. + */ + memset (old_mem, 0, sizeof (old_mem)); + for (i = 0; i < TRIES; i ++) { + u32 start, end; + + *rxtx_mem = kmalloc (size + 16, GFP_KERNEL /* | GFP_DMA */); + if (*rxtx_mem == NULL) break; + + start = virt_to_bus (*rxtx_mem); + end = start + size + 16; + + start &= 0xffff; + end &= 0xffff; + + if (start < end) break; + + printk (KERN_DEBUG "%s: RX/TX buffer allocation crossed 16 bit boundary, reallocating.\n", xpds_devs[xpds_num].name); + old_mem[i] = *rxtx_mem; + } + for (j = 0; j < i; j ++) { + if (old_mem[j] != NULL) kfree ((void *)(old_mem[j])); + } + if (i == TRIES || *rxtx_mem == NULL) return -ENOMEM; + + xpds_data[xpds_num].rxtx_mem_allocated = *rxtx_mem; + + if ((u32)*rxtx_mem & 0xf) { + *rxtx_mem = (volatile void *) (((u32) *rxtx_mem + 16) & 0xfffffff0); + } + + *rx_list = (volatile xpds_rxtx_list_t *) *rxtx_mem; + *tx_list = (volatile xpds_rxtx_list_t *) ((u32) *rxtx_mem + + sizeof (xpds_rxtx_list_t) * num_rxtx); + + rx_buffer = (volatile u8 *) ((u32) *tx_list + + sizeof (xpds_rxtx_list_t) * num_rxtx); + tx_buffer = (volatile u8 *) ((u32) rx_buffer + + RXTX_BUFFER_SIZE * num_rxtx); + + rx_ptr = *rx_list; + tx_ptr = *tx_list; + + for (i = 0; i < num_rxtx; i ++) { + rx_ptr->control = RXTX_CONTROL__NEXT_VALID | RXTX_CONTROL__HWGO; + rx_ptr->buffer = rx_buffer + i * RXTX_BUFFER_SIZE; + rx_ptr->buffer_bus_addr = virt_to_bus (rx_ptr->buffer); + rx_ptr->next = (i == num_rxtx - 1) ? + *rx_list : + (volatile xpds_rxtx_list_t *) ((u32) rx_ptr + + sizeof (xpds_rxtx_list_t)); + rx_ptr->next_bus_addr = virt_to_bus (rx_ptr->next); + rx_ptr->unused1 = 0; + rx_ptr->prev = (i == 0) ? + (volatile xpds_rxtx_list_t *) ((u32) *rx_list + + sizeof (xpds_rxtx_list_t) * (num_rxtx - 1)) : + (volatile xpds_rxtx_list_t *) ((u32) rx_ptr - + sizeof (xpds_rxtx_list_t)); + rx_ptr->offset = 0; + rx_ptr = rx_ptr->next; + + tx_ptr->control = RXTX_CONTROL__NEXT_VALID; + tx_ptr->buffer = tx_buffer + i * RXTX_BUFFER_SIZE; + tx_ptr->buffer_bus_addr = virt_to_bus (tx_ptr->buffer); + tx_ptr->next = (i == num_rxtx - 1) ? + *tx_list : + (volatile xpds_rxtx_list_t *) ((u32) tx_ptr + + sizeof (xpds_rxtx_list_t)); + tx_ptr->next_bus_addr = virt_to_bus (tx_ptr->next); + tx_ptr->unused1 = 0; + tx_ptr->prev = (i == 0) ? + (volatile xpds_rxtx_list_t *) ((u32) *tx_list + + sizeof (xpds_rxtx_list_t) * (num_rxtx - 1)) : + (volatile xpds_rxtx_list_t *) ((u32) tx_ptr - + sizeof (xpds_rxtx_list_t)); + tx_ptr->offset = 0; + tx_ptr = tx_ptr->next; + } + + dprintk (KERN_DEBUG "rxtx_mem = %08x, rx_list = %08x, tx_list = %08x,\n", + (u32) *rxtx_mem, (u32) *rx_list, (u32) *tx_list); + dprintk (KERN_DEBUG "rx_buffer = %08x, tx_buffer = %08x\n", + (u32) rx_buffer, (u32) tx_buffer); + return 0; +} + +/* + * Given a pointer to memory, set the control register pointers. + */ +static int +set_control_register_pointers (int xpds_num, volatile void *mem, + volatile xpds_rxtx_list_t *rx_list, volatile xpds_rxtx_list_t *tx_list) +{ + int rc; + + dprintk (KERN_DEBUG "setting %s: control register pointers\n", xpds_devs[xpds_num].name); + xpds_data[xpds_num].main_control_registers = + (volatile u32 *) ( (volatile u8 *) mem + 0x0000 ); + xpds_data[xpds_num].rx_fifo_control_registers = + (volatile u32 *) ( (volatile u8 *) mem + 0x0050 ); + xpds_data[xpds_num].tx_fifo_control_registers = + (volatile u32 *) ( (volatile u8 *) mem + 0x0040 ); + xpds_data[xpds_num].rx_dma_control_registers = + (volatile u32 *) ( (volatile u8 *) mem + 0x00c0 ); + xpds_data[xpds_num].tx_dma_control_registers = + (volatile u32 *) ( (volatile u8 *) mem + 0x0080 ); + xpds_data[xpds_num].rx_fifo_data_registers = + (volatile u32 *) ( (volatile u8 *) mem + + (xpds_data[xpds_num].is_fpga ? 0x0600 : 0x0500) ); + xpds_data[xpds_num].tx_fifo_data_registers = + (volatile u32 *) ( (volatile u8 *) mem + 0x0400 ); + xpds_data[xpds_num].aux_registers = + (volatile u32 *) ( (volatile u8 *) mem + 0x0060 ); + dprintk (KERN_DEBUG "memory=%08x\n", (u32)mem); + dprintk (KERN_DEBUG "main_control_registers=%08x\n", + (u32)(xpds_data[xpds_num].main_control_registers)); + dprintk (KERN_DEBUG "rx_fifo_control_registers=%08x\n", + (u32)(xpds_data[xpds_num].rx_fifo_control_registers)); + dprintk (KERN_DEBUG "tx_fifo_control_registers=%08x\n", + (u32)(xpds_data[xpds_num].tx_fifo_control_registers)); + dprintk (KERN_DEBUG "rx_dma_control_registers=%08x\n", + (u32)(xpds_data[xpds_num].rx_dma_control_registers)); + dprintk (KERN_DEBUG "tx_dma_control_registers=%08x\n", + (u32)(xpds_data[xpds_num].tx_dma_control_registers)); + dprintk (KERN_DEBUG "rx_fifo_data_registers=%08x\n", + (u32)(xpds_data[xpds_num].rx_fifo_data_registers)); + dprintk (KERN_DEBUG "tx_fifo_data_registers=%08x\n", + (u32)(xpds_data[xpds_num].tx_fifo_data_registers)); + dprintk (KERN_DEBUG "aux_registers=%08x\n", + (u32)(xpds_data[xpds_num].aux_registers)); + + /* + * Install the buffer lists for RX and TX DMA. + */ + xpds_data[xpds_num].rx_dma_list = rx_list; + dprintk (KERN_DEBUG "initializing %s: RX DMA Status Address:\n", xpds_devs[xpds_num].name); + rc = xpds_write_control_register (xpds_num, XPDS_DMA_STAT_ADDR, + (u32) rx_list, RX_DMA); + if (rc != 0) return rc; + dprintk ("\n"); + xpds_data[xpds_num].tx_dma_list = tx_list; + dprintk (KERN_DEBUG "initializing %s: TX DMA Status Address:\n", xpds_devs[xpds_num].name); + rc = xpds_write_control_register (xpds_num, XPDS_DMA_STAT_ADDR, + (u32) tx_list, TX_DMA); + dprintk ("\n"); + if (rc != 0) return rc; + + return 0; +} + +static int +xpds_alloc_data (void) +{ + int rc; + + if (xpds_data == NULL) { + xpds_data = kmalloc (sizeof (*xpds_data) * xpds_max_cards, GFP_KERNEL); + if (xpds_data == NULL) return -ENOMEM; + memset (xpds_data, 0, sizeof (*xpds_data) * xpds_max_cards); + } + if (xpds_names == NULL) { + xpds_names = kmalloc (NAME_SIZE * xpds_max_cards, GFP_KERNEL); + if (xpds_names == NULL) return -ENOMEM; + memset (xpds_names, 0, NAME_SIZE * xpds_max_cards); + } + if (xpds_reset_bh_tasks == NULL) { + xpds_reset_bh_tasks = kmalloc (sizeof (*xpds_reset_bh_tasks) * xpds_max_cards, GFP_KERNEL); + if (xpds_reset_bh_tasks == NULL) return -ENOMEM; + memset (xpds_reset_bh_tasks, 0, sizeof (*xpds_reset_bh_tasks) * xpds_max_cards); + } + if (xpds_interrupt_bh_tasks == NULL) { + int i; + xpds_interrupt_bh_tasks = kmalloc (sizeof (*xpds_interrupt_bh_tasks) * xpds_max_cards, GFP_KERNEL); + if (xpds_interrupt_bh_tasks == NULL) return -ENOMEM; + memset (xpds_interrupt_bh_tasks, 0, sizeof (*xpds_interrupt_bh_tasks) * xpds_max_cards); + for (i = 0; i < xpds_max_cards; i ++) { + xpds_interrupt_bh_tasks[i].data = kmalloc (sizeof (interrupt_bh_data_t), GFP_KERNEL); + xpds_interrupt_bh_tasks[i].next = NULL; + xpds_interrupt_bh_tasks[i].sync = 0; + xpds_interrupt_bh_tasks[i].routine = xpds_interrupt_bh; + } + } + if (xpds_devs == NULL) { + int i; + xpds_devs = kmalloc (sizeof (*xpds_devs) * xpds_max_cards, GFP_KERNEL); + if (xpds_devs == NULL) return -ENOMEM; + memset (xpds_devs, 0, sizeof (*xpds_devs) * xpds_max_cards); + + for (i = 0; i < xpds_max_cards; i ++) { +#if (LINUX_VERSION_CODE < HAS_SOFT_NET) + xpds_devs[i].name = xpds_names + NAME_SIZE * i; +#endif + xpds_devs[i].init = xpds_init; + } + } + rc = xpds_sdsl_allocate (); + if (rc) return rc; + return 0; +} + +static void +xpds_free_data (void) +{ + if (xpds_data != NULL) kfree (xpds_data); + if (xpds_names != NULL) kfree (xpds_names); + if (xpds_reset_bh_tasks != NULL) kfree (xpds_reset_bh_tasks); + if (xpds_devs != NULL) kfree (xpds_devs); + xpds_sdsl_cleanup (); +} + +#ifdef MODULE +int init_module (void) +#else +int xpdsl_init(void) +#endif +{ + int i; + int rc; + volatile xpds_rxtx_list_t *rx_list, *tx_list; + volatile void *rxtx_mem; + int found_sdsl = 0; + struct pci_dev *dev = NULL; +#if ALLOW_OLD_PCI_VENDOR_ID + int old_offset = -1; +#endif + + printk (KERN_NOTICE "xpds.c: Xpeed XPDS frame relay driver %s, linux@xpeed.com, Copyright 1999, 2000 Xpeed, Inc.\n", VERSION_STRING); + rc = xpds_alloc_data (); + if (rc != 0) { + printk (KERN_ERR "Unable to allocate memory for XPDS data.\n"); + xpds_free_data (); + return rc; + } + + dprintk (KERN_DEBUG "xpds_data = %p, &(xpds_data[0].rxci_interrupt_received) = %p\n", xpds_data, &(xpds_data[0].rxci_interrupt_received)); + + /* + * Make sure that there is a PCI present, and the + * desired device is there. + */ + if ( ! pci_present ()) { + printk (KERN_ERR "No PCI present.\n"); + xpds_free_data (); + return -ENODEV; + } + + for (i = 0; i < xpds_max_cards; i ++) { + char devname[NAME_SIZE], name[NAME_SIZE]; + int n; + + sprintf (devname, "%.*s%%d", NAME_SIZE - 4, xpds_dev_name); + n = dev_alloc_name (&(xpds_devs[i]), devname); + if (n < 0) { + printk(KERN_ERR "%s: dev_alloc_name failed (%d)\n", xpds_dev_name, n); + xpds_free_data (); + return -ENODEV; + } + sprintf (name, "%.*s%d", NAME_SIZE - 4, xpds_dev_name, n); + strcpy (xpds_devs[i].name, name); + } + + for (i = 0; i < xpds_max_cards; i ++) { + memset (&(xpds_data[i]), 0, sizeof (xpds_data[i])); + xpds_data[i].speed_mode = xpds_mode; + +#if ALLOW_OLD_PCI_VENDOR_ID + if (old_offset < 0) { + dev = pci_find_device (PCI_VENDOR_ID_XPDS, + PCI_DEVICE_ID_XPDS_1, dev); + if (dev == NULL) { + old_offset = i; + dev = pci_find_device (PCI_VENDOR_ID_XPDS_OLD, + PCI_DEVICE_ID_XPDS_1, dev); + } + } else { + dev = pci_find_device (PCI_VENDOR_ID_XPDS_OLD, + PCI_DEVICE_ID_XPDS_1, dev); + } +#else + dev = pci_find_device (PCI_VENDOR_ID_XPDS, + PCI_DEVICE_ID_XPDS_1, dev); +#endif + if (dev == NULL) break; + dprintk (KERN_DEBUG "dev = %p\n", dev); + + xpds_data[i].pci_dev = dev; + + pci_set_master (dev); + +#if ALLOW_OLD_PCI_VENDOR_ID + if (old_offset >= 0) { + dprintk (KERN_DEBUG "XPDS FPGA device %d at pci_bus=0x%02x, pci_dev_fn=0x%02x, pci_irq_line=0x%02x.\n", + i, + xpds_data[i].pci_dev->bus->number, + xpds_data[i].pci_dev->devfn, + xpds_data[i].pci_dev->irq); + xpds_data[i].is_fpga = 1; + } else { + dprintk (KERN_DEBUG "XPDS device %d found at pci_bus=0x%02x, pci_dev_fn=0x%02x, pci_irq_line=0x%02x.\n", + i, + xpds_data[i].pci_dev->bus->number, + xpds_data[i].pci_dev->devfn, + xpds_data[i].pci_dev->irq); + xpds_data[i].is_fpga = 0; + } +#else + dprintk (KERN_DEBUG "XPDS device %d found at pci_bus=0x%02x, pci_dev_fn=0x%02x, pci_irq_line=0x%02x.\n", + i, + xpds_data[i].pci_dev->bus->number, + xpds_data[i].pci_dev->devfn, + xpds_data[i].pci_dev->irq); + xpds_data[i].is_fpga = 0; +#endif + + /* + * Get the 32k of memory from hardware. + */ + dprintk (KERN_DEBUG "%s: setting up PCI configuration\n", xpds_devs[i].name); + rc = get_pci_config (xpds_data[i].pci_dev, + &(xpds_data[i].config_mem_remapped)); + if (rc != 0) { + xpds_free_data (); + return rc; + } + + /* + * Allocate the RX and TX lists and buffers. + */ + dprintk (KERN_DEBUG "%s: allocating RX/TX buffers\n", xpds_devs[i].name); + rc = allocate_rxtx_buffers (i, NUM_DESC, &rxtx_mem, + &rx_list, &tx_list); + if (rc != 0) { + xpds_free_data (); + return rc; + } + + /* + * Set up the control register pointers to the RX/TX buffers. + */ + rc = set_control_register_pointers (i, + xpds_data[i].config_mem_remapped, rx_list, tx_list); + if (rc != 0) { + xpds_free_data (); + return rc; + } + + /* + * Read the serial EPROM for some more information + * about the device. May set xpds_data[i].is_sdsl or + * xpds_data[i].has_last_byte_bug . + */ + read_seprom_info (i); + + /* + * If the serial EPROM read failed, then it should be + * an SDSL device. Read the information from the SDSL + * device. If an error, then something is wrong... + */ + if (xpds_data[i].is_sdsl) { + xpds_reset_sdsl (i); + xpds_start_sdsl (i); + DELAY_HZ (3 * HZ / 2, i); + rc = read_sdsl_info (i); + if (rc != 0) { + if (xpds_data[i].is_sdsl) { + printk (KERN_ERR "%s: Unable to determine if %s is an IDSL or SDSL card.\n", xpds_devs[i].name, xpds_devs[i].name); + printk (KERN_ERR "%s: %s may be defective\n", xpds_devs[i].name, xpds_devs[i].name); + if (! xpds_load_for_flash) { + xpds_free_data (); + return -ENODEV; + } + } else { + /* FPGA IDSL board */ + printk (KERN_DEBUG "%s: %s has no SDSL infomation.\n", xpds_devs[i].name, xpds_devs[i].name); + printk (KERN_DEBUG "%s: is assumed to be an FPGA IDSL card.\n", xpds_devs[i].name); + } + } + } + + /* + * Hardware bugs: + * ASIC < 1.1: last byte corruption bug + * hardware < 1.1: RX DMA burst bug + * hardware < 1.2: TX DMA burst bug + */ + if (! xpds_data[i].is_fpga && ! xpds_is_hardware_version (i, 1, 1)) { + dprintk (KERN_DEBUG "Has last byte bug, using workaround.\n"); + xpds_data[i].has_last_byte_bug = 1; + } + + if (! xpds_is_hardware_version (i, 1, 1)) { + dprintk (KERN_DEBUG "Has RX DMA burst bug, not using RX DMA burst mode.\n"); + xpds_data[i].has_rx_dma_burst_bug = 1; + } + + if (! xpds_is_hardware_version (i, 1, 2)) { + dprintk (KERN_DEBUG "Has TX DMA burst bug, not using TX DMA burst mode.\n"); + xpds_data[i].has_tx_dma_burst_bug = 1; + dprintk (KERN_DEBUG "Has TX DMA low rate (<%d Kbps) bug.\n", LOW_BIT_RATE); + xpds_data[i].has_tx_dma_low_rate_bug = 1; + } + + printk (KERN_DEBUG "%s: Xpeed %c00 %cDSL NIC, %02X %02X %02X %02X %02X %02X, IRQ %d.\n", + xpds_devs[i].name, + xpds_data[i].is_sdsl ? '3' : '2', + xpds_data[i].is_sdsl ? 'S' : 'I', + xpds_data[i].serial_data.mac_address[0], + xpds_data[i].serial_data.mac_address[1], + xpds_data[i].serial_data.mac_address[2], + xpds_data[i].serial_data.mac_address[3], + xpds_data[i].serial_data.mac_address[4], + xpds_data[i].serial_data.mac_address[5], + xpds_data[i].pci_dev->irq); + + if (xpds_data[i].is_sdsl) { + int rc; + u32 mode, speed, swap, invert, nt; + + rc = xpds_get_flash_sdsl_mode (i, &mode); + + if (rc) { + printk (KERN_ERR "%s: unable to get speed, swap, and invert\n", xpds_devs[i].name); + } else { + speed = (mode & XPDS_SDSL_MODE__SPEED_MASK) << 3; + nt = (mode & XPDS_SDSL_MODE__NT); + swap = (mode & XPDS_SDSL_MODE__SWAP); + invert = (mode & XPDS_SDSL_MODE__INVERT); + printk (KERN_DEBUG "%s: speed = %d%s, swap %s, invert %s, %s mode\n", xpds_devs[i].name, speed, (speed == 0) ? " (CM auto)" : "", swap ? "on" : "off", invert ? "on" : "off", nt ? "NT" : "LT"); + } + } + + if (xpds_data[i].is_sdsl) found_sdsl = 1; + + /* + * Register network device. + */ + rc = register_netdev (&(xpds_devs[i])); + if (rc != 0) { + xpds_free_data (); + return rc; + } + } + + num_xpds_found = i; + + if (num_xpds_found < 1) { + printk (KERN_ERR "PCI error: XPDS device not found.\n"); + xpds_free_data (); + return -ENODEV; + } + + return 0; +} + +void cleanup_module (void) +{ + int i; + + for (i = 0; i < num_xpds_found; i ++) { + if (xpds_data[i].rxtx_mem_allocated != NULL) { + kfree ((void *)(xpds_data[i].rxtx_mem_allocated)); + } + if (xpds_data[i].config_mem_remapped != NULL) { + iounmap ((void *)(xpds_data[i].config_mem_remapped)); + } + dprintk (KERN_DEBUG "unregistering XPDS network device %d\n", i); + unregister_netdev (&(xpds_devs[i])); + } + xpds_free_data (); + dprintk (KERN_DEBUG "removing Xpeed XPDS frame relay driver\n"); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/net/xpds/xpds.h linux/drivers/net/xpds/xpds.h --- v2.2.17/drivers/net/xpds/xpds.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/net/xpds/xpds.h Sun Oct 15 21:57:15 2000 @@ -0,0 +1,121 @@ +/* + * Copyright 1998, 1999, 2000 Xpeed, Inc. + * xpds-fr.h, $Revision: 1.10 $ + */ +#ifndef XPDS_H +#define XPDS_H 1 + +#include +#include "xpds-encap-fr.h" +#include + +extern int xpds_max_cards; + +#define DEBUG_MAIN 1 +#define DEBUG_FSM 2 +#define DEBUG_DETAILED 128 + +extern int xpds_debug_level; + +typedef struct xpds_rxtx_list_t { + volatile u32 control; + u32 buffer_bus_addr; + u32 next_bus_addr; + u32 unused1; + volatile u8 *buffer; + volatile struct xpds_rxtx_list_t *next; + volatile struct xpds_rxtx_list_t *prev; + u32 offset; +} xpds_rxtx_list_t; + +typedef struct { + struct pci_dev *pci_dev; + volatile u32 *main_control_registers; + volatile u32 *rx_fifo_control_registers; + volatile u32 *tx_fifo_control_registers; + volatile u32 *rx_dma_control_registers; + volatile u32 *tx_dma_control_registers; + volatile u32 *rx_fifo_data_registers; + volatile u32 *tx_fifo_data_registers; + volatile u32 *aux_registers; + volatile void *rxtx_mem_allocated; + volatile xpds_rxtx_list_t *rx_dma_list; + volatile xpds_rxtx_list_t *tx_dma_list; + volatile xpds_rxtx_list_t *current_rx_dma; + volatile xpds_rxtx_list_t *current_tx_dma; + struct net_device_stats stats; + volatile int rxci_interrupt_received; + int physical_up; + int physical_retrying; + int is_fpga; + int has_last_byte_bug; + int is_sdsl; + int is_lt; + int speed_mode; + short dlci; + xpds_serial_data_t serial_data; + int has_rx_dma_burst_bug; + int has_tx_dma_burst_bug; + volatile void *config_mem_remapped; + int has_tx_dma_low_rate_bug; + int sdsl_speed; + int current_tx_fifo; + volatile xpds_rxtx_list_t *current_hw_tx_dma; + int current_rx_fifo; + volatile xpds_rxtx_list_t *current_hw_rx_dma; + int has_rx_dma_low_rate_bug; + struct frad_local frad_data; + int bridged_ethernet; + u8 dlci_cr; + u8 dlci_lmi; + dlci_lmi_timer_data_t dlci_lmi_timer_data[CONFIG_DLCI_COUNT]; + struct timer_list dlci_lmi_timers[CONFIG_DLCI_COUNT]; +} xpds_data_t; + +extern struct net_device *xpds_devs; +extern xpds_data_t *xpds_data; + +extern int xpds_read_control_register_quiet (int xpds_num, int register_number, + u32 *value, int which); +extern int xpds_write_control_register_quiet (int xpds_num, int register_number, + u32 value, int which); +extern int xpds_read_control_register (int xpds_num, int register_number, + u32 *value, int which); +extern int xpds_write_control_register (int xpds_num, int register_number, + u32 value, int which); + +#define XPDS_MAIN 0 +#define XPDS_RX_FIFO 2 +#define XPDS_TX_FIFO 3 +#define XPDS_RX_DMA 4 +#define XPDS_TX_DMA 5 +#define XPDS_RX_FIFO_DATA 6 +#define XPDS_TX_FIFO_DATA 7 +#define XPDS_AUX 8 + +#define MAIN XPDS_MAIN +#define RX_FIFO XPDS_RX_FIFO +#define TX_FIFO XPDS_TX_FIFO +#define RX_DMA XPDS_RX_DMA +#define TX_DMA XPDS_TX_DMA +#define RX_FIFO_DATA XPDS_RX_FIFO_DATA +#define TX_FIFO_DATA XPDS_TX_FIFO_DATA +#define AUX XPDS_AUX + +extern int xpds_tx (u8 *buffer, unsigned int len, struct net_device *dev); + +#ifdef __SMP__ +#define schedule_if_no_interrupt(card_num) \ + do { \ + } while (0) +#else +#define schedule_if_no_interrupt(card_num) \ + do { \ + if (!in_interrupt()) schedule (); \ + } while (0) +#endif + +#define DELAY(n,card_num) schedule_timeout(HZ*(n)) +#define DELAY_HZ(n,card_num) schedule_timeout(n) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/nubus/Makefile linux/drivers/nubus/Makefile --- v2.2.17/drivers/nubus/Makefile Fri Apr 21 12:46:24 2000 +++ linux/drivers/nubus/Makefile Fri Oct 13 23:52:23 2000 @@ -9,7 +9,19 @@ # parent makefile. # -L_OBJS := nubus.o L_TARGET := nubus.a + +ifeq ($(CONFIG_MODULES),y) +O_TARGET := nubus_n_syms.o +OX_OBJS := nubus_syms.o +O_OBJS := nubus.o +L_OBJS := nubus_n_syms.o +else +L_OBJS := nubus.o +endif + +ifdef CONFIG_PROC_FS +L_OBJS += proc.o +endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c --- v2.2.17/drivers/nubus/nubus.c Fri Apr 21 12:46:24 2000 +++ linux/drivers/nubus/nubus.c Fri Oct 13 23:52:23 2000 @@ -1,78 +1,112 @@ /* * Macintosh Nubus Interface Code + * + * Originally by Alan Cox + * + * Mostly rewritten by David Huggins-Daines, C. Scott Ananian, + * and others. */ #include #include #include #include -#include -#include #include #include #include +#include +#include #include #include #include #include -/* for LCIII stuff; better find a general way like MACH_HAS_NUBUS */ -#include #include +#include +#include +extern void via_nubus_init(void); +extern void oss_nubus_init(void); -#undef LCIII_WEIRDNESS - -static struct nubus_slot nubus_slots[16]; - -/* - * Please skip to the bottom of this file if you ate lunch recently - * -- Alan - */ - +/* Constants */ -/* - * Yes this sucks. The ROM can appear on arbitary bytes of the long - * word. We are not amused. - */ +/* This is, of course, the size in bytelanes, rather than the size in + actual bytes */ +#define FORMAT_BLOCK_SIZE 20 +#define ROM_DIR_OFFSET 0x24 + +#define NUBUS_TEST_PATTERN 0x5A932BC7 + +/* Globals */ + +struct nubus_dev* nubus_devices; +struct nubus_board* nubus_boards; + +extern int console_loglevel; + +/* Meaning of "bytelanes": + + The card ROM may appear on any or all bytes of each long word in + NuBus memory. The low 4 bits of the "map" value found in the + format block (at the top of the slot address space, as well as at + the top of the MacOS ROM) tells us which bytelanes, i.e. which byte + offsets within each longword, are valid. Thus: + + A map of 0x0f, as found in the MacOS ROM, means that all bytelanes + are valid. + + A map of 0xf0 means that no bytelanes are valid (We pray that we + will never encounter this, but stranger things have happened) + + A map of 0xe1 means that only the MSB of each long word is actually + part of the card ROM. (We hope to never encounter NuBus on a + little-endian machine. Again, stranger things have happened) + + A map of 0x78 means that only the LSB of each long word is valid. + + Etcetera, etcetera. Hopefully this clears up some confusion over + what the following code actually does. */ -extern __inline__ int not_useful(void *p, int map) +extern inline int not_useful(void *p, int map) { unsigned long pv=(unsigned long)p; - pv&=3; - if(map&(1<65536) - printk("rewind of %d!\n", len); + + /* Sanity check */ + if(len > 65536) + printk(KERN_ERR "rewind of 0x%08x!\n", len); while(len) { do { p--; } - while(not_useful(p,map)); + while(not_useful(p, map)); len--; } *ptr=p; @@ -80,9 +114,9 @@ static void nubus_advance(unsigned char **ptr, int len, int map) { - unsigned char *p=*ptr; + unsigned char *p = *ptr; if(len>65536) - printk("advance of %d!\n", len); + printk(KERN_ERR "advance of 0x%08x!\n", len); while(len) { while(not_useful(p,map)) @@ -90,29 +124,32 @@ p++; len--; } - *ptr=p; + *ptr = p; } -/* - * 24bit signed offset to 32bit - */ - -static unsigned long nubus_expand32(unsigned long foo) +static void nubus_move(unsigned char **ptr, int len, int map) { - if(foo&0x00800000) /* 24bit negative */ - foo|=0xFF000000; - return foo; + if(len > 0) + nubus_advance(ptr, len, map); + else if(len < 0) + nubus_rewind(ptr, -len, map); } -static void nubus_move(unsigned char **ptr, int len, int map) +/* Now, functions to read the sResource tree */ + +/* Each sResource entry consists of a 1-byte ID and a 3-byte data + field. If that data field contains an offset, then obviously we + have to expand it from a 24-bit signed number to a 32-bit signed + number. */ + +extern inline long nubus_expand32(long foo) { - if(len>0) - nubus_advance(ptr,len,map); - else if(len<0) - nubus_rewind(ptr,-len,map); + if(foo & 0x00800000) /* 24bit negative */ + foo |= 0xFF000000; + return foo; } -static void *nubus_rom_addr(int slot) +extern inline void *nubus_rom_addr(int slot) { /* * Returns the first byte after the card. We then walk @@ -121,472 +158,734 @@ return (void *)(0xF1000000+(slot<<24)); } -void nubus_memcpy(int slot, void *to, unsigned char *p, int len) +static unsigned char *nubus_dirptr(const struct nubus_dirent *nd) { - unsigned char *t=(unsigned char *)to; + unsigned char *p = nd->base; + /* Essentially, just step over the bytelanes using whatever + offset we might have found */ + nubus_move(&p, nubus_expand32(nd->data), nd->mask); + /* And return the value */ + return p; +} + +/* These two are for pulling resource data blocks (i.e. stuff that's + pointed to with offsets) out of the card ROM. */ + +void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent* dirent, + int len) +{ + unsigned char *t = (unsigned char *)dest; + unsigned char *p = nubus_dirptr(dirent); while(len) { - *t++=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes); + *t++ = nubus_get_rom(&p, 1, dirent->mask); len--; } } -void nubus_strncpy(int slot, void *to, unsigned char *p, int len) +void nubus_get_rsrc_str(void *dest, const struct nubus_dirent* dirent, + int len) { - unsigned char *t=(unsigned char *)to; + unsigned char *t=(unsigned char *)dest; + unsigned char *p = nubus_dirptr(dirent); while(len) { - *t=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes); + *t = nubus_get_rom(&p, 1, dirent->mask); if(!*t++) break; len--; } } - - - -unsigned char *nubus_dirptr(struct nubus_dirent *nd) +int nubus_get_root_dir(const struct nubus_board* board, + struct nubus_dir* dir) { - unsigned char *p=(unsigned char *)(nd->base); - - nubus_move(&p, nubus_expand32(nd->value), nd->mask); - return p; + dir->ptr = dir->base = board->directory; + dir->done = 0; + dir->mask = board->lanes; + return 0; } - -struct nubus_dir *nubus_openrootdir(int slot) -{ - static struct nubus_dir nbdir; - unsigned char *rp=nubus_rom_addr(slot); - - nubus_rewind(&rp,20, nubus_slots[slot].slot_lanes); - - nubus_move(&rp, nubus_expand32(nubus_slots[slot].slot_directory), - nubus_slots[slot].slot_lanes); - - nbdir.base=rp; - nbdir.length=nubus_slots[slot].slot_dlength; - nbdir.count=0; - nbdir.mask=nubus_slots[slot].slot_lanes; - return &nbdir; +/* This is a slyly renamed version of the above */ +int nubus_get_func_dir(const struct nubus_dev* dev, + struct nubus_dir* dir) +{ + dir->ptr = dir->base = dev->directory; + dir->done = 0; + dir->mask = dev->board->lanes; + return 0; } -struct nubus_dir *nubus_opensubdir(struct nubus_dirent *d) +int nubus_get_board_dir(const struct nubus_board* board, + struct nubus_dir* dir) { - static struct nubus_dir nbdir; - unsigned char *rp=nubus_dirptr(d); - nbdir.base=rp; - nbdir.length=99999;/*slots[i].slot_dlength;*/ - nbdir.count=0; - nbdir.mask=d->mask; - return &nbdir; + struct nubus_dirent ent; + + dir->ptr = dir->base = board->directory; + dir->done = 0; + dir->mask = board->lanes; + + /* Now dereference it (the first directory is always the board + directory) */ + if (nubus_readdir(dir, &ent) == -1) + return -1; + if (nubus_get_subdir(&ent, dir) == -1) + return -1; + return 0; } -void nubus_closedir(struct nubus_dir *nd) +int nubus_get_subdir(const struct nubus_dirent *ent, + struct nubus_dir *dir) { - ; + dir->ptr = dir->base = nubus_dirptr(ent); + dir->done = 0; + dir->mask = ent->mask; + return 0; } -struct nubus_dirent *nubus_readdir(struct nubus_dir *nd) +int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent) { u32 resid; - u8 rescode; - static struct nubus_dirent d; - - if(nd->count==nd->length) - return NULL; + if (nd->done) + return -1; - d.base=(unsigned long)nd->base; - - resid=nubus_get_rom(&nd->base, 4, nd->mask); - nd->count++; - rescode=resid>>24; - if(rescode==0xFF) - { - nd->count=nd->length; - return NULL; - } - d.type=rescode; - d.value=resid&0xFFFFFF; - d.mask=nd->mask; - return &d; -} + /* Do this first, otherwise nubus_rewind & co are off by 4 */ + ent->base = nd->ptr; -/* - * MAC video handling irritations - */ + /* This moves nd->ptr forward */ + resid = nubus_get_rom(&nd->ptr, 4, nd->mask); -static unsigned char nubus_vid_byte[16]; -static unsigned long nubus_vid_offset[16]; + /* EOL marker, as per the Apple docs */ + if((resid&0xff000000) == 0xff000000) + { + /* Mark it as done */ + nd->done = 1; + return -1; + } -static void nubus_irqsplat(int slot, void *dev_id, struct pt_regs *regs) -{ - unsigned char *p=((unsigned char *)nubus_slot_addr(slot))+ - nubus_vid_offset[slot]; - *p=nubus_vid_byte[slot]; + /* First byte is the resource ID */ + ent->type = resid >> 24; + /* Low 3 bytes might contain data (or might not) */ + ent->data = resid & 0xffffff; + ent->mask = nd->mask; + return 0; } -static int nubus_add_irqsplatter(int slot, unsigned long ptr, unsigned char v) +int nubus_rewinddir(struct nubus_dir* dir) { - nubus_vid_byte[slot]=v; - nubus_vid_offset[slot]=ptr; - nubus_request_irq(slot, NULL, nubus_irqsplat); + dir->ptr = dir->base; + dir->done = 0; return 0; } - -void nubus_video_shutup(int slot, struct nubus_type *nt) -{ - if(nt->category!=3 /* Display */ || nt->type!=1 /* Video */ - || nt->DrSW!=1 /* Quickdraw device */) - return; - switch(nt->DrHW) - { - /* - * Toby and MacII Hires cards. These behave in a MacII - * anyway but not on an RBV box - */ - case 0x0001: - case 0x0013: - nubus_add_irqsplatter(slot, 0xA0000, 0); - break; - /* - * Apple workstation video card. - */ - case 0x0006: - nubus_add_irqsplatter(slot, 0xA00000, 0); - break; - /* - * Futura cards - */ - case 0x0417: - case 0x042F: - nubus_add_irqsplatter(slot, 0xF05000, 0x80); - break; - - /* - * Fingers crossed 8) - * - * If you have another card and an RBV based mac you'll - * almost certainly have to add it here to make it work. - */ - - default: - break; + +/* Driver interface functions, more or less like in pci.c */ + +struct nubus_dev* +nubus_find_device(unsigned short category, + unsigned short type, + unsigned short dr_hw, + unsigned short dr_sw, + const struct nubus_dev* from) +{ + struct nubus_dev* itor = + from ? from->next : nubus_devices; + + while (itor) { + if (itor->category == category + && itor->type == type + && itor->dr_hw == dr_hw + && itor->dr_sw == dr_sw) + return itor; + itor = itor->next; } + return NULL; } -/* - * Device list - */ +struct nubus_dev* +nubus_find_type(unsigned short category, + unsigned short type, + const struct nubus_dev* from) +{ + struct nubus_dev* itor = + from ? from->next : nubus_devices; + + while (itor) { + if (itor->category == category + && itor->type == type) + return itor; + itor = itor->next; + } + return NULL; +} -static struct nubus_device_specifier *nubus_device_list=NULL; - -void register_nubus_device(struct nubus_device_specifier *d) -{ - d->next=nubus_device_list; - nubus_device_list=d; +struct nubus_dev* +nubus_find_slot(unsigned int slot, + const struct nubus_dev* from) +{ + struct nubus_dev* itor = + from ? from->next : nubus_devices; + + while (itor) { + if (itor->board->slot == slot) + return itor; + itor = itor->next; + } + return NULL; } -void unregister_nubus_device(struct nubus_device_specifier *nb) -{ - struct nubus_device_specifier **t=&nubus_device_list; - while(*t!=nb && *t) - t=&((*t)->next); - *t=nb->next; +int +nubus_find_rsrc(struct nubus_dir* dir, unsigned char rsrc_type, + struct nubus_dirent* ent) +{ + while (nubus_readdir(dir, ent) != -1) { + if (ent->type == rsrc_type) + return 0; + } + return -1; +} + +/* Initialization functions - decide which slots contain stuff worth + looking at, and print out lots and lots of information from the + resource blocks. */ + +/* FIXME: A lot of this stuff will eventually be useful after + initializaton, for intelligently probing Ethernet and video chips, + among other things. The rest of it should go in the /proc code. + For now, we just use it to give verbose boot logs. */ + +static int __init nubus_show_display_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) +{ + switch (ent->type) { + case NUBUS_RESID_GAMMADIR: + printk(KERN_INFO " gamma directory offset: 0x%06x\n", ent->data); + break; + case 0x0080 ... 0x0085: + printk(KERN_INFO " mode %02X info offset: 0x%06x\n", + ent->type, ent->data); + break; + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); + } + return 0; } -static struct nubus_device_specifier *find_nubus_device(int slot, struct nubus_type *nt) +static int __init nubus_show_network_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) { - struct nubus_device_specifier *t=nubus_device_list; - while(t!=NULL) + switch (ent->type) { + case NUBUS_RESID_MAC_ADDRESS: { - if(t->setup(t,slot, nt)==0) - return t; - t=t->next; + char addr[6]; + int i; + + nubus_get_rsrc_mem(addr, ent, 6); + printk(KERN_INFO " MAC address: "); + for (i = 0; i < 6; i++) + printk("%02x%s", addr[i] & 0xff, + i == 5 ? "" : ":"); + printk("\n"); + break; + } + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); } - printk("No driver for device [%d %d %d %d]\n", - nt->category, nt->type, nt->DrHW, nt->DrSW); - return NULL; + return 0; } -/* - * Probe a nubus slot - */ +static int __init nubus_show_cpu_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) +{ + switch (ent->type) { + case NUBUS_RESID_MEMINFO: + { + unsigned long meminfo[2]; + nubus_get_rsrc_mem(&meminfo, ent, 8); + printk(KERN_INFO " memory: [ 0x%08lx 0x%08lx ]\n", + meminfo[0], meminfo[1]); + break; + } + case NUBUS_RESID_ROMINFO: + { + unsigned long rominfo[2]; + nubus_get_rsrc_mem(&rominfo, ent, 8); + printk(KERN_INFO " ROM: [ 0x%08lx 0x%08lx ]\n", + rominfo[0], rominfo[1]); + break; + } + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); + } + return 0; +} -void nubus_probe_slot(int slot, int mode) +static int __init nubus_show_private_resource(struct nubus_dev* dev, + const struct nubus_dirent* ent) { - unsigned char *rp; - unsigned char dp; - int lanes; - int i; - unsigned long dpat; - struct nubus_dir *dir; - struct nubus_dirent *nd; - struct nubus_type type_info; + switch (dev->category) { + case NUBUS_CAT_DISPLAY: + nubus_show_display_resource(dev, ent); + break; + case NUBUS_CAT_NETWORK: + nubus_show_network_resource(dev, ent); + break; + case NUBUS_CAT_CPU: + nubus_show_cpu_resource(dev, ent); + break; + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent->type, ent->data); + } + return 0; +} - /* - * Ok see whats cooking in the bytelanes - */ +static struct nubus_dev* __init +nubus_get_functional_resource(struct nubus_board* board, + int slot, + const struct nubus_dirent* parent) +{ + struct nubus_dir dir; + struct nubus_dirent ent; + struct nubus_dev* dev; + + printk(KERN_INFO " Function 0x%02x:\n", parent->type); + nubus_get_subdir(parent, &dir); + + printk(KERN_DEBUG "nubus_get_functional_resource: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); + + /* Actually we should probably panic if this fails */ + if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) + return NULL; + memset(dev, 0, sizeof(*dev)); + dev->resid = parent->type; + dev->directory = dir.base; + dev->board = board; - rp=nubus_rom_addr(slot); - - for(i=4;i;i--) + while (nubus_readdir(&dir, &ent) != -1) { - rp--; - - if(!hwreg_present(rp)) - continue; - - dp=*rp; - - if(dp==0) - continue; - - /* - * Valid ? - */ - - if((((dp>>4)^dp)&0x0F)!=0x0F) - continue; - - if((dp&0x0F) >= 1<type==0x80/*RES_ID_BOARD_DIR*/) - break; + unsigned short nbtdata[4]; + nubus_get_rsrc_mem(nbtdata, &ent, 8); + dev->category = nbtdata[0]; + dev->type = nbtdata[1]; + dev->dr_sw = nbtdata[2]; + dev->dr_hw = nbtdata[3]; + printk(KERN_INFO " type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n", + nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]); + break; } - - nubus_closedir(dir); - - if(nd==NULL) + case NUBUS_RESID_NAME: { - printk("board resource not found!\n"); - return; + nubus_get_rsrc_str(dev->name, &ent, 64); + printk(KERN_INFO " name: %s\n", dev->name); + break; } - - dir=nubus_opensubdir(nd); - - /* - * Walk the board resource - */ - - while((nd=nubus_readdir(dir))!=NULL) + case NUBUS_RESID_DRVRDIR: { - switch(nd->type) - { - case RES_ID_TYPE: - { - unsigned short nbtdata[4]; - nubus_memcpy(slot, nbtdata, nubus_dirptr(nd), 8); - type_info.category=nbtdata[0]; - type_info.type=nbtdata[1]; - type_info.DrHW=nbtdata[2]; - type_info.DrSW=nbtdata[3]; - break; - } - case RES_ID_NAME: - nubus_strncpy(slot, nubus_slots[slot].slot_cardname,nubus_dirptr(nd),64); - break; - default: - ; - } + /* MacOS driver. If we were NetBSD we might + use this :-) */ + struct nubus_dir drvr_dir; + struct nubus_dirent drvr_ent; + nubus_get_subdir(&ent, &drvr_dir); + nubus_readdir(&drvr_dir, &drvr_ent); + dev->driver = nubus_dirptr(&drvr_ent); + printk(KERN_INFO " driver at: 0x%p\n", + dev->driver); + break; } - - nubus_closedir(dir); - - /* - * Attempt to bind a driver to this slot - */ - - if (mode==0) { - printk("%s\n", - nubus_slots[slot].slot_cardname); - find_nubus_device(slot,&type_info); + case NUBUS_RESID_MINOR_BASEOS: + /* We will need this in order to support + multiple framebuffers. It might be handy + for Ethernet as well */ + nubus_get_rsrc_mem(&dev->iobase, &ent, 4); + printk(KERN_INFO " memory offset: 0x%08lx\n", + dev->iobase); + break; + case NUBUS_RESID_MINOR_LENGTH: + /* Ditto */ + nubus_get_rsrc_mem(&dev->iosize, &ent, 4); + printk(KERN_INFO " memory length: 0x%08lx\n", + dev->iosize); + break; + case NUBUS_RESID_FLAGS: + dev->flags = ent.data; + printk(KERN_INFO " flags: 0x%06x\n", dev->flags); + break; + case NUBUS_RESID_HWDEVID: + dev->hwdevid = ent.data; + printk(KERN_INFO " hwdevid: 0x%06x\n", dev->hwdevid); + break; + default: + /* Local/Private resources have their own + function */ + nubus_show_private_resource(dev, &ent); } - if (mode==1) - nubus_video_shutup(slot, &type_info); + } + + return dev; +} - return; +/* This is cool. */ +static int __init nubus_get_vidnames(struct nubus_board* board, + const struct nubus_dirent* parent) +{ + struct nubus_dir dir; + struct nubus_dirent ent; + /* FIXME: obviously we want to put this in a header file soon */ + struct vidmode { + u32 size; + /* Don't know what this is yet */ + u16 id; + /* Longest one I've seen so far is 26 characters */ + char name[32]; + }; + + printk(KERN_INFO " video modes supported:\n"); + nubus_get_subdir(parent, &dir); + printk(KERN_DEBUG "nubus_get_vidnames: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); + + while(nubus_readdir(&dir, &ent) != -1) + { + struct vidmode mode; + u32 size; + + /* First get the length */ + nubus_get_rsrc_mem(&size, &ent, 4); + + /* Now clobber the whole thing */ + if (size > sizeof(mode) - 1) + size = sizeof(mode) - 1; + memset(&mode, sizeof(mode), 0); + nubus_get_rsrc_mem(&mode, &ent, size); + printk (KERN_INFO " %02X: (%02X) %s\n", ent.type, + mode.id, mode.name); } + return 0; } +/* This is *really* cool. */ +static int __init nubus_get_icon(struct nubus_board* board, + const struct nubus_dirent* ent) +{ + /* Should be 32x32 if my memory serves me correctly */ + unsigned char icon[128]; + int x, y; + + nubus_get_rsrc_mem(&icon, ent, 128); + printk(KERN_INFO " icon:\n"); + + /* We should actually plot these somewhere in the framebuffer + init. This is just to demonstrate that they do, in fact, + exist */ + for (y = 0; y < 32; y++) { + printk(KERN_INFO " "); + for (x = 0; x < 32; x++) { + if (icon[y*4 + x/8] + & (0x80 >> (x%8))) + printk("*"); + else + printk(" "); + } + printk("\n"); + } + return 0; +} -void nubus_probe_bus(void) +static int __init nubus_get_vendorinfo(struct nubus_board* board, + const struct nubus_dirent* parent) { - int i; - for(i=9;i<15;i++) - { - /* printk("nubus: probing slot %d !\n", i); */ - nubus_probe_slot(i, 0); + struct nubus_dir dir; + struct nubus_dirent ent; + static char* vendor_fields[6] = {"ID", "serial", "revision", + "part", "date", "unknown field"}; + + printk(KERN_INFO " vendor info:\n"); + nubus_get_subdir(parent, &dir); + printk(KERN_DEBUG "nubus_get_vendorinfo: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); + + while(nubus_readdir(&dir, &ent) != -1) + { + char name[64]; + + /* These are all strings, we think */ + nubus_get_rsrc_str(name, &ent, 64); + if (ent.type > 5) + ent.type = 5; + printk(KERN_INFO " %s: %s\n", + vendor_fields[ent.type-1], name); } + return 0; } -/* - * RBV machines have level triggered video interrupts, and a VIA - * emulation that doesn't always seem to include being able to disable - * an interrupt. Totally lusing hardware. Before we can init irq's we - * have to install a handler to shut the bloody things up. - */ - -void nubus_sweep_video(void) +static int __init nubus_get_board_resource(struct nubus_board* board, int slot, + const struct nubus_dirent* parent) { - int i; - return; /* XXX why ?? */ - for(i=9;i<15;i++) + struct nubus_dir dir; + struct nubus_dirent ent; + + nubus_get_subdir(parent, &dir); + printk(KERN_DEBUG "nubus_get_board_resource: parent is 0x%p, dir is 0x%p\n", + parent->base, dir.base); + + while(nubus_readdir(&dir, &ent) != -1) { - nubus_probe_slot(i,1); + switch (ent.type) { + case NUBUS_RESID_TYPE: + { + unsigned short nbtdata[4]; + /* This type is always the same, and is not + useful except insofar as it tells us that + we really are looking at a board resource. */ + nubus_get_rsrc_mem(nbtdata, &ent, 8); + printk(KERN_INFO " type: [cat 0x%x type 0x%x hw 0x%x sw 0x%x]\n", + nbtdata[0], nbtdata[1], nbtdata[2], + nbtdata[3]); + if (nbtdata[0] != 1 || nbtdata[1] != 0 || + nbtdata[2] != 0 || nbtdata[3] != 0) + printk(KERN_ERR "this sResource is not a board resource!\n"); + break; + } + case NUBUS_RESID_NAME: + nubus_get_rsrc_str(board->name, &ent, 64); + printk(KERN_INFO " name: %s\n", board->name); + break; + case NUBUS_RESID_ICON: + nubus_get_icon(board, &ent); + break; + case NUBUS_RESID_BOARDID: + printk(KERN_INFO " board id: 0x%x\n", ent.data); + break; + case NUBUS_RESID_PRIMARYINIT: + printk(KERN_INFO " primary init offset: 0x%06x\n", ent.data); + break; + case NUBUS_RESID_VENDORINFO: + nubus_get_vendorinfo(board, &ent); + break; + case NUBUS_RESID_FLAGS: + printk(KERN_INFO " flags: 0x%06x\n", ent.data); + break; + case NUBUS_RESID_HWDEVID: + printk(KERN_INFO " hwdevid: 0x%06x\n", ent.data); + break; + case NUBUS_RESID_SECONDINIT: + printk(KERN_INFO " secondary init offset: 0x%06x\n", ent.data); + break; + /* WTF isn't this in the functional resources? */ + case NUBUS_RESID_VIDNAMES: + nubus_get_vidnames(board, &ent); + break; + /* Same goes for this */ + case NUBUS_RESID_VIDMODES: + printk(KERN_INFO " video mode parameter directory offset: 0x%06x\n", + ent.data); + break; + default: + printk(KERN_INFO " unknown resource %02X, data 0x%06x\n", + ent.type, ent.data); + } } + return 0; } -/* - * Support functions - */ - -int nubus_ethernet_addr(int slot, unsigned char *addr) +/* Add a board (might be many devices) to the list */ +static struct nubus_board* __init nubus_add_board(int slot, int bytelanes) { - struct nubus_dir *nb; - struct nubus_dirent *d; - int ng=-ENOENT; - - nb=nubus_openrootdir(slot); + struct nubus_board* board; + struct nubus_board** boardp; + + unsigned char *rp; + unsigned long dpat; + struct nubus_dir dir; + struct nubus_dirent ent; + + /* Move to the start of the format block */ + rp = nubus_rom_addr(slot); + nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes); + + /* Actually we should probably panic if this fails */ + if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL) + return NULL; + memset(board, 0, sizeof(*board)); + board->fblock = rp; + + /* Dump the format block for debugging purposes */ + if (console_loglevel >= 10) { + int i; + printk(KERN_DEBUG "Slot %X, format block at 0x%p\n", + slot, rp); + printk(KERN_DEBUG "Format block: "); + for (i = 0; i < FORMAT_BLOCK_SIZE; i += 4) { + unsigned short foo, bar; + foo = nubus_get_rom(&rp, 2, bytelanes); + bar = nubus_get_rom(&rp, 2, bytelanes); + printk("%04x %04x ", foo, bar); + } + printk("\n"); + rp = board->fblock; + } - if(nb==NULL) - return -ENOENT; + board->slot = slot; + board->slot_addr = (unsigned long) nubus_slot_addr(slot); + board->doffset = nubus_get_rom(&rp, 4, bytelanes); + /* rom_length is *supposed* to be the total length of the + * ROM. In practice it is the "amount of ROM used to compute + * the CRC." So some jokers decide to set it to zero and + * set the crc to zero so they don't have to do any math. + * See the Performa 460 ROM, for example. Those Apple "engineers". + */ + board->rom_length = nubus_get_rom(&rp, 4, bytelanes); + board->crc = nubus_get_rom(&rp, 4, bytelanes); + board->rev = nubus_get_rom(&rp, 1, bytelanes); + board->format = nubus_get_rom(&rp,1, bytelanes); + board->lanes = bytelanes; + + /* Directory offset should be small and negative... */ + if(!(board->doffset & 0x00FF0000)) + printk(KERN_WARNING "Dodgy doffset!\n"); + dpat = nubus_get_rom(&rp, 4, bytelanes); + if(dpat != NUBUS_TEST_PATTERN) + printk(KERN_WARNING "Wrong test pattern %08lx!\n", dpat); - while((d=nubus_readdir(nb))!=NULL) - { - if(d->type==0x80) /* First private resource */ - break; + /* + * I wonder how the CRC is meant to work - + * any takers ? + * CSA: According to MAC docs, not all cards pass the CRC anyway, + * since the initial Macintosh ROM releases skipped the check. + */ + + /* Set up the directory pointer */ + board->directory = board->fblock; + nubus_move(&board->directory, nubus_expand32(board->doffset), board->lanes); + + nubus_get_root_dir(board, &dir); + + /* We're ready to rock */ + printk(KERN_INFO "Slot %X:\n", slot); + + /* Each slot should have one board resource and any number of + functional resources. So we'll fill in some fields in the + struct nubus_board from the board resource, then walk down + the list of functional resources, spinning out a nubus_dev + for each of them. */ + if (nubus_readdir(&dir, &ent) == -1) { + /* We can't have this! */ + printk(KERN_ERR "Board resource not found!\n"); + return NULL; + } else { + printk(KERN_INFO " Board resource:\n"); + nubus_get_board_resource(board, slot, &ent); } - if(d==NULL) - return -ENOENT; - - nb=nubus_opensubdir(d); + + while (nubus_readdir(&dir, &ent) != -1) { + struct nubus_dev* dev; + struct nubus_dev** devp; + dev = nubus_get_functional_resource(board, slot, &ent); + if (dev == NULL) + continue; + + /* We zeroed this out above */ + if (board->first_dev == NULL) + board->first_dev = dev; + + /* Put it on the global NuBus device chain. Keep entries in order. */ + for (devp=&nubus_devices; *devp!=NULL; devp=&((*devp)->next)) + /* spin */; + *devp = dev; + dev->next = NULL; + } + + /* Put it on the global NuBus board chain. Keep entries in order. */ + for (boardp=&nubus_boards; *boardp!=NULL; boardp=&((*boardp)->next)) + /* spin */; + *boardp = board; + board->next = NULL; - while((d=nubus_readdir(nb))!=NULL) + return board; +} + +void __init nubus_probe_slot(int slot) +{ + unsigned char dp; + unsigned char* rp; + int i; + + rp = nubus_rom_addr(slot); + for(i = 4; i; i--) { - if(d->type==0x80) /* First private field is the mac */ - { - int i; - nubus_memcpy(slot, addr, nubus_dirptr(d), 6); -/* printk("d.base=%lX, d.value=%lX\n", - d->base,d->value); - memcpy(addr,"\xC0\xC1\xC2\xC3\xC4\xC5",6);*/ - printk("MAC address: "); - for(i=0;i<6;i++) - { - printk("%s%02X", i?":":"", addr[i]); - } - ng=0; - break; - } - else - printk("ID=%d val=%x\n", - d->type, d->value); + unsigned long flags; + int card_present; + + rp--; + save_flags(flags); + cli(); + card_present = hwreg_present(rp); + restore_flags(flags); + + if (!card_present) + continue; + + dp = *rp; + if(dp == 0) + continue; + + /* The last byte of the format block consists of two + nybbles which are "mirror images" of each other. + These show us the valid bytelanes */ + if ((((dp>>4) ^ dp) & 0x0F) != 0x0F) + continue; + /* Check that this value is actually *on* one of the + bytelanes it claims are valid! */ + if ((dp & 0x0F) >= (1<slot, board->name); + return strlen(ptr); } +/* We're going to have to be a bit more sophisticated about this, I + think, because it doesn't really seem to work right when you do a + full listing of boards and devices */ int get_nubus_list(char *buf) { int nprinted, len, size; - int slot; + struct nubus_board* board; #define MSG "\nwarning: page-size limit reached!\n" /* reserve same for truncation warning message: */ size = PAGE_SIZE - (strlen(MSG) + 1); - len = sprintf(buf, "Nubus devices found:\n"); + len = sprintf(buf, "Nubus boards found:\n"); - for (slot=0; slot< 16; slot++) + /* Walk the list of NuBus boards */ + for (board = nubus_boards; board != NULL; board = board->next) { - if(!(nubus_slots[slot].slot_flags&NUBUS_DEVICE_PRESENT)) - continue; - nprinted = sprint_nubus_config(slot, buf + len, size - len); + nprinted = sprint_nubus_board(board, buf + len, size - len); if (nprinted < 0) { return len + sprintf(buf + len, MSG); } @@ -595,46 +894,42 @@ return len; } -static struct proc_dir_entry proc_nubus = { +static struct proc_dir_entry proc_old_nubus = { PROC_NUBUS, 5, "nubus", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_array_inode_operations }; -#endif +#endif /* CONFIG_PROC_FS */ -void nubus_init(void) +void __init nubus_scan_bus(void) { - /* - * Register cards - */ -#ifdef CONFIG_DAYNAPORT - extern struct nubus_device_specifier nubus_8390; -#endif + int slot; + for(slot = 9; slot < 15; slot++) + { + nubus_probe_slot(slot); + } +} +void __init nubus_init(void) +{ if (!MACH_IS_MAC) return; -#ifdef LCIII_WEIRDNESS - if (macintosh_config->ident == MAC_MODEL_LCIII) { - printk("nubus init: LCIII has no nubus!\n"); - return; + /* Initialize the NuBus interrupts */ + if (oss_present) { + oss_nubus_init(); + } else { + via_nubus_init(); } -#endif -#ifdef CONFIG_DAYNAPORT - register_nubus_device(&nubus_8390); -#endif + /* And probe */ + printk("NuBus: Scanning NuBus slots.\n"); + nubus_devices = NULL; + nubus_boards = NULL; + nubus_scan_bus(); - /* - * And probe - */ - - nubus_init_via(); - printk("Scanning nubus slots.\n"); - nubus_probe_bus(); #ifdef CONFIG_PROC_FS - proc_register(&proc_root, &proc_nubus); + proc_register(&proc_root, &proc_old_nubus); + nubus_proc_init(); #endif } - - \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/nubus/nubus_syms.c linux/drivers/nubus/nubus_syms.c --- v2.2.17/drivers/nubus/nubus_syms.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/nubus/nubus_syms.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,27 @@ +/* Exported symbols for NuBus services + + (c) 1999 David Huggins-Daines */ + +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +EXPORT_SYMBOL(nubus_proc_attach_device); +EXPORT_SYMBOL(nubus_proc_detach_device); +#endif + +EXPORT_SYMBOL(nubus_find_device); +EXPORT_SYMBOL(nubus_find_type); +EXPORT_SYMBOL(nubus_find_slot); +EXPORT_SYMBOL(nubus_get_root_dir); +EXPORT_SYMBOL(nubus_get_board_dir); +EXPORT_SYMBOL(nubus_get_func_dir); +EXPORT_SYMBOL(nubus_readdir); +EXPORT_SYMBOL(nubus_find_rsrc); +EXPORT_SYMBOL(nubus_rewinddir); +EXPORT_SYMBOL(nubus_get_subdir); +EXPORT_SYMBOL(nubus_get_rsrc_mem); +EXPORT_SYMBOL(nubus_get_rsrc_str); + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/nubus/proc.c linux/drivers/nubus/proc.c --- v2.2.17/drivers/nubus/proc.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/nubus/proc.c Fri Oct 13 23:40:43 2000 @@ -0,0 +1,183 @@ +/* drivers/nubus/proc.c: Proc FS interface for NuBus. + + By David Huggins-Daines + + Much code and many ideas from drivers/pci/proc.c: + Copyright (c) 1997, 1998 Martin Mares + + This is initially based on the Zorro and PCI interfaces. However, + it works somewhat differently. The intent is to provide a + structure in /proc analogous to the structure of the NuBus ROM + resources. + + Therefore each NuBus device is in fact a directory, which may in + turn contain subdirectories. The "files" correspond to NuBus + resource records. For those types of records which we know how to + convert to formats that are meaningful to userspace (mostly just + icons) these files will provide "cooked" data. Otherwise they will + simply provide raw access (read-only of course) to the ROM. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +get_nubus_dev_info(char *buf, char **start, off_t pos, int count, int wr) +{ + struct nubus_dev *dev = nubus_devices; + off_t at = 0; + int len, cnt; + + cnt = 0; + while (dev && count > cnt) { + len = sprintf(buf, "%x\t%04x %04x %04x %04x", + dev->board->slot, + dev->category, + dev->type, + dev->dr_sw, + dev->dr_hw); + len += sprintf(buf+len, + "\t%08lx", + dev->board->slot_addr); + buf[len++] = '\n'; + at += len; + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else + cnt += len; + buf += len; + } + dev = dev->next; + } + return (count > cnt) ? cnt : count; +} + +static struct proc_dir_entry proc_nubus_devices = { + PROC_BUS_NUBUS_DEVICES, 7, "devices", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + get_nubus_dev_info +}; + +static struct proc_dir_entry *proc_bus_nubus_dir; + +static void nubus_proc_subdir(struct nubus_dev* dev, + struct proc_dir_entry* parent, + struct nubus_dir* dir) +{ + struct nubus_dirent ent; + + /* Some of these are directories, others aren't */ + while (nubus_readdir(dir, &ent) != -1) { + char name[8]; + struct proc_dir_entry* e; + + sprintf(name, "%x", ent.type); + e = create_proc_entry(name, S_IFREG | S_IRUGO | + S_IWUSR, parent); + if (!e) return; + } +} + +/* Can't do this recursively since the root directory is structured + somewhat differently from the subdirectories */ +static void nubus_proc_populate(struct nubus_dev* dev, + struct proc_dir_entry* parent, + struct nubus_dir* root) +{ + struct nubus_dirent ent; + + /* We know these are all directories (board resource + one or + more functional resources) */ + while (nubus_readdir(root, &ent) != -1) { + char name[8]; + struct proc_dir_entry* e; + struct nubus_dir dir; + + sprintf(name, "%x", ent.type); + e = create_proc_entry(name, S_IFDIR, parent); + if (!e) return; + + /* And descend */ + if (nubus_get_subdir(&ent, &dir) == -1) { + /* This shouldn't happen */ + printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n", + dev->board->slot, ent.type); + continue; + } else { + nubus_proc_subdir(dev, e, &dir); + } + } +} + +int nubus_proc_attach_device(struct nubus_dev *dev) +{ + struct proc_dir_entry *e; + struct nubus_dir root; + char name[8]; + + if (dev == NULL) { + printk(KERN_ERR + "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); + return -1; + } + + if (dev->board == NULL) { + printk(KERN_ERR + "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); + printk("dev = %p, dev->board = %p\n", dev, dev->board); + return -1; + } + + /* Create a directory */ + sprintf(name, "%x", dev->board->slot); + e = dev->procdir = create_proc_entry(name, S_IFDIR, + proc_bus_nubus_dir); + if (!e) + return -ENOMEM; + + /* Now recursively populate it with files */ + nubus_get_root_dir(dev->board, &root); + nubus_proc_populate(dev, e, &root); + + return 0; +} + +/* FIXME: this is certainly broken! */ +int nubus_proc_detach_device(struct nubus_dev *dev) +{ + struct proc_dir_entry *e; + + if ((e = dev->procdir)) { + if (e->count) + return -EBUSY; + remove_proc_entry(e->name, proc_bus_nubus_dir); + dev->procdir = NULL; + } + return 0; +} + +__initfunc(void proc_bus_nubus_add_devices(void)) +{ + struct nubus_dev *dev; + + for(dev = nubus_devices; dev; dev = dev->next) + nubus_proc_attach_device(dev); +} + +__initfunc(void nubus_proc_init(void)) +{ + if (!MACH_IS_MAC) + return; + proc_bus_nubus_dir = create_proc_entry("nubus", S_IFDIR, proc_bus); + proc_register(proc_bus_nubus_dir, &proc_nubus_devices); + proc_bus_nubus_add_devices(); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/pci/compat.c linux/drivers/pci/compat.c --- v2.2.17/drivers/pci/compat.c Fri Apr 21 12:46:24 2000 +++ linux/drivers/pci/compat.c Fri Sep 8 17:05:10 2000 @@ -41,3 +41,31 @@ } return PCIBIOS_DEVICE_NOT_FOUND; } + +/* 2.4 compatibility */ + +unsigned long pci_resource_len (struct pci_dev *dev, int n_base) +{ + u32 l, sz; + int reg = PCI_BASE_ADDRESS_0 + (n_base << 2); + + /* XXX temporarily disable I/O and memory decoding for this device? */ + + pci_read_config_dword (dev, reg, &l); + if (l == 0xffffffff) + return 0; + + pci_write_config_dword (dev, reg, ~0); + pci_read_config_dword (dev, reg, &sz); + pci_write_config_dword (dev, reg, l); + + if (!sz || sz == 0xffffffff) + return 0; + if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { + sz = ~(sz & PCI_BASE_ADDRESS_MEM_MASK); + } else { + sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; + } + + return sz + 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c --- v2.2.17/drivers/pci/pcisyms.c Fri Apr 21 12:46:24 2000 +++ linux/drivers/pci/pcisyms.c Fri Sep 8 17:05:10 2000 @@ -40,6 +40,10 @@ EXPORT_SYMBOL(pcibios_find_class); EXPORT_SYMBOL(pcibios_find_device); +/* Forward compatibility */ + +EXPORT_SYMBOL(pci_resource_len); + /* Quirk info */ #ifdef CONFIG_PCI_QUIRKS diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/Config.in linux/drivers/s390/Config.in --- v2.2.17/drivers/s390/Config.in Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/Config.in Wed Nov 8 23:09:58 2000 @@ -52,7 +52,7 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then comment 'S390 Network devices' - bool 'CTC device support' CONFIG_CTC + tristate 'CTC device support' CONFIG_CTC bool 'IUCV device support (VM only)' CONFIG_IUCV tristate 'Dummy net driver support' CONFIG_DUMMY bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/Makefile linux/drivers/s390/Makefile --- v2.2.17/drivers/s390/Makefile Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/Makefile Wed Nov 8 23:05:31 2000 @@ -11,18 +11,17 @@ CFLAGS += O_TARGET := io.o -O_OBJS := ccwcache.o +O_OBJS := ccwcache.o idals.o M_OBJS := SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \ arch/s390/drivers/misc arch/s390/drivers/net MOD_SUB_DIRS += ./net ./block -O_OBJS := block/s390-block.o \ +O_OBJS += block/s390-block.o \ char/s390-char.o \ misc/s390-misc.o \ - net/s390-net.o \ - ccwcache.o + net/s390-net.o io.o: $(O_OBJS) @@ -37,6 +36,5 @@ net/s390-net.o: dummy $(MAKE) -C net - include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile --- v2.2.17/drivers/s390/block/Makefile Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/block/Makefile Wed Nov 8 23:05:31 2000 @@ -2,7 +2,7 @@ CFLAGS += O_TARGET := s390-block.o -O_OBJS := +O_OBJS := M_OBJS := D_OBJS := diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c --- v2.2.17/drivers/s390/block/dasd.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/block/dasd.c Sat Dec 9 20:56:00 2000 @@ -11,7 +11,7 @@ Adapted request function to make it work on 2.4 * 07/10/00 Added some code to the request function to dequeue requests that cannot be handled due to errors - * 07/10/00 Moved linux/ccwcache.h to asm/ + * 07/10/00 Moved linux/dasd.h and linux/ccwcache.h to asm/ * 07/10/00 Fixed a bug when formatting a 'new' device * 07/10/00 Removed an annoying message from dasd_format * 07/11/00 Reanimated probeonly mode @@ -20,9 +20,26 @@ * 07/12/00 fixed a bug in dasd_devices_open when having 'unknown' devices * 07/13/00 fixed error message when having no device * 07/13/00 added code for dynamic device recognition + * 07/14/00 reorganized the format process for better ERP + * 07/17/00 fixed a race condition when sleeping on a request + * 07/17/00 modified default ERP action to use TIC instead of NOP + * 07/20/00 fixed proc filesystem for 2.4 + * 07/24/00 fixed missing interrupt handler + * 08/01/00 fixed a race condition when sleeping on a request + * 09/15/00 fixed a race condition on dasd_do_chanq + * 09/15/00 got rid of some paranoia + * 09/18/00 fixed the state machine for duplicate devnos in dasd ranges + * 10/26/00 fixed ITPM PL020141RSC load module to a kernel with static driver + are the fixes in dasd_init + * 10/26/00 fixed ITPM PL020062RSC formatting r/o volume + are the fixes in dasd_format + * 10/26/00 fixed ITPM PL010261EPA race condition when formatting + are the fixes in dasd_do_chanq + * 11/21/00 fixed BLKFLSBUF ioctl and dasd_release to flush the buffers */ #include +#include #include #include #include @@ -34,6 +51,12 @@ #include #include #include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#include +#else +#include +#endif + #include #include #include @@ -49,15 +72,15 @@ #include #include #include -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -#include -#endif /* LINUX_IS_24 */ #include #include #include #include #include #include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#include +#endif /* LINUX_IS_24 */ #include "dasd.h" #ifdef CONFIG_DASD_ECKD @@ -73,7 +96,7 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct block_device_operations dasd_device_operations; #endif /* VERSION_CODE */ - + #ifdef MODULE #define EXPORT_SYMTAB #include @@ -113,7 +136,6 @@ static void dasd_do_chanq (void); static void schedule_request_fn (void (*func) (void)); static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int); -static int dasd_oper_handler ( int irq, devreg_t *devreg ); /* SECTION: managing setup of dasd_driver */ typedef struct dasd_range_t { @@ -145,7 +167,7 @@ } return r; } - + static void dasd_add_range (int from, int to) { @@ -162,7 +184,7 @@ } else { range -> to = to; } - + /* chain current range to end of list */ if ( dasd_range_head == NULL ) { dasd_range_head = range; @@ -226,7 +248,7 @@ count ++; tmp = end; } while ( tmp != NULL && *tmp != '\0' ); - } +} static char dasd_parm_string[1024] = {0,}; @@ -239,12 +261,12 @@ *(dasd_parm_string+strlen(dasd_parm_string))=','; } else { first_time = 0; - } + } memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1); return 1; } #else -void +void dasd_setup (char *str, int *ints) { static int first_time = 1; @@ -269,7 +291,7 @@ { char *temp; int from, to; - + if ( *str ) { dasd_probeonly = 0; } @@ -284,19 +306,19 @@ } else if ( strncmp ( *str,"probeonly",strlen("probeonly"))== 0) { dasd_probeonly = 1; printk (KERN_INFO "turning to probeonly mode\n"); - break; + break; } else { dasd_autodetect = 0; from = dasd_strtoul (temp, &temp); if (*temp == '-') { temp++; to = dasd_strtoul (temp, &temp); - } + } dasd_add_range (from, to); - } + } str ++; - } - } + } +} int devindex_from_devno (int devno) @@ -310,11 +332,11 @@ devindex += devno - temp -> from; break; } - } + } if ( temp == NULL ) return -ENODEV; return devindex; - } +} /* SECTION: ALl needed for multiple major numbers */ @@ -335,7 +357,7 @@ #endif /* LINUX_IS_24 */ nr_real:DASD_PER_MAJOR, } - } + } #if 0 , { @@ -352,8 +374,8 @@ max_nr:DASD_PER_MAJOR, #endif /* LINUX_IS_24 */ nr_real:DASD_PER_MAJOR, - } } + } #endif }; @@ -361,7 +383,7 @@ find_dasd_device (int devindex) { major_info_t *major_info = dasd_major_info; - while (major_info && devindex > DASD_PER_MAJOR) { + while (major_info && devindex >= DASD_PER_MAJOR) { devindex -= DASD_PER_MAJOR; major_info = major_info->next; } @@ -374,12 +396,12 @@ major_info_from_devindex (int devindex) { major_info_t *major_info = dasd_major_info; - while (major_info && devindex > DASD_PER_MAJOR) { + while (major_info && devindex >= DASD_PER_MAJOR) { devindex -= DASD_PER_MAJOR; major_info = major_info->next; } return major_info; - } +} int major_from_devindex (int devindex) @@ -413,7 +435,7 @@ * void dasd_discipline_enq (dasd_discipline_t * d) */ -void +void dasd_discipline_enq (dasd_discipline_t * d) { spin_lock (&discipline_lock); @@ -473,14 +495,14 @@ static void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) - { +{ cqr->next = q->head; q->head = cqr; if (q->tail == NULL) q->tail = cqr; q->queued_requests++; atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED); - } +} /* * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) @@ -507,7 +529,7 @@ if (prev->next == NULL) q->tail = prev; } - cqr->next = NULL; +/* cqr->next = NULL; */ q->queued_requests--; return 0; } @@ -520,6 +542,8 @@ #else static spinlock_t cq_lock = SPIN_LOCK_UNLOCKED; /* spinlock for cq_head */ #endif /* LINUX_IS_24 */ +#else +int cq_lock; #endif /* __SMP__ */ static dasd_chanq_t *qlist_head = NULL; /* head of queue of queues */ @@ -532,18 +556,19 @@ static void qlist_enq (dasd_chanq_t * q) { + long flags; if (q == NULL) { printk (KERN_WARNING PRINTK_HEADER " NULL queue to be queued to queue of queues\n"); return; } - spin_lock (&cq_lock); + spin_lock_irqsave (&cq_lock,flags); if (atomic_read (&q->flags) & DASD_CHANQ_ACTIVE) { printk (KERN_WARNING PRINTK_HEADER " Queue already active"); } atomic_set_mask (DASD_CHANQ_ACTIVE, &q->flags); q->next_q = qlist_head; qlist_head = q; - spin_unlock (&cq_lock); + spin_unlock_irqrestore (&cq_lock,flags); } /* @@ -555,8 +580,8 @@ static void qlist_deq (dasd_chanq_t * q) { - - if (qlist_head == NULL) { + long flags; + if (qlist_head == NULL) { printk (KERN_ERR PRINTK_HEADER "Channel queue is empty%s\n", ""); return; } @@ -564,7 +589,7 @@ printk (KERN_WARNING PRINTK_HEADER " NULL queue to be dequeued from queue of queues\n"); return; } - spin_lock (&cq_lock); + spin_lock_irqsave (&cq_lock,flags); if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) { printk (KERN_WARNING PRINTK_HEADER " Queue not active\n"); } else if (qlist_head == q) { @@ -580,7 +605,7 @@ } atomic_clear_mask (DASD_CHANQ_ACTIVE, &q->flags); q->next_q = NULL; - spin_unlock (&cq_lock); + spin_unlock_irqrestore (&cq_lock,flags); } /* SECTION: All the gendisk stuff */ @@ -608,7 +633,7 @@ resetup_one_dev(dd,minor>>DASD_PARTN_BITS); #endif /* LINUX_IS_24 */ return rc; - } +} /* SECTION: Managing wrappers for ccwcache */ @@ -623,8 +648,8 @@ int i; for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) { dasd_emergency_req[i] = (ccw_req_t*)get_free_page(GFP_KERNEL); - } } +} static void dasd_cleanup_emergency_req ( void ) @@ -654,6 +679,7 @@ if ( dasd_emergency_req[i] != NULL ) { rv = dasd_emergency_req[i]; dasd_emergency_req[i] = NULL; + break; } } spin_unlock(&dasd_emergency_req_lock); @@ -670,15 +696,15 @@ return rv; } -void +void dasd_free_request (ccw_req_t * request) { if ( request -> cache >= (kmem_cache_t *)dasd_emergency_req && request -> cache <= (kmem_cache_t *)(dasd_emergency_req + DASD_EMERGENCY_REQUESTS) ) { *((ccw_req_t **)(request -> cache)) = request; - } else { + } else { ccw_free_request(request); - } + } } /* SECTION: Managing the device queues etc. */ @@ -718,7 +744,7 @@ major_info_t *mi; for (mi=dasd_major_info; mi != NULL; mi = mi->next ) { do_dasd_request(BLK_DEFAULT_QUEUE(mi->gendisk.major)); - } + } } #else do_dasd_request (); @@ -754,10 +780,10 @@ major_info_t *major_info; struct request *req; - if (!cqr) { + if (!cqr) { printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function"); return -EINVAL; - } + } irq = device->devinfo.irq; devno = device->devinfo.devno; req = (struct request *) cqr->req; @@ -776,39 +802,39 @@ return -EINVAL; } atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); - do { + do { asm volatile ("STCK %0":"=m" (cqr->startclk)); rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options); switch (rc) { case 0: if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) { atomic_set_mask (DASD_CHANQ_BUSY, &device->queue.flags); - } + } if ( cqr->expires ) { cqr->expires += cqr->startclk; - } - break; + } + break; case -ENODEV: printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " appears not to be present %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, retries); - break; + break; case -EIO: printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " I/O error %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, retries); - break; + break; case -EBUSY: /* set up timer, try later */ printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " is busy %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, retries); - break; + break; default: printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" @@ -816,26 +842,63 @@ " Pls report this message to linux390@de.ibm.com\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc, retries); - break; - } + break; + } } while (rc && retries--); if (rc) { atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERROR); - } + } return rc; - } +} + + +static int +sleep_on_req ( ccw_req_t * req ) +{ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + DECLARE_WAITQUEUE (wait,current); +#else + struct wait_queue wait = {current, NULL}; +#endif /* LINUX_VERSION_CODE */ + unsigned long flags; + int cs; + int rc = 0; + dasd_device_t *device = (dasd_device_t *)req->device; + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + dasd_chanq_enq (&device->queue, req); + if (!(atomic_read (&device->queue.flags) & DASD_CHANQ_ACTIVE)) { + qlist_enq (&device->queue); + } + dasd_schedule_bh(); + add_wait_queue (&device->wait_q, &wait); + do { + current->state = TASK_INTERRUPTIBLE; + s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); + schedule (); + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + cs = atomic_read (&req->status); + } while ( ! (cs & CQR_STATUS_FINISHED) ); + /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */ + remove_wait_queue (&device->wait_q, &wait); + s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); + if ( cs & CQR_STATUS_FAILED ) { + rc = -EIO; + } + return rc; +} + static void dasd_end_request (struct request *req, int uptodate) { struct buffer_head *bh; while ((bh = req->bh) != NULL) { - req->bh = bh->b_reqnext; + req->bh = bh->b_reqnext; bh->b_reqnext = NULL; bh->b_end_io (bh, uptodate); - } + } if (!end_that_request_first (req, uptodate, DASD_NAME)) { #ifndef DEVICE_NO_RANDOM add_blkdev_randomness (MAJOR (req->rq_dev)); @@ -871,7 +934,7 @@ major_info_t *major_info; int devno; int major; - + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) { @@ -894,34 +957,34 @@ #else for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) { major = major_info->gendisk.major; - prev = NULL; - for (req = CURRENT; req != NULL; req = next) { - next = req->next; + prev = NULL; + for (req = CURRENT; req != NULL; req = next) { + next = req->next; if (req == &blk_dev[major].plug) { /* remove plug if applicable */ req->next = NULL; - if (prev) { - prev->next = next; - } else { - CURRENT = next; - } + if (prev) { + prev->next = next; + } else { + CURRENT = next; + } continue; - } + } #endif /* LINUX_IS_24 */ devindex = devindex_from_kdev_t(req->rq_dev); if ( devindex < 0 ) { printk ( KERN_WARNING PRINTK_HEADER "requesting I/O on nonexistent device %d -> %d\n", devindex,req->rq_dev); - dasd_end_request (req, 0); + dasd_end_request(req,0); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) blkdev_dequeue_request (req); #else req->next = NULL; if (prev) { prev->next = next; - } else { + } else { CURRENT = next; - } + } #endif /* LINUX_IS_24 */ continue; } @@ -1068,43 +1131,45 @@ volatile int cqrstatus; for (qp = qlist_head; qp != NULL; qp = nqp) { + + device = (dasd_device_t *)((long)qp - (long)offsetof(dasd_device_t,queue)); + irq = device->devinfo.irq; + + s390irq_spin_lock_irqsave (irq, flags); + /* Get first request */ cqr = (ccw_req_t *) (qp->head); nqp = qp->next_q; /* empty queue -> dequeue and proceed */ if (!cqr) { qlist_deq (qp); + s390irq_spin_unlock_irqrestore(irq,flags); continue; } + s390irq_spin_unlock_irqrestore(irq,flags); + /* process all requests on that queue */ do { - dasd_discipline_t *discipline; + dasd_discipline_t *discipline=device->discipline; next = NULL; - /* Sanity check... walk through disciplines */ - for (discipline = dasd_disciplines; - discipline != NULL; - discipline = discipline->next) - if (!strncmp ((char *) &cqr->magic, discipline->ebcname, 4)) - break; - if (!discipline) { /* 1st sanity check */ + + if (strncmp ((char *) &cqr->magic, discipline->ebcname, 4)) { panic (PRINTK_HEADER "in dasd_do_chanq: magic no mismatch %p -> 0x%lX\n", cqr, cqr->magic); } - device = (dasd_device_t *) (cqr->device); - if (discipline != device->discipline) { /* 1st sanity check */ - printk (KERN_WARNING PRINTK_HEADER - "in dasd_do_chanq: discipline mismatch %p -> 0x%lX\n", - cqr, cqr->magic); - discipline = device->discipline; + if ( device != cqr->device ) { + panic (PRINTK_HEADER + "in dasd_do_chanq: device mismatch %p -> %p(qcr) vs. %p\n", + cqr, cqr->device,device); } - irq = device->devinfo.irq; devno = device->devinfo.devno; devindex = devindex_from_devno (devno); - s390irq_spin_lock_irqsave (irq, flags); - + s390irq_spin_lock_irqsave (irq, + flags); cqrstatus = atomic_read (&cqr->status); + switch (cqrstatus) { case CQR_STATUS_QUEUED: if (discipline->start_IO && @@ -1118,8 +1183,8 @@ case EBUSY: if (cqr->retries--) { printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " retrying %d retries left\n", + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:" + " retrying ... %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); break; } @@ -1128,24 +1193,29 @@ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Giving up this request!\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_FAILED); + + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_QUEUED, + CQR_STATUS_FAILED | CQR_STATUS_FINISHED); break; } } } break; case CQR_STATUS_IN_IO:{ - unsigned long long now; - unsigned long long delta; - + unsigned long long now; + unsigned long long delta; + asm volatile ("STCK %0":"=m" (now)); if (cqr->expires && cqr->startclk && cqr->expires < now) { delta = cqr->expires - cqr->startclk; printk (KERN_ERR PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " I/O operation outstanding longer than %Ld usecs on req %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, delta >> 12, cqr); + " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr); + cqr->expires += delta; +#if 0 if ( cqr->retries-- ) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" @@ -1159,46 +1229,45 @@ " You should disable that device by issueing '@#?!'\n", /* FIXME */ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); + halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT); break; } +#endif } break; - } + } case CQR_STATUS_ERROR:{ - dasd_erp_action_fn_t erp_action; - ccw_req_t *erp_cqr = NULL; - if (discipline->erp_action && - ((erp_action = discipline->erp_action (cqr)) != NULL)) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Taking error recovery action %p on req %p \n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_action,cqr); - erp_cqr = erp_action (cqr); - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " No error recovery action\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - } - if ( erp_cqr != NULL ) { - dasd_chanq_enq_head (qp, erp_cqr); - next = erp_cqr; /* prefer execution of erp ccw */ - } + dasd_erp_action_fn_t erp_action; + ccw_req_t *erp_cqr = NULL; + + if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) { + atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED); + next = cqr; + } else if ( cqr -> retries-- && + cqr -> refers == NULL && + discipline -> erp_action != NULL && + (erp_action = discipline->erp_action (cqr)) != NULL && + (erp_cqr = erp_action (cqr)) != NULL ) { + dasd_chanq_enq_head (qp, erp_cqr); + next = erp_cqr; /* prefer execution of erp ccw */ + } else { + atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); + next = cqr; + } break; } case CQR_STATUS_DONE:{ dasd_erp_postaction_fn_t erp_postaction; next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if (discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing successful error recovery action %p\n", + " postprocessing successful error recovery action using %p\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); erp_postaction (cqr, 1); - atomic_dec (&device->queue.dirty_requests); } else { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" @@ -1207,68 +1276,93 @@ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); } + atomic_dec (&device->queue.dirty_requests); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ } else if ( cqr->req ) { - asm volatile ("STCK %0":"=m" (cqr->endclk)); dasd_end_request (cqr->req, 1); #ifdef DASD_PROFILE dasd_profile_add (cqr); #endif /* DASD_PROFILE */ - } - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ + } else { + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_DONE, + CQR_STATUS_DONE | CQR_STATUS_FINISHED); + dasd_chanq_deq (&device->queue, cqr); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + wake_up (&device->wait_q); +#else + if (device->wait_q) { + wake_up (&device->wait_q); + } +#endif /* LINUX_IS_24 */ + } break; } case CQR_STATUS_FAILED:{ dasd_erp_postaction_fn_t erp_postaction; next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if (discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing unsuccessful error recovery action %p\n", + " postprocessing unsuccessful error recovery action using %p\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); erp_postaction (cqr, 0); - atomic_dec (&device->queue.dirty_requests); - } else { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " No procedure to postprocess unsuccessful error recovery action" - " giving up request", + " giving up request", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); } + atomic_dec (&device->queue.dirty_requests); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ } else if (cqr->req) { - asm volatile ("STCK %0":"=m" (cqr->endclk)); dasd_end_request (cqr->req, 0); #ifdef DASD_PROFILE dasd_profile_add (cqr); #endif /* DASD_PROFILE */ + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ } else { - printk (KERN_WARNING PRINTK_HEADER - "Internal error in " __FILE__ " on line %d." - " inconsistent content of ccw_req_t" - " refers = %p,function = %p, request = %p" - " Pls send this message and your System.map to" - " linux390@de.ibm.com\n", - __LINE__, cqr->refers, cqr->function, cqr->req); - } - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_FAILED, + CQR_STATUS_FAILED | CQR_STATUS_FINISHED); + + dasd_chanq_deq (&device->queue, cqr); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + wake_up (&device->wait_q); +#else + if (device->wait_q) { + wake_up (&device->wait_q); + } +#endif /* LINUX_IS_24 */ + } break; } + default:{ printk (KERN_WARNING PRINTK_HEADER "Internal error in " __FILE__ " on line %d." - " inconsistent content of ccw_req_t" + " inconsistent content of ccw_req_t" " cqrstatus = %d" " Pls send this message and your System.map to" " linux390@de.ibm.com\n", __LINE__, cqrstatus); + } } - } - s390irq_spin_unlock_irqrestore (irq, flags); + s390irq_spin_unlock_irqrestore (irq, flags); } while ((cqr = next) != NULL); } schedule_request_fn (try_request_fn); @@ -1286,9 +1380,9 @@ dasd_device_t *device; int devno = -1, devindex = -1; -#undef ERP_DEBUG +#undef ERP_DEBUG #ifdef ERP_DEBUG - static int counter = 0; + static int counter = 0; #endif if (!stat) { @@ -1301,11 +1395,11 @@ stat->devno); return; } - if (ip & 0x80000001) { + if (ip & 0x80000001) { PRINT_INFO ("%04X caught spurious interrupt with parm %08x\n", stat->devno, ip); - return; - } + return; + } cqr = (ccw_req_t *) ip; device = (dasd_device_t *) cqr->device; devno = device->devinfo.devno; @@ -1341,10 +1435,11 @@ cqr->magic, *(int *) (&device->discipline->name)); return; } - asm volatile ("STCK %0":"=m" (cqr->stopclk)); - if ((stat->cstat == 0x00 && - stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || - (device->discipline->examine_error && + asm volatile ("STCK %0":"=m" (cqr->stopclk)); + if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) && + stat->cstat == 0x00 && + stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || + (device->discipline->examine_error && (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) { #ifdef ERP_DEBUG if ( ++counter % 137 == 0 ) { @@ -1353,20 +1448,20 @@ stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; stat->dstat |= 0x02; goto error_fake_done; - } + } #endif atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE); atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, &device->level); - if (cqr->next && - (atomic_read (&cqr->next->status) == - CQR_STATUS_QUEUED)) { - if (dasd_start_IO (cqr->next) == 0) { - done_fast_io = 1; + if (cqr->next && + (atomic_read (&cqr->next->status) == + CQR_STATUS_QUEUED)) { + if (dasd_start_IO (cqr->next) == 0) { + done_fast_io = 1; } } - } else { /* only visited in case of error ! */ + } else { /* only visited in case of error ! */ #ifdef ERP_DEBUG error_fake_done: #endif @@ -1375,7 +1470,7 @@ if (cqr->dstat) { memcpy (cqr->dstat, stat, sizeof (devstat_t)); } else { - PRINT_ERR ("no memory for dstat\n"); + PRINT_ERR ("no memory for dstat\n"); } if (device->discipline && device->discipline->dump_sense) { @@ -1390,14 +1485,14 @@ } atomic_inc (&device->queue.dirty_requests); /* errorprocessing */ - if (era == dasd_era_fatal) { - PRINT_WARN ("ERP returned fatal error\n"); + if (era == dasd_era_fatal) { + PRINT_WARN ("ERP returned fatal error\n"); atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_IN_IO, CQR_STATUS_FAILED); - } else { + CQR_STATUS_IN_IO, CQR_STATUS_FAILED); + } else { atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERROR); - } + } } if (done_fast_io == 0) atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags); @@ -1412,56 +1507,30 @@ dasd_schedule_bh (); } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -static wait_queue_head_t watcher_queue; -#else -static struct wait_queue watcher_queue_Qend = {NULL,}; -static struct wait_queue *watcher_queue = &watcher_queue_Qend; -#endif /* LINUX_IS_24 */ - -static void -dasd_watcher (void) -{ - do { - dasd_schedule_bh (); - schedule_request_fn (try_request_fn); - interruptible_sleep_on_timeout (&watcher_queue, 5 * HZ); - } while (1); - } - /* SECTION: Some stuff related to error recovery */ ccw_req_t * default_erp_action (ccw_req_t * cqr) { ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0); - - erp->cpaddr->cmd_code = CCW_CMD_NOOP; + + erp->cpaddr->cmd_code = CCW_CMD_TIC; + erp->cpaddr->cda = (__u32)cqr -> cpaddr; erp->function = default_erp_action; erp->refers = cqr; erp->device = cqr->device; erp->magic = cqr->magic; + erp->retries = 16; atomic_set (&erp->status, CQR_STATUS_FILLED); - if ( cqr->startclk && cqr->expires ) - cqr->expires -= cqr->startclk; - - if (cqr->retries++ <= 16) { - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); - } else { - printk (KERN_WARNING PRINTK_HEADER "ERP retry count exceeded\n"); - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + if ( cqr->startclk && cqr->expires ) { + /* cqr->expires -= cqr->startclk; */ } - return erp; + return erp; } int default_erp_postaction (ccw_req_t * cqr, int success) { - int rc = 0; if (cqr->refers == NULL || cqr->function == NULL) { printk (KERN_WARNING PRINTK_HEADER "ERP postaction called for non ERP cqr\n"); @@ -1471,55 +1540,186 @@ printk (KERN_WARNING PRINTK_HEADER "default ERP postaction called for non default ERP cqr\n"); return -EINVAL; - } - return rc; + } + if ( success ) { + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + } else { + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + return 0; } /* SECTION: The helpers of the struct file_operations */ +/* + * int dasd_format ( device* device, format_data_t *fdata ) + * performs formatting of _device_ according to _fdata_ + * Note: The discipline's format_function is assumed to deliver formatting + * commands to format a single unit of the device. In terms of the ECKD + * devices this means CCWs are generated to format a single track. + */ + static int dasd_format (dasd_device_t * device, format_data_t * fdata) { - int rc = 0; - int devno = device->devinfo.devno; - int irq = device->devinfo.irq; - int devindex = devindex_from_devno (devno); - + int rc = 0; + int devno = device->devinfo.devno; + int irq = device->devinfo.irq; + int devindex = devindex_from_devno (devno); + ccw_req_t *req = NULL; + if (device->open_count != 1) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " you shouldn't format a device that is already open\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); + " you shouldn't format a device that is already open\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); return -EINVAL; } + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " Starting format process\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + dasd_set_device_level( device->devinfo.irq, DASD_DEVICE_LEVEL_RECOGNIZED, device->discipline, 0); - if (device->discipline->format_device) - rc = device->discipline->format_device (device, fdata); - if (rc) { + + if (device->discipline->format_device) { + format_data_t temp = { + fdata->start_unit, + fdata->stop_unit, + fdata->blksize, + fdata->intensity}; + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " invalidating disk...\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + + if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT && + fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + !(fdata -> intensity & 0x04)) { + format_data_t temp2 = { 0,0,DASD_FORMAT_DEFAULT_BLOCKSIZE,0x04}; + req = device->discipline->format_device (device,&temp2); + + if ( req ) { + rc = sleep_on_req(req); + dasd_free_request(req); /* request is no longer used */ + } else { + rc = -EINVAL; + } + if ( rc ) { + printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n"); + } + temp.start_unit++; + } printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Formatting failed with rc = %d\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc); - return rc; - } - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Formatting finished successfully rc = %d\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc); + " ...invalidation done.\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + + while ((!rc ) && + ((req = device->discipline->format_device (device, &temp)) != NULL ) ) { + + if ( rc=sleep_on_req(req) ) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " Formatting failed with rc = %d\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, + rc); + break; + } + dasd_free_request(req); /* request is no longer used */ + temp.start_unit++; + } /* end if no more requests */ + + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " revalidating disk...\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + + if (!rc && + req == NULL ) { + if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT && + fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + !(fdata -> intensity & 0x04)) { + format_data_t temp2 = { 0,0,fdata->blksize,fdata->intensity}; + + req = device->discipline->format_device (device, + &temp2); + if ( req ) { + rc = sleep_on_req(req); + dasd_free_request(req); /* request is no longer used */ + } else { + rc = -EINVAL; + } + if ( rc ) { + printk (KERN_WARNING PRINTK_HEADER "Can't revalidate Track 0\n"); + } + } + } + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " ...revalidation done\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + } /* end if discipline->format_device */ + + if (!rc) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " Formatting finished successfully\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + } + dasd_set_device_level( device->devinfo.irq, - DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, device->discipline, 0); udelay(1500000); + dasd_set_device_level( device->devinfo.irq, DASD_DEVICE_LEVEL_ANALYSED, device->discipline, 0); + return rc; -} +} /* end dasd_format */ static int do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) @@ -1561,6 +1761,7 @@ } case BLKFLSBUF:{ rc = fsync_dev (inp->i_rdev); + invalidate_buffers(inp->i_rdev); break; } case BLKRAGET:{ @@ -1617,15 +1818,14 @@ case BIODASDFORMAT:{ /* fdata == NULL is a valid arg to dasd_format ! */ int partn; - format_data_t *fdata = NULL; + format_data_t fdata = { + DASD_FORMAT_DEFAULT_START_UNIT, + DASD_FORMAT_DEFAULT_STOP_UNIT, + DASD_FORMAT_DEFAULT_BLOCKSIZE, + DASD_FORMAT_DEFAULT_INTENSITY }; + if (data) { - fdata = kmalloc (sizeof (format_data_t), - GFP_ATOMIC); - if (!fdata) { - rc = -ENOMEM; - break; - } - rc = copy_from_user (fdata, (void *) data, + rc = copy_from_user (&fdata, (void *) data, sizeof (format_data_t)); if (rc) break; @@ -1634,15 +1834,12 @@ if (partn != 0) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Cannot low-level format a partition\n", + " Cannot low-level format a partition\n", device->devinfo.devno, device->devinfo.irq, device->name, - MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); + MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); return -EINVAL; } - rc = dasd_format (device, fdata); - if (fdata) { - kfree (fdata); - } + rc = dasd_format (device, &fdata); break; } case BIODASDEXCP:{ @@ -1675,11 +1872,11 @@ static int dasd_ioctl (struct inode *inp, struct file *filp, unsigned int no, unsigned long data) - { +{ int rc = 0; if ((!inp) || !(inp->i_rdev)) { return -EINVAL; - } + } rc = do_dasd_ioctl (inp, no, data); return rc; } @@ -1719,7 +1916,7 @@ printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Cannot open unrecognized device\n", - device->devinfo.devno, device->devinfo.irq, device->name, + device->devinfo.devno, device->devinfo.irq, device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); return -EINVAL; } @@ -1753,6 +1950,10 @@ MOD_DEC_USE_COUNT; #endif /* MODULE */ } + if ( device->open_count == 0 ) { + rc = fsync_dev (inp->i_rdev); + invalidate_buffers(inp->i_rdev); + } return rc; } @@ -1833,7 +2034,7 @@ if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER "Cannot register to major no %d, rc = %d\n", major, rc); - return rc; + return rc; } else if (rc > 0) { if (major == 0) { major = rc; @@ -1950,11 +2151,11 @@ if ( hd ) { index = devindex_from_kdev_t (MKDEV(hd->major,index<minor_shift)); -} + } third = index % 26; second = (index / 26) % 27; first = ((index / 26) / 27) % 27; - + len = sprintf (str, "dasd"); if (first) { len += sprintf (str + len, "%c", first + 'a' - 1 ); @@ -1968,7 +2169,7 @@ return -EINVAL; } else { len += sprintf (str + len, "%d", partition); - } + } } str[len] = '\0'; return 0; @@ -1976,25 +2177,40 @@ static void dasd_not_oper_handler ( int irq, int status ) { - int devno,devindex; - dasd_device_t *device; - devno = get_devno_by_irq(irq); + dasd_device_t *device=NULL; + major_info_t * major_info; + int i,devno = -ENODEV; + + for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) { + for ( i = 0; i <= DASD_PER_MAJOR; i ++ ) { + device = major_info->dasd_device[i]; + if ( device && + device -> devinfo.irq == irq ) { + devno = device->devinfo.devno; + break; + } + } + if ( devno != -ENODEV ) + break; + } if ( devno < 0 ) { - printk (KERN_WARNING PRINTK_HEADER - "not_oper_handler called on irq %d no devno!\n", irq); - return; - } + printk ( KERN_WARNING PRINTK_HEADER + "not_oper_handler called on irq %d no devno!\n", irq); + return; + } printk ( KERN_INFO PRINTK_HEADER "not_oper_handler called on irq %d devno %04X\n", irq,devno); - devindex = devindex_from_devno(devno); - device = find_dasd_device(devindex); - dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 ); + if ( device -> open_count != 0 ) { + printk (KERN_ALERT PRINTK_HEADER + "Device %04X detached has still been open. expect errors\n", devno); } + dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 ); +} static int dasd_enable_single_volume ( int irq ) { int rc = 0; - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, NULL, 0); printk (KERN_INFO PRINTK_HEADER "waiting for response...\n"); { @@ -2008,14 +2224,14 @@ } dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, NULL, 0); - return rc; + return rc; } -static int +int dasd_oper_handler ( int irq, devreg_t *devreg ) { int devno; int devindex; - int rc; + int rc; devno = get_devno_by_irq(irq); if ( devno == -ENODEV ) return -ENODEV; @@ -2024,12 +2240,12 @@ if ( dasd_autodetect ) { dasd_add_range(devno,0); } else { - return -ENODEV; - } + return -ENODEV; + } } while ( devindex == -ENODEV ); rc = dasd_enable_single_volume(irq); - return rc; - } + return rc; +} /* * int @@ -2061,8 +2277,8 @@ devindex = devindex_from_devno (devno); if (devindex < 0) { printk (KERN_WARNING PRINTK_HEADER " device %d is not in list of known DASDs\n", irq); - return -ENODEV; - } + return -ENODEV; + } device = find_dasd_device (devindex); while ( (major_info = major_info_from_devindex (devindex)) == NULL ) { if ((rc = dasd_register_major (major_info)) > 0) { @@ -2072,8 +2288,8 @@ printk (KERN_WARNING PRINTK_HEADER "Couldn't register successfully to another major no\n"); return -ERANGE; - } - } + } + } ind = devindex & (DASD_PER_MAJOR-1); device = major_info->dasd_device[ind]; if (!device) { /* allocate device descriptor */ @@ -2108,7 +2324,7 @@ if (temp->check_characteristics) { if (temp->check_characteristics (device)) continue; - } + } discipline = temp; break; } @@ -2119,17 +2335,25 @@ devno, irq, discipline->name, device->name, major_from_devindex (devindex), (devindex % 64) << DASD_PARTN_BITS); - } else { + } else { break; - } + } device->discipline = discipline; if (device->discipline->int_handler) { +#ifdef CONFIG_DASD_DYNAMIC s390_request_irq_special(irq, device->discipline->int_handler, dasd_not_oper_handler, 0, DASD_NAME, &device->dev_status); +#else /* !defined(CONFIG_DASD_DYNAMIC) */ + request_irq(irq, + device->discipline->int_handler, + 0, + DASD_NAME, + &device->dev_status); +#endif /* CONFIG_DASD_DYNAMIC */ } atomic_compare_and_swap_debug (&device->level, DASD_DEVICE_LEVEL_UNKNOWN, @@ -2149,13 +2373,13 @@ DASD_DEVICE_LEVEL_RECOGNIZED, DASD_DEVICE_LEVEL_ANALYSIS_PENDING); s390irq_spin_unlock_irqrestore (irq, flags); -} + } } } else { atomic_compare_and_swap_debug (& device->level,DASD_DEVICE_LEVEL_RECOGNIZED, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); } - if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING) + if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING) break; case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: /* Fallthrough ?? */ return -EAGAIN; @@ -2170,7 +2394,7 @@ case 4096: break; default: -{ + { printk (KERN_INFO PRINTK_HEADER "/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes" " Did you format the drive?\n", @@ -2220,19 +2444,6 @@ } } else if (desired_level < current_level) { /* donwgrade device status */ switch (current_level) { - case DASD_DEVICE_LEVEL_PARTITIONED: /* Fallthrough ?? */ - /* delete the partition information */ - for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - struct hd_struct *p = &major_info->gendisk.part[minor+i]; - p->start_sect = 0; - p->nr_sects = 0; - p->type = 0; - } - atomic_compare_and_swap_debug (&device->level, - DASD_DEVICE_LEVEL_PARTITIONED, - DASD_DEVICE_LEVEL_ANALYSED); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) - break; case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ atomic_compare_and_swap_debug (&device->level, DASD_DEVICE_LEVEL_ANALYSED, @@ -2315,7 +2526,7 @@ #endif /* KERNEL_VERSION */ static struct proc_dir_entry* dasd_devices_entry; - + static int dasd_devices_open (struct inode* inode, struct file* file ) { @@ -2331,7 +2542,7 @@ return -ENOMEM; } else { file->private_data = (void *)info; - } + } while ( temp ) { int i; for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) { @@ -2393,7 +2604,7 @@ temp = temp->next; } info->len=len; - return rc; + return rc; } #define MIN(a,b) ((a)<(b)?(a):(b)) @@ -2407,41 +2618,59 @@ if(*offset >= p_info->len) { return 0; /* EOF */ - } + } else { len = MIN(user_len, (p_info->len - *offset)); copy_to_user(user_buf, &(p_info->data[*offset]), len); (*offset) += len; return len; /* number of bytes "read" */ + } +} + +static ssize_t +dasd_devices_write ( struct file *file, const char* user_buf, size_t user_len, loff_t* offset ) +{ + char * buffer = vmalloc(user_len); + + if ( buffer == NULL) + return -ENOMEM; + copy_from_user ( buffer, user_buf, user_len); + buffer[user_len] = 0; + printk ( KERN_INFO PRINTK_HEADER "Now executing %s\n",buffer); + if ( ! strncmp(buffer,"add range",strlen("add_range"))) { + + } else if ( ! strncmp(buffer,"enable device",strlen("enable device"))) { + + } else if ( ! strncmp(buffer,"disable device",strlen("disable device"))) { + + } else { + printk (KERN_WARNING PRINTK_HEADER "unknown command %s", + buffer ); } + vfree(buffer); + return user_len; } -static int +static int dasd_devices_close (struct inode* inode, struct file* file) { - int rc = 0; + int rc = 0; tempinfo_t* p_info = (tempinfo_t*)file->private_data; if ( p_info ) { if ( p_info->data ) vfree(p_info->data); vfree(p_info); - } - return rc; + } + return rc; } static struct file_operations dasd_devices_file_ops = { - NULL, /* lseek */ - dasd_devices_read, /* read */ - NULL, /* dasd_devices_write, */ /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - dasd_devices_open, /* open */ - NULL, /* flush */ - dasd_devices_close, /* close */ + read: dasd_devices_read, /* read */ + write: dasd_devices_write, /* write */ + open: dasd_devices_open, /* open */ + release: dasd_devices_close, /* close */ }; static struct inode_operations dasd_devices_inode_ops = @@ -2451,16 +2680,17 @@ #endif /* LINUX_IS_24 */ }; -void +int dasd_proc_init (void) { + int rc = 0; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - dasd_proc_root_entry = create_proc_entry("dasd", - S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, - &proc_root); + dasd_proc_root_entry = proc_mkdir("dasd",&proc_root); dasd_devices_entry = create_proc_entry("devices", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry); + dasd_devices_entry -> proc_fops = &dasd_devices_file_ops; + dasd_devices_entry -> proc_iops = &dasd_devices_inode_ops; #else proc_register (&proc_root, &dasd_proc_root_entry); dasd_devices_entry = (struct proc_dir_entry*)kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); @@ -2479,6 +2709,7 @@ proc_register(&dasd_proc_root_entry, dasd_devices_entry); } #endif /* LINUX_IS_24 */ + return rc; } void @@ -2506,15 +2737,13 @@ dasd_range_t *range; printk (KERN_INFO PRINTK_HEADER "initializing...\n"); - genhd_dasd_name = dasd_device_name; #ifndef MODULE dasd_split_parm_string(dasd_parm_string); #endif /* ! MODULE */ dasd_parse(dasd); - dasd_proc_init(); dasd_init_emergency_req(); - + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) init_waitqueue_head(&watcher_queue); spin_lock_init(&cq_lock); @@ -2527,72 +2756,115 @@ } else { printk (KERN_WARNING PRINTK_HEADER "Couldn't register successfully to major no %d\n", major_info->gendisk.major); - } + /* revert registration of major infos */ + goto major_failed; } + } + rc = dasd_proc_init(); + if ( rc ) { + goto proc_failed; + } + + genhd_dasd_name = dasd_device_name; #ifdef CONFIG_DASD_ECKD rc = dasd_eckd_init (); if (rc==0) { printk (KERN_INFO PRINTK_HEADER "Registered ECKD discipline successfully\n"); - } + } else { + goto eckd_failed; + } #endif /* CONFIG_DASD_ECKD */ #ifdef CONFIG_DASD_FBA rc = dasd_fba_init (); if (rc == 0) { printk (KERN_INFO PRINTK_HEADER "Registered FBA discipline successfully\n"); + } else { + goto fba_failed; } #endif /* CONFIG_DASD_FBA */ #ifdef CONFIG_DASD_MDSK - rc = dasd_diag_init (); - if (rc == 0) { + if ( MACHINE_IS_VM ) { + rc = dasd_diag_init (); + if (rc == 0) { printk (KERN_INFO PRINTK_HEADER "Registered MDSK discipline successfully\n"); - } + } else { + goto mdsk_failed; + } + } #endif /* CONFIG_DASD_MDSK */ rc = 0; for (range = dasd_range_head; range; range= range->next) { for (j = range->from; j <= range->to; j++) { irq = get_irq_by_devno (j); if (irq >= 0) - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, NULL, 0); + } } - } if ( dasd_autodetect ) { for ( irq = get_irq_first(); irq != -ENODEV; irq = get_irq_next(irq) ) { int devno = get_devno_by_irq(irq); int index = devindex_from_devno(devno); if ( index == -ENODEV ) { /* not included in ranges */ dasd_add_range (devno,0); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, NULL, 0); - } - } -} + } + } + } printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); -{ + { #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static wait_queue_head_t wait_queue; init_waitqueue_head(&wait_queue); #else static struct wait_queue *wait_queue = NULL; #endif /* LINUX_IS_24 */ - interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 ); - } + interruptible_sleep_on_timeout (&wait_queue, + (20 * HZ) >> 1 ); + } for (range = dasd_range_head; range; range= range->next) { for (j = range->from; j <= range->to; j++) { irq = get_irq_by_devno (j); if (irq >= 0) { dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, NULL, 0); - } + } } } - - printk (KERN_INFO PRINTK_HEADER "initialization completed\n"); - return rc; + goto out; +#ifdef CONFIG_DASD_MDSK + mdsk_failed: + dasd_diag_cleanup (); +#endif /* CONFIG_DASD_MDSK */ +#ifdef CONFIG_DASD_FBA + fba_failed: + dasd_fba_cleanup (); +#endif /* CONFIG_DASD_FBA */ +#ifdef CONFIG_DASD_ECKD + eckd_failed: + dasd_eckd_cleanup (); +#endif /* CONFIG_DASD_ECKD */ + proc_failed: + dasd_proc_cleanup(); + major_failed: { + for (major_info = dasd_major_info; + major_info; + major_info = major_info->next) { + dasd_unregister_major(major_info); + } + } + emergency_failed: + dasd_cleanup_emergency_req(); + failed: + printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n"); + out: + printk (KERN_INFO PRINTK_HEADER "initialization finished\n"); + return rc; } void @@ -2615,7 +2887,7 @@ dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0); kfree(find_dasd_device(devindex_from_devno(j))); - } + } } } for (major_info = dasd_major_info; major_info; major_info = major_info->next) { @@ -2634,19 +2906,19 @@ next = range -> next; kfree (range); if ( next == NULL ) - break; + break; else range = next; - } + } dasd_range_head = NULL; while ( dasd_devreg_head ) { reg = dasd_devreg_head->next; kfree ( dasd_devreg_head ); dasd_devreg_head = reg; - } + } printk (KERN_INFO PRINTK_HEADER "shutdown completed\n"); - } +} #ifdef MODULE int @@ -2655,7 +2927,7 @@ int rc=0; return dasd_init(); return rc; - } +} void cleanup_module ( void ) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/block/dasd.h linux/drivers/s390/block/dasd.h --- v2.2.17/drivers/s390/block/dasd.h Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/block/dasd.h Wed Nov 8 23:05:32 2000 @@ -5,6 +5,5 @@ ccw_req_t * dasd_alloc_request (char *, int , int ) ; void dasd_free_request(ccw_req_t *); int (*genhd_dasd_name)(char*,int,int,struct gendisk*); - - +int dasd_oper_handler ( int irq, devreg_t *devreg ); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c --- v2.2.17/drivers/s390/block/dasd_3990_erp.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/block/dasd_3990_erp.c Wed Nov 8 23:05:32 2000 @@ -64,13 +64,22 @@ dasd_3990_erp_examine_24 (char *sense) { - /* check for 'Command Recejct' which is always a fatal error */ + /* check for 'Command Recejct' whithout environmental data present */ if (sense[0] & 0x80) { - return dasd_era_fatal; - } - /* check for 'Invalid Track Format' */ + if (sense[2] &0x10){ + return dasd_era_recover; + } else { + return dasd_era_fatal; + } + } + + /* check for 'Invalid Track Format' whithout environmental data present */ if (sense[1] & 0x40) { - return dasd_era_fatal; + if (sense[2] &0x10){ + return dasd_era_recover; + } else { + return dasd_era_fatal; + } } /* check for 'No Record Found' */ if (sense[1] & 0x08) { diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c --- v2.2.17/drivers/s390/block/dasd_diag.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/block/dasd_diag.c Wed Nov 8 23:09:58 2000 @@ -5,6 +5,10 @@ * ...............: by Hartmunt Penner * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + + * History of changes + * 07/13/00 Added fixup sections for diagnoses ans saved some registers + * 07/14/00 fixed constraints in newly generated inline asm */ #include @@ -20,6 +24,7 @@ #include #include #include +#include #include "dasd.h" #include "dasd_diag.h" @@ -47,13 +52,24 @@ { int rc; - __asm__ __volatile__ (" lr 2,%1\n" - " .long 0x83200210\n" + __asm__ __volatile__ (" diag %1,0,0x210\n" "0: ipm %0\n" - " srl %0,28" + " srl %0,28\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: lhi %0,3\n" + " bras 1,3f\n" + " .long 1b\n" + "3: l 1,0(1)\n" + " br 1\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,2b\n" + ".previous\n" :"=d" (rc) :"d" ((void *) __pa (devchar)) - :"2"); + :"1"); return rc; } @@ -62,13 +78,23 @@ { int rc; - __asm__ __volatile__ (" lr 2,%1\n" - " lr 3,%2\n" - " .long 0x83230250\n" - " lr %0,3" - :"=d" (rc) - :"d" ((void *) __pa (iob)), "d" (cmd) - :"2", "3"); + __asm__ __volatile__ (" lr 1,%1\n" + " diag 1,%2,0x250\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: lhi %0,3\n" + " bras 1,3f\n" + " .long 1b\n" + "3: l 1,0(1)\n" + " br 1\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,2b\n" + ".previous\n" + : "=d" (rc) + : "d" ((void *) __pa (iob)), "0" (cmd) + : "1" ); return rc; } @@ -528,6 +554,23 @@ ctl_set_bit (0, 9); register_external_interrupt (0x2603, dasd_ext_handler); dasd_discipline_enq(&dasd_diag_discipline); + } else { + printk ( KERN_INFO PRINTK_HEADER + "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name); + rc = -EINVAL; + } + return rc; +} + +void +dasd_diag_cleanup( void ) { + int rc = 0; + if ( MACHINE_IS_VM ) { + printk ( KERN_INFO PRINTK_HEADER + "%s discipline cleaning up\n", dasd_diag_discipline.name); + dasd_discipline_deq(&dasd_diag_discipline); + unregister_external_interrupt (0x2603, dasd_ext_handler); + ctl_clear_bit (0, 9); } else { printk ( KERN_INFO PRINTK_HEADER "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c --- v2.2.17/drivers/s390/block/dasd_eckd.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/block/dasd_eckd.c Sat Dec 9 20:56:00 2000 @@ -6,6 +6,12 @@ * History of changes (starts July 2000) * 07/11/00 Enabled rotational position sensing + * 07/14/00 Reorganized the format process for better ERP + * 07/20/00 added experimental support for 2105 control unit (ESS) + * 07/24/00 increased expiration time and added the missing zero + * 08/07/00 added some bits to define_extent for ESS support + * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF) + * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages) */ #include @@ -21,6 +27,7 @@ #include #include #include +#include #include "dasd.h" #include "dasd_eckd.h" @@ -32,15 +39,15 @@ #define PRINTK_HEADER DASD_NAME"(eckd):" #define ECKD_C0(i) (i->home_bytes) -#define ECKD_F(i) (i -> formula) + #define ECKD_F(i) (i->formula) #define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1)) #define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2)) #define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3)) #define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0) #define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0) -#define ECKD_F6(i) (i -> factor6) -#define ECKD_F7(i) (i -> factor7) -#define ECKD_F8(i) (i -> factor8) +#define ECKD_F6(i) (i->factor6) +#define ECKD_F7(i) (i->factor7) +#define ECKD_F8(i) (i->factor8) #define DASD_ECKD_CCW_WRITE 0x05 #define DASD_ECKD_CCW_READ 0x06 @@ -67,6 +74,25 @@ eckd_count_t count_area; } dasd_eckd_private_t; +static +devreg_t dasd_eckd_known_devices[] = { + { + ci : { hc: { ctype: 0x3990, dtype: 0x3390 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + }, + { + ci : { hc: { ctype: 0x3990, dtype: 0x3380 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + }, + { + ci : { hc: { ctype: 0x9343, dtype: 0x9345 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + } +}; + static inline unsigned int round_up_multiple (unsigned int no, unsigned int mult) { @@ -133,15 +159,15 @@ { int rpt = 0; int dn; - switch ( rdc -> dev_type ) { - case 0x3380: + switch (rdc->dev_type) { + case 0x3380: if (kl) return 1499 / (15 + 7 + ceil_quot (kl + 12, 32) + ceil_quot (dl + 12, 32)); else return 1499 / (15 + ceil_quot (dl + 12, 32)); - case 0x3390: + case 0x3390: dn = ceil_quot (dl + 6, 232) + 1; if (kl) { int kn = ceil_quot (kl + 6, 232) + 1; @@ -151,16 +177,16 @@ } else return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34)); - case 0x9345: - dn = ceil_quot (dl + 6, 232) + 1; - if (kl) { - int kn = ceil_quot (kl + 6, 232) + 1; - return 1420 / (18 + - 7 + ceil_quot (kl + 6 * kn, 34) + - ceil_quot (dl + 6 * dn, 34)); - } else - return 1420 / (18 + - 7 + ceil_quot (dl + 6 * dn, 34)); + case 0x9345: + dn = ceil_quot (dl + 6, 232) + 1; + if (kl) { + int kn = ceil_quot (kl + 6, 232) + 1; + return 1420 / (18 + + 7 + ceil_quot (kl + 6 * kn, 34) + + ceil_quot (dl + 6 * dn, 34)); + } else + return 1420 / (18 + + 7 + ceil_quot (dl + 6 * dn, 34)); } return rpt; } @@ -186,7 +212,7 @@ memset (de_ccw, 0, sizeof (ccw1_t)); de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; de_ccw->count = 16; - de_ccw->cda = (void *) __pa (data); + de_ccw->cda = (__u32) __pa (data); memset (data, 0, sizeof (DE_eckd_data_t)); switch (cmd) { @@ -198,12 +224,12 @@ case DASD_ECKD_CCW_READ_CKD_MT: case DASD_ECKD_CCW_READ_COUNT: data->mask.perm = 0x1; - data->attributes.operation = 0x3; /* enable seq. caching */ + data->attributes.operation = 0x3; /* enable seq. caching */ break; case DASD_ECKD_CCW_WRITE: case DASD_ECKD_CCW_WRITE_MT: data->mask.perm = 0x02; - data->attributes.operation = 0x3; /* enable seq. caching */ + data->attributes.operation = 0x3; /* enable seq. caching */ break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: @@ -220,6 +246,9 @@ break; } data->attributes.mode = 0x3; + if ( private -> rdc_data.cu_type == 0x2105 ) { + data -> reserved |= 0x40; + } data->beg_ext.cyl = beg.cyl; data->beg_ext.head = beg.head; data->end_ext.cyl = end.cyl; @@ -233,19 +262,19 @@ int rec_on_trk, int no_rec, int cmd, - dasd_device_t * device) + dasd_device_t * device, + int reclen) { dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private; ch_t geo = {private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl}; ch_t seek ={trk / (geo.head), trk % (geo.head)}; - int reclen = device->sizes.bp_block; int sector; memset (lo_ccw, 0, sizeof (ccw1_t)); lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; lo_ccw->count = 16; - lo_ccw->cda = (void *) __pa (data); + lo_ccw->cda = (__u32) __pa (data); memset (data, 0, sizeof (LO_eckd_data_t)); switch (cmd) { @@ -293,7 +322,7 @@ break; case DASD_ECKD_CCW_READ_COUNT: data->operation.operation = 0x06; - break; + break; default: INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd); } @@ -325,17 +354,19 @@ static int dasd_eckd_id_check ( dev_info_t *info ) { - if ( info->sid_data.cu_type == 0x3990 ) + if ( info->sid_data.cu_type == 0x3990 || + info->sid_data.cu_type == 0x2105 ) if ( info->sid_data.dev_type == 0x3390 ) return 0; - if ( info->sid_data.cu_type == 0x3990 ) + if ( info->sid_data.cu_type == 0x3990 || + info->sid_data.cu_type == 0x2105 ) if ( info->sid_data.dev_type == 0x3380 ) return 0; if ( info->sid_data.cu_type == 0x9343 ) if ( info->sid_data.dev_type == 0x9345 ) return 0; return -ENODEV; - } +} static int dasd_eckd_check_characteristics (struct dasd_device_t *device) @@ -366,7 +397,7 @@ printk ( KERN_WARNING PRINTK_HEADER "Read device characteristics returned error %d\n",rc); return rc; - } + } printk ( KERN_INFO PRINTK_HEADER "%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n", device->devinfo.devno, device->devinfo.irq, @@ -381,7 +412,7 @@ printk ( KERN_WARNING PRINTK_HEADER "Read configuration data returned error %d\n",rc); return rc; - } + } if ( conf_len != sizeof(dasd_eckd_confdata_t)) { printk ( KERN_WARNING PRINTK_HEADER "sizes of configuration data mismatch %d (read) vs %ld (expected)\n", @@ -429,13 +460,14 @@ define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device); ccw->flags = CCW_FLAG_CC; ccw++; - locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, device); + locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device,0); ccw->flags = CCW_FLAG_CC; ccw++; ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->count = 8; - ccw->cda = (void *) __pa (count_data); + ccw->cda = (__u32) __pa (count_data); cqr->device = device; + cqr->retries = 0; atomic_set (&cqr->status, CQR_STATUS_FILLED); return cqr; @@ -511,10 +543,9 @@ return rc; } -static inline int -dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags) +static ccw_req_t * +dasd_eckd_format_device (dasd_device_t *device, format_data_t *fdata) { - int rc = 0; int i; ccw_req_t *fcp = NULL; DE_eckd_data_t *DE_data = NULL; @@ -525,252 +556,178 @@ ccw1_t *last_ccw = NULL; void * last_data = NULL; dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private; - int retries; - + int trk = fdata -> start_unit; + int bs = fdata -> blksize == DASD_FORMAT_DEFAULT_BLOCKSIZE ? 4096 : fdata->blksize; + int flags = fdata -> intensity == DASD_FORMAT_DEFAULT_INTENSITY ? 0 : fdata -> intensity; + int rpt = recs_per_track (&(private->rdc_data), 0, bs); int cyl = trk / private->rdc_data.trk_per_cyl; int head = trk % private->rdc_data.trk_per_cyl; int wrccws = rpt; int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t); + + if ( ( (fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) && + trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl ) ) || + ( (fdata -> stop_unit != DASD_FORMAT_DEFAULT_STOP_UNIT) && + trk > fdata->stop_unit ) ) { + printk (KERN_WARNING PRINTK_HEADER "Track %d reached...ending!\n",trk); + return NULL; + } + switch(bs) { + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + printk (KERN_WARNING PRINTK_HEADER "Invalid blocksize %d...terminating!\n",bs); + return NULL; + } switch ( flags ) { case 0x00: case 0x01: case 0x03: - break; + case 0x04: /* make track invalid */ + break; default: - return -EINVAL; + printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n",flags); + return NULL; + } + + /* print status line */ + if ( (private->rdc_data.no_cyl < 20 ) ? + ( trk % private->rdc_data.no_cyl == 0 ) : + ( trk % private->rdc_data.no_cyl == 0 && + (trk / private->rdc_data.no_cyl) % + (private->rdc_data.no_cyl / 20 ) ) ) { + + printk (KERN_INFO PRINTK_HEADER + "Format %04X Cylinder: %d Flags: %d\n", + device->devinfo.devno, + trk / private->rdc_data.trk_per_cyl, + flags); } - if ( flags & 0x1 ) { - wrccws++; - datasize += sizeof(eckd_count_t); - } - if ( flags & 0x2 ) { - wrccws++; - datasize += sizeof(eckd_home_t); + if ( flags & 0x04) { + rpt = 1; + wrccws = 1; + } else { + if ( flags & 0x1 ) { + wrccws++; + datasize += sizeof(eckd_count_t); + } + if ( flags & 0x2 ) { + wrccws++; + datasize += sizeof(eckd_home_t); + } } fcp = ccw_alloc_request (dasd_eckd_discipline.name, wrccws + 2, datasize+rpt*sizeof(eckd_count_t)); - fcp->device = device; - - last_data = fcp->data; - DE_data = (DE_eckd_data_t *) last_data; - last_data = (void*)(DE_data +1); - LO_data = (LO_eckd_data_t *) last_data; - last_data = (void*)(LO_data +1); - if ( flags & 0x2 ) { - ha_data = (eckd_home_t *) last_data; - last_data = (void*)(ha_data +1); - } - if ( flags & 0x1 ) { - r0_data = (eckd_count_t *) last_data; - last_data = (void*)(r0_data +1); - } - ct_data = (eckd_count_t *)last_data; - - last_ccw = fcp->cpaddr; - - switch (flags) { - case 0x03: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - break; - case 0x01: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_RECORD_ZERO, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, + if ( fcp != NULL ) { + fcp->device = device; + fcp->retries = 2; /* set retry counter to enable ERP */ + last_data = fcp->data; + DE_data = (DE_eckd_data_t *) last_data; + last_data = (void*)(DE_data +1); + LO_data = (LO_eckd_data_t *) last_data; + last_data = (void*)(LO_data +1); + if ( flags & 0x2 ) { + ha_data = (eckd_home_t *) last_data; + last_data = (void*)(ha_data +1); + } + if ( flags & 0x1 ) { + r0_data = (eckd_count_t *) last_data; + last_data = (void*)(r0_data +1); + } + ct_data = (eckd_count_t *)last_data; + + last_ccw = fcp->cpaddr; + + switch (flags) { + case 0x03: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,device->sizes.bp_block ); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + break; + case 0x01: + define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_RECORD_ZERO, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - memset (r0_data, 0, sizeof (eckd_count_t)); - break; - case 0x00: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_CKD, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_CKD, device); - LO_data->length = bs; - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - break; - default: - PRINT_WARN ("Unknown format flags...%d\n", flags); - return -EINVAL; - } - if (flags & 0x02) { - PRINT_WARN ("Unsupported format flag...%d\n", flags); - return -EINVAL; - } - if (flags & 0x01) { /* write record zero */ - r0_data->cyl = cyl; - r0_data->head = head; - r0_data->record = 0; - r0_data->kl = 0; - r0_data->dl = 8; - last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO; - last_ccw->count = 8; - last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; - last_ccw->cda = (void *) __pa (r0_data); - last_ccw++; - } - /* write remaining records */ - for (i = 0; i < rpt; i++, last_ccw++) { - memset (ct_data + i, 0, sizeof (eckd_count_t)); - (ct_data + i)->cyl = cyl; - (ct_data + i)->head = head; - (ct_data + i)->record = i + 1; - (ct_data + i)->kl = 0; - (ct_data + i)->dl = bs; - last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; - last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; - last_ccw->count = 8; - last_ccw->cda = (void *) __pa (ct_data + i); - } - (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC); - fcp->device = device; - do { -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - DECLARE_WAITQUEUE (wait,current); -#else - struct wait_queue wait = {current, NULL}; -#endif /* LINUX_VERSION_CODE */ - unsigned long flags; - int cs; - - retries = 1; - s390irq_spin_lock_irqsave (device->devinfo.irq, flags); - atomic_set(&fcp->status,CQR_STATUS_QUEUED); - do { - rc = dasd_eckd_discipline.start_IO (fcp); - } while ( rc && retries-- ); - if ( rc && retries == 0 ) + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,device->sizes.bp_block); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + memset (r0_data, 0, sizeof (eckd_count_t)); break; -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - add_wait_queue (&device->wait_q, &wait); -#endif /* LINUX_VERSION_CODE */ - do { - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); - schedule (); - s390irq_spin_lock_irqsave (device->devinfo.irq, flags); - cs = atomic_read (&fcp->status); - } while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_ERROR)); -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - remove_wait_queue (&device->wait_q, &wait); -#endif /* LINUX_VERSION_CODE */ - s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); - } while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) && - retries--); - if ( retries == 0 ) - rc = -EIO; - ccw_free_request (fcp); - return rc; -} - -static int -dasd_eckd_format_device (struct dasd_device_t *device, struct format_data_t *fdata) -{ - int rc = 0; - int i; - format_data_t fd; - dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private; - int last_track =private->rdc_data.no_cyl*private->rdc_data.trk_per_cyl-1; - int intensity; - kdev_t kdev = device->kdev; - int nr_tracks, blocksize; - - if (fdata==NULL) { - fd.start_unit = 0; - fd.stop_unit = last_track; - fd.blksize = 4096; - } else { - memcpy (&fd, fdata, sizeof (format_data_t)); - if (fd.stop_unit == -1) { - fd.stop_unit = last_track; - } - if (fd.blksize == 0) { - fd.blksize = 4096; - } - } - if (fd.start_unit > fd.stop_unit) { - return -EINVAL; - } - if (fd.start_unit > last_track ) { - return -EINVAL; - } - if (fd.stop_unit > last_track ) { - return -EINVAL; - } - switch(fd.blksize) { - case 512: - case 1024: - case 2048: - case 4096: - break; - default: - return -EINVAL; - } - fd.intensity = 0x0; - intensity = fd.intensity; - set_blocksize(kdev, fd.blksize); - printk (KERN_INFO PRINTK_HEADER - "Formatting device %04X from track %d to %d with bs %d\n", - device->devinfo.devno,fd.start_unit, fd.stop_unit, fd.blksize); - nr_tracks = fd.stop_unit-fd.start_unit+1; - for (i = 0; i <= nr_tracks; i++) { - /* print 20 messages per format cmd at all */ - if ( i % (nr_tracks / 20) == 0 ) { - printk (KERN_INFO PRINTK_HEADER - "Format %04X Cylinder: %d Track %d Intensity %d\n", - device->devinfo.devno, - (i+fd.start_unit) / private->rdc_data.trk_per_cyl, - (i+fd.start_unit) % private->rdc_data.trk_per_cyl, - intensity); - } - do { - if ( i == 0 ) { - blocksize = 8; - } else { - blocksize = fd.blksize; - } - rc = dasd_eckd_format_track (device, - (i % nr_tracks) + fd.start_unit , - blocksize, intensity); - /* fix VM controlled minidisk */ - if ( rc ) { - if ( intensity ) { - intensity = intensity >> 1; - } - printk (KERN_WARNING PRINTK_HEADER - "decreasing format intensity to %d\n", - intensity); - } - } while ( rc && intensity > 0); - if (rc) { - printk (KERN_WARNING PRINTK_HEADER - "Formatting of device %04X Cylinder %d Track %d failed...exiting\n", - device->devinfo.devno, - i / private->rdc_data.trk_per_cyl, - i % private->rdc_data.trk_per_cyl); + case 0x04: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_CKD, device); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_CKD, device,0); + LO_data->length = bs; + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; break; - } - } - printk ( KERN_INFO PRINTK_HEADER - "Formatting of device %04X completed from track %d to %d with bs %d\n", - device->devinfo.devno, fd.start_unit, fd.stop_unit, fd.blksize); - return rc; + case 0x00: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_CKD, device); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_CKD, device,device->sizes.bp_block); + LO_data->length = bs; + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + break; + default: + PRINT_WARN ("Unknown format flags...%d\n", flags); + return NULL; + } + if (flags & 0x02 ) { + PRINT_WARN ("Unsupported format flag...%d\n", flags); + return NULL; + } + if (flags & 0x01) { /* write record zero */ + r0_data->cyl = cyl; + r0_data->head = head; + r0_data->record = 0; + r0_data->kl = 0; + r0_data->dl = 8; + last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO; + last_ccw->count = 8; + last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; + last_ccw->cda = (__u32) __pa (r0_data); + last_ccw++; + } + /* write remaining records */ + for (i = 0; i < rpt; i++) { + memset (ct_data + i, 0, sizeof (eckd_count_t)); + (ct_data + i)->cyl = cyl; + (ct_data + i)->head = head; + (ct_data + i)->record = i + 1; + (ct_data + i)->kl = 0; + (ct_data + i)->dl = bs; + last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; + last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; + last_ccw->count = 8; + last_ccw->cda = (__u32) __pa (ct_data + i); + last_ccw ++; + } + (last_ccw-1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC); + fcp->device = device; + atomic_set(&fcp->status,CQR_STATUS_FILLED); + } + return fcp; } static dasd_era_t @@ -781,8 +738,9 @@ stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) return dasd_era_none; - switch (device->devinfo.sid_data.cu_model) { + switch (device->devinfo.sid_data.cu_type) { case 0x3990: + case 0x2105: return dasd_3990_erp_examine (cqr, stat); case 0x9343: return dasd_9343_erp_examine (cqr, stat); @@ -838,20 +796,20 @@ /* count bhs to prevent errors, when bh smaller than block */ bhct = 0; for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size > byt_per_blk) - for (size = 0; size < bh->b_size; size += byt_per_blk) + if (bh->b_size > byt_per_blk) + for (size = 0; size < bh->b_size; size += byt_per_blk) bhct++; else bhct++; } - + rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 2 + bhct, - sizeof (DE_eckd_data_t) + - sizeof (LO_eckd_data_t)); - if ( ! rw_cp ) { - return NULL; - } + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + if (!rw_cp) { + return NULL; + } DE_data = rw_cp->data; LO_data = rw_cp->data + sizeof (DE_eckd_data_t); ccw = rw_cp->cpaddr; @@ -860,17 +818,17 @@ ccw->flags = CCW_FLAG_CC; ccw++; locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1, - req->nr_sectors >> shift, rw_cmd, device); + req->nr_sectors >> shift, rw_cmd, device,device->sizes.bp_block); ccw->flags = CCW_FLAG_CC; for (bh = req->bh; bh != NULL;) { if (bh->b_size > byt_per_blk) { - for (size = 0; size < bh->b_size; size += byt_per_blk) { - ccw++; - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = rw_cmd; - ccw->count = byt_per_blk; - ccw->cda = (void *) __pa (bh->b_data + size); - } + for (size = 0; size < bh->b_size; size += byt_per_blk) { + ccw++; + ccw->flags = CCW_FLAG_CC; + ccw->cmd_code = rw_cmd; + ccw->count = byt_per_blk; + ccw->cda = (__u32) __pa (bh->b_data + size); + } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ for (size = 0; bh != NULL && size < byt_per_blk;) { @@ -878,22 +836,23 @@ ccw->flags = CCW_FLAG_DC; ccw->cmd_code = rw_cmd; ccw->count = bh->b_size; - ccw->cda = (void *) __pa (bh->b_data); + ccw->cda = (__u32) __pa (bh->b_data); size += bh->b_size; bh = bh->b_reqnext; - } + } if (size != byt_per_blk) { - PRINT_WARN ("Cannot fulfill small request %d vs. %d (%d sects)\n", size, byt_per_blk, req->nr_sectors); + PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors); ccw_free_request (rw_cp); - return NULL; - } + return NULL; + } ccw->flags = CCW_FLAG_CC; } } ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC); rw_cp->device = device; - rw_cp->expires = 5 * 0xf424000; /* 5 seconds */ + rw_cp->expires = 60 * (unsigned long long)0xf4240000; /* 60 seconds */ rw_cp->req = req; + rw_cp->retries = 2; atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED); return rw_cp; } @@ -924,7 +883,7 @@ for (sct = 0; sct < 8; sct++) { len += sprintf ( page + len," %2d:0x%02x", 8 * sl + sct, sense[8 * sl + sct]); - } + } len += sprintf ( page + len,"\n"); } if (sense[27] & 0x80) { @@ -938,8 +897,8 @@ len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER "32 Byte: Format: %x Exception class %x\n", sense[6] & 0x0f, sense[22] >> 4); - } - } + } + } return page; } @@ -964,11 +923,43 @@ int dasd_eckd_init( void ) { int rc = 0; + int i; printk ( KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_eckd_discipline.name); ASCEBC(dasd_eckd_discipline.ebcname,4); dasd_discipline_enq(&dasd_eckd_discipline); - +#ifdef CONFIG_DASD_DYNAMIC + for ( i=0; i #include #include +#include #include "dasd.h" #include "dasd_fba.h" @@ -40,6 +41,20 @@ dasd_fba_characteristics_t rdc_data; } dasd_fba_private_t; +static +devreg_t dasd_fba_known_devices[] = { + { + ci : { hc: { ctype: 0x6310, dtype: 0x9336 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + }, + { + ci : { hc: { ctype: 0x3880, dtype: 0x3370 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + } +}; + static inline void define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw, int blksize, int beg, int nr) @@ -86,7 +101,7 @@ return 0; if ( info->sid_data.cu_type == 0x6310 ) if ( info->sid_data.dev_type == 0x9336 ) - return 0; + return 0; return -ENODEV; } @@ -247,17 +262,17 @@ /* count bhs to prevent errors, when bh smaller than block */ bhct = 0; for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size > byt_per_blk) - for (size = 0; size < bh->b_size; size += byt_per_blk) + if (bh->b_size > byt_per_blk) + for (size = 0; size < bh->b_size; size += byt_per_blk) bhct++; else bhct++; } - + rw_cp = dasd_alloc_request (dasd_fba_discipline.name, 2 + bhct, - sizeof (DE_fba_data_t) + - sizeof (LO_fba_data_t)); + sizeof (DE_fba_data_t) + + sizeof (LO_fba_data_t)); if (!rw_cp) { return NULL; } @@ -326,7 +341,7 @@ int len; if ( page == NULL ) { return NULL; -} + } len = sprintf ( page, KERN_WARNING PRINTK_HEADER "device %04X on irq %d: I/O status report:\n", @@ -352,15 +367,48 @@ int_handler: dasd_int_handler }; + int dasd_fba_init( void ) { - int rc = 0; + int rc = 0; + int i; printk ( KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_fba_discipline.name); ASCEBC(dasd_fba_discipline.ebcname,4); dasd_discipline_enq(&dasd_fba_discipline); +#ifdef CONFIG_DASD_DYNAMIC + for ( i=0; i * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a @@ -15,7 +15,6 @@ #include #include - #ifdef PRINTK_HEADER #undef PRINTK_HEADER #endif @@ -33,6 +32,7 @@ /* pointer to list of allocated requests */ static ccw_req_t *ccwreq_actual = NULL; +static spinlock_t ccwchain_lock = SPIN_LOCK_UNLOCKED; /* pointer to debug area */ static debug_info_t *debug_area = NULL; @@ -56,12 +56,16 @@ static void dechain ( ccw_req_t *request ) { + long flags; + /* Sanity checks */ if ( request == NULL ) { printk( KERN_WARNING PRINTK_HEADER "Trying to deallocate NULL request\n"); return; } + + spin_lock_irqsave(&ccwchain_lock,flags); /* first deallocate request from list of allocates requests */ if ( request -> int_next && request -> int_prev ) { if ( request -> int_next == request -> int_prev ) { @@ -75,6 +79,7 @@ } } else if ( request -> int_next || request -> int_prev ) { } + spin_unlock_irqrestore(&ccwchain_lock,flags); return; } @@ -90,13 +95,14 @@ ccw_req_t * request = NULL; int cachind = 0; int size_needed = 0; + long flags; debug_text_event ( debug_area, 1, "ALLC"); if ( magic ) { debug_text_event ( debug_area, 1, magic); } - debug_event ( debug_area, 1, cplength); - debug_event ( debug_area, 1, datasize); + debug_int_event ( debug_area, 1, cplength); + debug_int_event ( debug_area, 1, datasize); /* Sanity checks */ if ( cplength == 0 ) { @@ -140,7 +146,7 @@ /* Try to fulfill the request from a cache */ while ( cachind < CCW_NUMBER_CACHES ) { /* Now try to get an entry from a cache above or equal to cachind */ if ( ccw_cache[cachind] == NULL ){ - printk("cache=%p index %d\n",cachind,cachind); + printk(KERN_WARNING PRINTK_HEADER "NULL cache found! cache=%p index %d\n",ccw_cache[cachind],cachind); } request = kmem_cache_alloc ( ccw_cache[cachind], GFP_ATOMIC ); if ( request != NULL ) { @@ -148,13 +154,13 @@ request->cache = ccw_cache[cachind]; break; } else { - printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache"); + printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache\n"); } cachind++; } /* if no success, fall back to kmalloc */ if ( request == NULL ) { - printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc"); + printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc\n"); request = kmalloc ( sizeof(ccw_req_t), GFP_ATOMIC ); if ( request != NULL ) { memset ( request, 0, sizeof(ccw_req_t)); @@ -162,7 +168,7 @@ } /* Initialize request */ if ( request == NULL ) { - printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request"); + printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request\n"); } else { if ( request -> cache != NULL ) { /* Three cases when coming from a cache */ @@ -215,6 +221,7 @@ request -> cplength = cplength; request -> datasize = datasize; /* enqueue request to list of allocated requests */ + spin_lock_irqsave(&ccwchain_lock,flags); if ( ccwreq_actual == NULL ) { /* queue empty */ ccwreq_actual = request; request->int_prev = ccwreq_actual; @@ -225,8 +232,9 @@ request->int_prev->int_next = request; request->int_next->int_prev = request; } + spin_unlock_irqrestore(&ccwchain_lock,flags); } - debug_event ( debug_area, 1, (long)request); + debug_int_event ( debug_area, 1, (long)request); return request; } @@ -242,7 +250,7 @@ int slabsize; debug_text_event ( debug_area, 1, "FREE"); - debug_event ( debug_area, 1, (long)request); + debug_int_event ( debug_area, 1, (long)request); /* Sanity checks */ if ( request == NULL ) { printk(KERN_DEBUG PRINTK_HEADER"Trying to deallocate NULL request\n"); @@ -256,7 +264,7 @@ if ( request ->cpaddr ) { kfree ( request -> cpaddr ); } - dechain ( request); + dechain (request); kfree ( request ); } else { /* Find which area has been allocated by kmalloc */ @@ -300,26 +308,28 @@ int cachind; /* allocate a debug area */ - debug_area = debug_register( "ccwcache", 2, 4); + debug_area = debug_register( "ccwcache", 2, 4,4); if ( ! debug_area ) { printk ( KERN_WARNING PRINTK_HEADER"cannot allocate debug area\n" ); } else { printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area ); } + debug_register_view(debug_area,&debug_hex_view); + debug_register_view(debug_area,&debug_ebcdic_view); debug_text_event ( debug_area, 0, "INIT"); /* First allocate the kmem caches */ for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) { int slabsize = SMALLEST_SLAB << cachind; debug_text_event ( debug_area, 1, "allc"); - debug_event ( debug_area, 1, slabsize); + debug_int_event ( debug_area, 1, slabsize); sprintf ( ccw_cache_name[cachind], "%s%d%c", ccw_name_template, slabsize, 0); ccw_cache[cachind] = kmem_cache_create( ccw_cache_name[cachind], slabsize, 0, SLAB_HWCACHE_ALIGN, NULL, NULL ); - debug_event ( debug_area, 1, (long)ccw_cache[cachind]); + debug_int_event ( debug_area, 1, (long)ccw_cache[cachind]); if ( ! ccw_cache [cachind] ) { printk (KERN_WARNING PRINTK_HEADER "Allocation of CCW cache failed\n"); } @@ -345,7 +355,7 @@ } } } - debug_unregister( debug_area ,"ccwcache"); + debug_unregister( debug_area ); } #ifdef MODULE diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c --- v2.2.17/drivers/s390/char/con3215.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/char/con3215.c Sat Dec 9 20:56:00 2000 @@ -5,6 +5,10 @@ * S390 version * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * + * Updated: + * Aug-2000: Added tab support + * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu) */ #include @@ -45,6 +49,8 @@ #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ #define RAW3215_BH_PENDING 256 /* indication for bh scheduling */ +#define TAB_STOP_SIZE 8 /* tab stop size */ + struct _raw3215_info; /* forward declaration ... */ int raw3215_condevice = -1; /* preset console device */ @@ -87,6 +93,7 @@ char *message; /* pending message from raw3215_irq */ int msg_dstat; /* dstat for pending message */ int msg_cstat; /* cstat for pending message */ + int line_pos; /* position on the line (for tabs) */ } raw3215_info; static raw3215_info *raw3215[NR_3215]; /* array of 3215 devices structures */ @@ -103,11 +110,13 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +extern void tod_wait(unsigned long usecs); + __initfunc(void con3215_setup(char *str, char *ints)) { int vdev; - vdev = simple_strtoul(str,&str,10); + vdev = simple_strtoul(str,&str,0); if (vdev >= 0 && vdev < 65536) raw3215_condevice = vdev; return; @@ -167,7 +176,7 @@ ccw->cmd_code = 0x0A; /* read inquiry */ ccw->flags = 0x20; /* ignore incorrect length */ ccw->count = 160; - ccw->cda = (void *) virt_to_phys(raw->inbuf); + ccw->cda = (__u32) __pa(raw->inbuf); } /* @@ -178,7 +187,7 @@ */ static void raw3215_mk_write_req(raw3215_info *raw) { - raw3215_req *req; + raw3215_req *req; ccw1_t *ccw; int len, count, ix, lines; @@ -186,28 +195,28 @@ return; /* check if there is a queued write request */ req = raw->queued_write; - if (req == NULL) { + if (req == NULL) { /* no queued write request, use new req structure */ - req = raw3215_alloc_req(); + req = raw3215_alloc_req(); req->type = RAW3215_WRITE; - req->info = raw; + req->info = raw; raw->queued_write = req; } else { raw->written -= req->len; -} + } ccw = req->ccws; req->start = (raw->head - raw->count + raw->written) & (RAW3215_BUFFER_SIZE - 1); -/* + /* * now we have to count newlines. We can at max accept * RAW3215_MAX_NEWLINE newlines in a single ssch due to * a restriction in VM - */ + */ lines = 0; ix = req->start; while (lines < RAW3215_MAX_NEWLINE && ix != raw->head) { - if (raw->buffer[ix] == '\n') + if (raw->buffer[ix] == 0x15) lines++; ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1); } @@ -226,21 +235,20 @@ ccw[-1].flags |= 0x40; /* use command chaining */ ccw->cmd_code = 0x01; /* write, auto carrier return */ ccw->flags = 0x20; /* ignore incorrect length ind. */ - ccw->cda = - (void *) virt_to_phys(raw->buffer + ix); + ccw->cda = (__u32) __pa(raw->buffer + ix); count = len; if (ix + count > RAW3215_BUFFER_SIZE) - count = RAW3215_BUFFER_SIZE-ix; + count = RAW3215_BUFFER_SIZE - ix; ccw->count = count; len -= count; ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1); ccw++; } -/* + /* * Add a NOP to the channel program. 3215 devices are purely * emulated and its much better to avoid the channel end * interrupt in this case. - */ + */ if (ccw > req->ccws) ccw[-1].flags |= 0x40; /* use command chaining */ ccw->cmd_code = 0x03; /* NOP */ @@ -319,7 +327,7 @@ if ((raw->queued_write->delayable == 0) || (raw->flags & RAW3215_FLUSHING)) { /* execute write requests bigger than minimum size */ - raw3215_start_io(raw); + raw3215_start_io(raw); if (raw->flags & RAW3215_TIMER_RUNS) { del_timer(&raw->timer); raw->flags &= ~RAW3215_TIMER_RUNS; @@ -459,7 +467,7 @@ return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ && raw->tty != NULL) { tty = raw->tty; - count = 160 - req->residual; + count = 160 - req->residual; if (MACHINE_IS_P390) { slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE); if (count > slen) @@ -517,7 +525,7 @@ } else if (req->type == RAW3215_WRITE) { raw->count -= req->len; raw->written -= req->len; - } + } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); /* check for empty wait */ @@ -530,7 +538,7 @@ raw3215_sched_bh(raw); break; default: - /* Strange interrupt, I'll do my best to clean up */ + /* Strange interrupt, I'll do my best to clean up */ if ((raw = raw3215_find_info(irq)) == NULL) return; /* That shouldn't happen ... */ if (req != NULL && req->type != RAW3215_FREE) { @@ -540,18 +548,46 @@ } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); - } - raw->message = KERN_WARNING - "Spurious interrupt in in raw3215_irq " - "(dev %i, dev sts 0x%2x, sch sts 0x%2x)"; - raw->msg_dstat = dstat; - raw->msg_cstat = cstat; + } + raw->message = KERN_WARNING + "Spurious interrupt in in raw3215_irq " + "(dev %i, dev sts 0x%2x, sch sts 0x%2x)"; + raw->msg_dstat = dstat; + raw->msg_cstat = cstat; raw3215_sched_bh(raw); } return; } /* + * Wait until length bytes are available int the output buffer. + * Has to be called with the s390irq lock held. Can be called + * disabled. + */ +void raw3215_make_room(raw3215_info *raw, unsigned int length) +{ + while (RAW3215_BUFFER_SIZE - raw->count < length) { + /* there might be a request pending */ + raw->flags |= RAW3215_FLUSHING; + raw3215_mk_write_req(raw); + raw3215_try_io(raw); + raw->flags &= ~RAW3215_FLUSHING; + if (wait_cons_dev(raw->irq) != 0) { + /* that shouldn't happen */ + raw->count = 0; + raw->written = 0; + } + /* Enough room freed up ? */ + if (RAW3215_BUFFER_SIZE - raw->count >= length) + break; + /* there might be another cpu waiting for the lock */ + s390irq_spin_unlock(raw->irq); + tod_wait(100); + s390irq_spin_lock(raw->irq); + } +} + +/* * String write routine for 3215 devices */ static int @@ -569,16 +605,7 @@ RAW3215_BUFFER_SIZE : length; length -= count; - while (RAW3215_BUFFER_SIZE - raw->count < count) { - /* there might be a request pending */ - raw3215_mk_write_req(raw); - raw3215_try_io(raw); - if (wait_cons_dev(raw->irq) != 0) { - /* that shouldn't happen */ - raw->count = 0; - raw->written = 0; - } - } + raw3215_make_room(raw, count); /* copy string to output buffer and convert it to EBCDIC */ if (from_user) { @@ -599,6 +626,7 @@ raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); raw->count += c; + raw->line_pos += c; str += c; count -= c; ret += c; @@ -615,6 +643,7 @@ raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); raw->count += c; + raw->line_pos += c; str += c; count -= c; ret += c; @@ -622,8 +651,8 @@ } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); - /* start or queue request */ - raw3215_try_io(raw); + /* start or queue request */ + raw3215_try_io(raw); } s390irq_spin_unlock_irqrestore(raw->irq, flags); } @@ -634,29 +663,35 @@ /* * Put character routine for 3215 devices */ + static void raw3215_putchar(raw3215_info *raw, unsigned char ch) { unsigned long flags; + unsigned int length, i; s390irq_spin_lock_irqsave(raw->irq, flags); - while (RAW3215_BUFFER_SIZE - raw->count < 1) { - /* there might be a request pending */ - raw3215_mk_write_req(raw); - raw3215_try_io(raw); - if (wait_cons_dev(raw->irq) != 0) { - /* that shouldn't happen */ - raw->count = 0; - raw->written = 0; - } + if (ch == '\t') { + length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE); + raw->line_pos += length; + ch = ' '; + } else if (ch == '\n') { + length = 1; + raw->line_pos = 0; + } else { + length = 1; + raw->line_pos++; } + raw3215_make_room(raw, length); - raw->buffer[raw->head] = (char) _ascebc[(int) ch]; - raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); - raw->count++; + for (i = 0; i < length; i++) { + raw->buffer[raw->head] = (char) _ascebc[(int) ch]; + raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); + raw->count++; + } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); - /* start or queue request */ - raw3215_try_io(raw); + /* start or queue request */ + raw3215_try_io(raw); } s390irq_spin_unlock_irqrestore(raw->irq, flags); } @@ -690,6 +725,7 @@ if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT, "3215 terminal driver", &raw->devstat) != 0) return -1; + raw->line_pos = 0; raw->flags |= RAW3215_ACTIVE; s390irq_spin_lock_irqsave(raw->irq, flags); set_cons_dev(raw->irq); @@ -720,6 +756,7 @@ s390irq_spin_unlock_irqrestore(raw->irq, flags); schedule(); s390irq_spin_lock_irqsave(raw->irq, flags); + remove_wait_queue(&raw->empty_wait, &wait); current->state = TASK_RUNNING; raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); } @@ -739,12 +776,12 @@ while (count <= number && irq != -ENODEV) { if (get_dev_info(irq, &dinfo) == -ENODEV) break; - if (dinfo.devno == raw3215_condevice || + if (dinfo.devno == raw3215_condevice || dinfo.sid_data.cu_type == 0x3215) { - count++; + count++; if (count > number) - return irq; -} + return irq; + } irq = get_irq_next(irq); } return -1; /* console not found */ @@ -762,7 +799,8 @@ if (!MACHINE_IS_VM && !MACHINE_IS_P390) return 0; raw = raw3215[0]; /* 3215 console is the first one */ - if (raw->irq == -1) /* now console device found in con3215_init */ + if (raw == NULL || raw->irq == -1) + /* console device not found in con3215_init */ return -1; return raw3215_startup(raw); } @@ -774,11 +812,24 @@ con3215_write(struct console *co, const char *str, unsigned int count) { raw3215_info *raw; + int i; if (count <= 0) return; - raw = raw3215[0]; /* console 3215 is the first one */ - raw3215_write(raw, str, 0, count); + raw = raw3215[0]; /* console 3215 is the first one */ + while (count > 0) { + for (i = 0; i < count; i++) + if (str[i] == '\t' || str[i] == '\n') + break; + raw3215_write(raw, str, 0, i); + count -= i; + str += i; + if (count > 0) { + raw3215_putchar(raw, *str); + count--; + str++; + } + } } kdev_t con3215_device(struct console *c) @@ -797,17 +848,7 @@ raw = raw3215[0]; /* console 3215 is the first one */ s390irq_spin_lock_irqsave(raw->irq, flags); - while (raw->count > 0) { - /* there might be a request pending */ - raw->flags |= RAW3215_FLUSHING; - raw3215_try_io(raw); - if (wait_cons_dev(raw->irq) != 0) { - /* that shouldn't happen */ - raw->count = 0; - raw->written = 0; - } - raw->flags &= ~RAW3215_FLUSHING; - } + raw3215_make_room(raw, RAW3215_BUFFER_SIZE); s390irq_spin_unlock_irqrestore(raw->irq, flags); } @@ -914,7 +955,12 @@ raw3215_info *raw; raw = (raw3215_info *) tty->driver_data; - return RAW3215_BUFFER_SIZE - raw->count; + + /* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */ + if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0) + return RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE; + else + return 0; } /* @@ -924,7 +970,7 @@ const unsigned char *buf, int count) { raw3215_info *raw; - int ret; + int ret = 0; if (!tty) return 0; @@ -1062,8 +1108,8 @@ if (!MACHINE_IS_VM && !MACHINE_IS_P390) return kmem_start; if (MACHINE_IS_VM) { - cpcmd("TERM CONMODE 3215", NULL, 0); - cpcmd("TERM AUTOCR OFF", NULL, 0); + cpcmd("TERM CONMODE 3215", NULL, 0); + cpcmd("TERM AUTOCR OFF", NULL, 0); } kmem_start = (kmem_start + 7) & -8L; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/char/hwc.h linux/drivers/s390/char/hwc.h --- v2.2.17/drivers/s390/char/hwc.h Fri Apr 21 12:46:24 2000 +++ linux/drivers/s390/char/hwc.h Wed Nov 8 23:05:32 2000 @@ -1,13 +1,13 @@ /* * drivers/s390/char/hwc.h - * + * * * S390 version * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Peschke * - * - * + * + * */ #ifndef __HWC_H__ @@ -109,29 +109,29 @@ go_t; -typedef struct { - go_t go; +typedef struct { + go_t go; } __attribute__ ((packed)) mdb_body_t; typedef struct { _MDB_HEADER - mdb_body_t mdb_body; + mdb_body_t mdb_body; } __attribute__ ((packed)) mdb_t; typedef struct { _EBUF_HEADER - mdb_t mdb; + mdb_t mdb; } __attribute__ ((packed)) msgbuf_t; typedef struct { _HWCB_HEADER - msgbuf_t msgbuf; + msgbuf_t msgbuf; } __attribute__ ((packed)) write_hwcb_t; @@ -144,27 +144,27 @@ static write_hwcb_t write_hwcb_template = { - sizeof(write_hwcb_t), - 0x00, + sizeof (write_hwcb_t), + 0x00, { 0x00, - 0x00, - 0x00 + 0x00, + 0x00 }, - 0x0000, - { - sizeof(msgbuf_t), - ET_Msg, - 0x00, - 0x0000, - { - sizeof(mdb_t), + 0x0000, + { + sizeof (msgbuf_t), + ET_Msg, + 0x00, + 0x0000, + { + sizeof (mdb_t), 0x0001, 0xD4C4C240, 0x00000001, - { - { - sizeof(go_t), + { + { + sizeof (go_t), 0x0001 } @@ -175,38 +175,38 @@ static mto_t mto_template = { - sizeof(mto_t), + sizeof (mto_t), 0x0004, - LTF_EndText, - 0x00 + LTF_EndText, + 0x00 }; typedef u32 _hwcb_mask_t; typedef struct { _HWCB_HEADER - u16 _reserved; - u16 mask_length; - _hwcb_mask_t cp_receive_mask; - _hwcb_mask_t cp_send_mask; - _hwcb_mask_t hwc_receive_mask; - _hwcb_mask_t hwc_send_mask; + u16 _reserved; + u16 mask_length; + _hwcb_mask_t cp_receive_mask; + _hwcb_mask_t cp_send_mask; + _hwcb_mask_t hwc_receive_mask; + _hwcb_mask_t hwc_send_mask; } __attribute__ ((packed)) init_hwcb_t; static init_hwcb_t init_hwcb_template = { - sizeof(init_hwcb_t), + sizeof (init_hwcb_t), 0x00, { 0x00, - 0x00, - 0x00 + 0x00, + 0x00 }, - 0x0000, - 0x0000, - sizeof(_hwcb_mask_t), + 0x0000, + 0x0000, + sizeof (_hwcb_mask_t), ET_OpCmd_Mask | ET_PMsgCmd_Mask, ET_Msg_Mask }; @@ -238,12 +238,12 @@ static read_hwcb_t read_hwcb_template = { PAGE_SIZE, - 0x00, + 0x00, { - 0x00, - 0x00, - 0x80 + 0x00, + 0x00, + 0x80 } }; -#endif /* __HWC_H__ */ +#endif /* __HWC_H__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/char/hwc_con.c linux/drivers/s390/char/hwc_con.c --- v2.2.17/drivers/s390/char/hwc_con.c Sun Jun 11 21:44:15 2000 +++ linux/drivers/s390/char/hwc_con.c Wed Nov 8 23:05:32 2000 @@ -18,16 +18,16 @@ #include "hwc_rw.h" -extern void hwc_tty_init(void); +extern void hwc_tty_init (void); #ifdef CONFIG_HWC_CONSOLE -#define hwc_console_major 4 +#define hwc_console_major 4 #define hwc_console_minor 0 -#define hwc_console_name "console" +#define hwc_console_name "console" -void hwc_console_write(struct console *, const char *, unsigned int); -kdev_t hwc_console_device(struct console *); +void hwc_console_write (struct console *, const char *, unsigned int); +kdev_t hwc_console_device (struct console *); void hwc_console_unblank (void); #define HWC_CON_PRINT_HEADER "hwc console driver: " @@ -39,36 +39,36 @@ hwc_console_write, NULL, hwc_console_device, - NULL, + NULL, hwc_console_unblank, - NULL, + NULL, CON_PRINTBUFFER, 0, 0, NULL }; - + void hwc_console_write ( - struct console *console, - const char *message, - unsigned int count) + struct console *console, + const char *message, + unsigned int count) { if (console->device (console) != hwc_console.device (&hwc_console)) { - hwc_printk(KERN_WARNING HWC_CON_PRINT_HEADER - "hwc_console_write() called with wrong " - "device number"); + hwc_printk (KERN_WARNING HWC_CON_PRINT_HEADER + "hwc_console_write() called with wrong " + "device number"); return; } - hwc_write(0, message, count); + hwc_write (0, message, count); } kdev_t hwc_console_device (struct console * c) { - return MKDEV(hwc_console_major, hwc_console_minor); + return MKDEV (hwc_console_major, hwc_console_minor); } void @@ -77,26 +77,26 @@ hwc_unblank (); } -#endif +#endif -__initfunc(unsigned long hwc_console_init(unsigned long kmem_start)) +__initfunc (unsigned long hwc_console_init (unsigned long kmem_start)) { #ifdef CONFIG_3215 - if (MACHINE_IS_VM) - return kmem_start; + if (MACHINE_IS_VM) + return kmem_start; #endif if (MACHINE_IS_P390) return kmem_start; - if (hwc_init(&kmem_start) == 0) { + if (hwc_init (&kmem_start) == 0) { hwc_tty_init (); #ifdef CONFIG_HWC_CONSOLE - register_console(&hwc_console); -#endif + register_console (&hwc_console); +#endif } else panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !"); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c --- v2.2.17/drivers/s390/char/hwc_rw.c Sun Jun 11 21:44:15 2000 +++ linux/drivers/s390/char/hwc_rw.c Wed Nov 8 23:05:32 2000 @@ -6,11 +6,11 @@ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Peschke * + * * - * - * - * - * + * + * + * */ #include @@ -50,6 +50,8 @@ #undef BUFFER_STRESS_TEST +#define MEASURE_HWC_OUTPUT + typedef struct { unsigned char *next; unsigned short int mto_char_sum; @@ -115,7 +117,7 @@ static unsigned char _obuf[MAX_HWCB_ROOM]; static unsigned char - _page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); + _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE))); typedef u32 kmem_pages_t; @@ -179,39 +181,42 @@ { { }, - { - 8, - 0, - 80, - CODE_ASCII, - 1, - 50, - MAX_KMEM_PAGES, - - 0, - - 0x6c - + { + 8, + 0, + 80, + CODE_ASCII, + 1, + 50, + MAX_KMEM_PAGES, + + 0, + + 0x6c, + + 0, + 0, + 0 }, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - _obuf, - 0, - 0, - 0, - _page, - 0, - NULL, - 0, - 0, - 0, - 0, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + _obuf, + 0, + 0, + 0, + _page, + 0, + NULL, + 0, + 0, + 0, + 0, 0, NULL @@ -225,9 +230,9 @@ #define IMMEDIATE_WRITE 1 static signed int do_hwc_write (int from_user, unsigned char *, - unsigned int, - unsigned char, - unsigned char); + unsigned int, + unsigned char, + unsigned char); static asmlinkage int internal_print (char write_time, char *fmt,...) @@ -236,10 +241,10 @@ int i; unsigned char buf[512]; - va_start(args, fmt); - i = vsprintf(buf, fmt, args); - va_end(args); - return do_hwc_write(0, buf, i, CODE_ASCII, write_time); + va_start (args, fmt); + i = vsprintf (buf, fmt, args); + va_end (args); + return do_hwc_write (0, buf, i, CODE_ASCII, write_time); } int @@ -250,18 +255,18 @@ unsigned char buf[512]; unsigned long flags; int retval; - - spin_lock_irqsave(&hwc_data.lock, flags); - i = vsprintf(buf, fmt, args); - va_end(args); - retval = do_hwc_write(0, buf, i, CODE_ASCII, IMMEDIATE_WRITE); - - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_lock_irqsave (&hwc_data.lock, flags); + + i = vsprintf (buf, fmt, args); + va_end (args); + retval = do_hwc_write (0, buf, i, CODE_ASCII, IMMEDIATE_WRITE); + + spin_unlock_irqrestore (&hwc_data.lock, flags); return retval; } - + #ifdef DUMP_HWCB_INPUT static void @@ -275,46 +280,46 @@ old_final_nl = hwc_data.ioctls.final_nl; hwc_data.ioctls.final_nl = 1; - - internal_print(DELAYED_WRITE, "\n%8x ", area); + + internal_print (DELAYED_WRITE, "\n%8x ", area); for (index = 0; index < count; index++) { - + if (area[index] <= 0xF) - internal_print(DELAYED_WRITE, "0%x", area[index]); + internal_print (DELAYED_WRITE, "0%x", area[index]); else internal_print (DELAYED_WRITE, "%x", area[index]); - + if ((index & 0xF) == 0xF) - internal_print(DELAYED_WRITE, "\n%8x ", - &area[index + 1]); - else if ((index & 3) == 3) - internal_print(DELAYED_WRITE, " "); + internal_print (DELAYED_WRITE, "\n%8x ", + &area[index + 1]); + else if ((index & 3) == 3) + internal_print (DELAYED_WRITE, " "); } - - internal_print(IMMEDIATE_WRITE, "\n"); + + internal_print (IMMEDIATE_WRITE, "\n"); hwc_data.ioctls.final_nl = old_final_nl; } -#endif +#endif static inline u32 service_call ( - u32 hwc_command_word, - unsigned char hwcb[]) + u32 hwc_command_word, + unsigned char hwcb[]) { unsigned int condition_code = 1; - __asm__ __volatile__("L 1, 0(0,%0) \n\t" - "LRA 2, 0(0,%1) \n\t" - ".long 0xB2200012 \n\t" - : - :"a"(&hwc_command_word), "a"(hwcb) - :"1", "2", "memory"); - - __asm__ __volatile__("IPM %0 \n\t" - "SRL %0, 28 \n\t" - :"=r"(condition_code)); + __asm__ __volatile__ ("L 1, 0(0,%0) \n\t" + "LRA 2, 0(0,%1) \n\t" + ".long 0xB2200012 \n\t" + : + :"a" (&hwc_command_word), "a" (hwcb) + :"1", "2", "memory"); + + __asm__ __volatile__ ("IPM %0 \n\t" + "SRL %0, 28 \n\t" + :"=r" (condition_code)); return condition_code; } @@ -324,8 +329,8 @@ { u32 param; - __asm__ __volatile__("L %0,128(0,0)\n\t" - :"=r"(param)); + __asm__ __volatile__ ("L %0,128(0,0)\n\t" + :"=r" (param)); return ((unsigned char *) param); } @@ -337,14 +342,14 @@ if (!BUF_HWCB) return -ENOMEM; - + BUF_HWCB_MTO = 0; BUF_HWCB_CHAR = 0; hwcb = (write_hwcb_t *) BUF_HWCB; - memcpy(hwcb, &write_hwcb_template, sizeof(write_hwcb_t)); - + memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t)); + if (!hwc_data.write_nonprio && hwc_data.write_prio) hwcb->msgbuf.type = ET_PMsgCmd; @@ -363,27 +368,27 @@ if (!OUT_HWCB) return -ENOMEM; - - if ((unsigned long)OUT_HWCB & 0xFFF) { + + if ((unsigned long) OUT_HWCB & 0xFFF) { bad_addr = OUT_HWCB; #ifdef DUMP_HWC_WRITE_LIST_ERROR - __asm__("LHI 1,0xe30\n\t" - "LRA 2,0(0,%0) \n\t" - "J .+0 \n\t" - : - :"a"(bad_addr) - :"1", "2"); -#endif - + __asm__ ("LHI 1,0xe30\n\t" + "LRA 2,0(0,%0) \n\t" + "J .+0 \n\t" + : + : "a" (bad_addr) + : "1", "2"); +#endif + hwc_data.kmem_pages = 0; - if ((unsigned long)BUF_HWCB & 0xFFF) { + if ((unsigned long) BUF_HWCB & 0xFFF) { lost_hwcb = hwc_data.hwcb_count; lost_msg = ALL_HWCB_MTO; lost_char = ALL_HWCB_CHAR; - + OUT_HWCB = NULL; BUF_HWCB = NULL; ALL_HWCB_MTO = 0; @@ -399,27 +404,27 @@ ALL_HWCB_CHAR = BUF_HWCB_CHAR; hwc_data.hwcb_count = 1; page = (unsigned long) BUF_HWCB; - + if (page >= hwc_data.kmem_start && - page < hwc_data.kmem_end) { - + page <= hwc_data.kmem_end) { + page_nr = (int) - ((page - hwc_data.kmem_start) >> 12); - set_bit(page_nr, &hwc_data.kmem_pages); + ((page - hwc_data.kmem_start) >> 12); + set_bit (page_nr, &hwc_data.kmem_pages); } } - - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER "found invalid HWCB at address 0x%x. List corrupted. " - "Lost %i HWCBs with %i characters within up to %i " - "messages. Saved %i HWCB with last %i characters i" - "within up to %i messages.\n", - (unsigned int)bad_addr, - lost_hwcb, lost_char, lost_msg, - hwc_data.hwcb_count, - ALL_HWCB_CHAR, ALL_HWCB_MTO); + "Lost %i HWCBs with %i characters within up to %i " + "messages. Saved %i HWCB with last %i characters i" + "within up to %i messages.\n", + (unsigned int) bad_addr, + lost_hwcb, lost_char, lost_msg, + hwc_data.hwcb_count, + ALL_HWCB_CHAR, ALL_HWCB_MTO); } return 0; } @@ -430,18 +435,18 @@ int retval; if (hwc_data.hwcb_count < 2) -#ifdef DUMP_HWC_WRITE_LIST_ERROR - __asm__("LHI 1,0xe31\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0 \n\t" - : - :"a"(BUF_HWCB), "a"(OUT_HWCB) - :"1", "2", "3"); +#ifdef DUMP_HWC_WRITE_LIST_ERROR + __asm__ ("LHI 1,0xe31\n\t" + "LRA 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0 \n\t" + : + : "a" (BUF_HWCB), "a" (OUT_HWCB) + : "1", "2", "3"); #else return -EPERM; -#endif - +#endif + if (hwc_data.current_hwcb == OUT_HWCB) { if (hwc_data.hwcb_count > 2) { @@ -471,34 +476,34 @@ ALL_HWCB_MTO -= BUF_HWCB_MTO; ALL_HWCB_CHAR -= BUF_HWCB_CHAR; - retval = prepare_write_hwcb(); + retval = prepare_write_hwcb (); if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb) - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "reached my own limit of " - "allowed buffer space for output (%i HWCBs = %li " - "bytes), skipped content of oldest HWCB %i time(s) " - "(%i lines = %i characters)\n", - hwc_data.ioctls.max_hwcb, - hwc_data.ioctls.max_hwcb * PAGE_SIZE, - BUF_HWCB_TIMES_LOST, - BUF_HWCB_MTO_LOST, - BUF_HWCB_CHAR_LOST); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "reached my own limit of " + "allowed buffer space for output (%i HWCBs = %li " + "bytes), skipped content of oldest HWCB %i time(s) " + "(%i lines = %i characters)\n", + hwc_data.ioctls.max_hwcb, + hwc_data.ioctls.max_hwcb * PAGE_SIZE, + BUF_HWCB_TIMES_LOST, + BUF_HWCB_MTO_LOST, + BUF_HWCB_CHAR_LOST); else internal_print ( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "page allocation failed, " - "could not expand buffer for output (currently in " - "use: %i HWCBs = %li bytes), skipped content of " + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "page allocation failed, " + "could not expand buffer for output (currently in " + "use: %i HWCBs = %li bytes), skipped content of " "oldest HWCB %i time(s) (%i lines = %i characters)\n", - hwc_data.hwcb_count, - hwc_data.hwcb_count * PAGE_SIZE, - BUF_HWCB_TIMES_LOST, - BUF_HWCB_MTO_LOST, - BUF_HWCB_CHAR_LOST); + hwc_data.hwcb_count, + hwc_data.hwcb_count * PAGE_SIZE, + BUF_HWCB_TIMES_LOST, + BUF_HWCB_MTO_LOST, + BUF_HWCB_CHAR_LOST); return retval; } @@ -508,16 +513,16 @@ { unsigned char *page; int page_nr; - + if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb) return -ENOMEM; - - page_nr = find_first_zero_bit(&hwc_data.kmem_pages, MAX_KMEM_PAGES); + + page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES); if (page_nr < hwc_data.ioctls.kmem_hwcb) { page = (unsigned char *) - (hwc_data.kmem_start + (page_nr << 12)); - set_bit(page_nr, &hwc_data.kmem_pages); + (hwc_data.kmem_start + (page_nr << 12)); + set_bit (page_nr, &hwc_data.kmem_pages); } else page = (unsigned char *) __get_free_page (GFP_ATOMIC); @@ -526,7 +531,7 @@ if (!OUT_HWCB) OUT_HWCB = page; - else + else BUF_HWCB_NEXT = page; BUF_HWCB = page; @@ -535,7 +540,7 @@ hwc_data.hwcb_count++; - prepare_write_hwcb(); + prepare_write_hwcb (); BUF_HWCB_TIMES_LOST = 0; BUF_HWCB_MTO_LOST = 0; @@ -543,13 +548,13 @@ #ifdef BUFFER_STRESS_TEST - internal_print( - DELAYED_WRITE, - "*** " HWC_RW_PRINT_HEADER - "page #%i at 0x%x for buffering allocated. ***\n", - hwc_data.hwcb_count, page); + internal_print ( + DELAYED_WRITE, + "*** " HWC_RW_PRINT_HEADER + "page #%i at 0x%x for buffering allocated. ***\n", + hwc_data.hwcb_count, page); -#endif +#endif return 0; } @@ -559,54 +564,53 @@ { unsigned long page; int page_nr; - - if (!hwc_data.hwcb_count) - return -ENODATA; - - if (hwc_data.hwcb_count == 1) { - - prepare_write_hwcb(); - - ALL_HWCB_CHAR = 0; - ALL_HWCB_MTO = 0; - BUF_HWCB_TIMES_LOST = 0; - BUF_HWCB_MTO_LOST = 0; - BUF_HWCB_CHAR_LOST = 0; + + if (!hwc_data.hwcb_count) + return -ENODATA; + + if (hwc_data.hwcb_count == 1) { + + prepare_write_hwcb (); + + ALL_HWCB_CHAR = 0; + ALL_HWCB_MTO = 0; + BUF_HWCB_TIMES_LOST = 0; + BUF_HWCB_MTO_LOST = 0; + BUF_HWCB_CHAR_LOST = 0; } else { - page = (unsigned long) OUT_HWCB; - - ALL_HWCB_MTO -= OUT_HWCB_MTO; - ALL_HWCB_CHAR -= OUT_HWCB_CHAR; - hwc_data.hwcb_count--; - - OUT_HWCB = OUT_HWCB_NEXT; - - if (page >= hwc_data.kmem_start && - page < hwc_data.kmem_end) { + page = (unsigned long) OUT_HWCB; + + ALL_HWCB_MTO -= OUT_HWCB_MTO; + ALL_HWCB_CHAR -= OUT_HWCB_CHAR; + hwc_data.hwcb_count--; + + OUT_HWCB = OUT_HWCB_NEXT; -/* memset((void *) page, 0, PAGE_SIZE); */ + if (page >= hwc_data.kmem_start && + page <= hwc_data.kmem_end) { + /*memset((void *) page, 0, PAGE_SIZE); */ - page_nr = (int) ((page - hwc_data.kmem_start) >> 12); - clear_bit(page_nr, &hwc_data.kmem_pages); + page_nr = (int) ((page - hwc_data.kmem_start) >> 12); + clear_bit (page_nr, &hwc_data.kmem_pages); } else - free_page(page); + free_page (page); #ifdef BUFFER_STRESS_TEST - internal_print( - DELAYED_WRITE, - "*** " HWC_RW_PRINT_HEADER - "page at 0x%x released, %i pages still in use ***\n", - page, hwc_data.hwcb_count); + internal_print ( + DELAYED_WRITE, + "*** " HWC_RW_PRINT_HEADER + "page at 0x%x released, %i pages still in use ***\n", + page, hwc_data.hwcb_count); -#endif - } +#endif + } return 0; } static int add_mto ( - unsigned char *message, - unsigned short int count) + unsigned char *message, + unsigned short int count) { unsigned short int mto_size; write_hwcb_t *hwcb; @@ -619,32 +623,38 @@ if (BUF_HWCB == hwc_data.current_hwcb) return -ENOMEM; - mto_size = sizeof(mto_t) + count; + mto_size = sizeof (mto_t) + count; hwcb = (write_hwcb_t *) BUF_HWCB; - + if ((MAX_HWCB_ROOM - hwcb->length) < mto_size) return -ENOMEM; mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length); - memcpy(mto, &mto_template, sizeof(mto_t)); + memcpy (mto, &mto_template, sizeof (mto_t)); - dest = (void *) (((unsigned long) mto) + sizeof(mto_t)); + dest = (void *) (((unsigned long) mto) + sizeof (mto_t)); - memcpy(dest, message, count); + memcpy (dest, message, count); mto->length += count; - - hwcb->length += mto_size; - hwcb->msgbuf.length += mto_size; - hwcb->msgbuf.mdb.length += mto_size; + + hwcb->length += mto_size; + hwcb->msgbuf.length += mto_size; + hwcb->msgbuf.mdb.length += mto_size; BUF_HWCB_MTO++; ALL_HWCB_MTO++; BUF_HWCB_CHAR += count; ALL_HWCB_CHAR += count; +#ifdef MEASURE_HWC_OUTPUT + + hwc_data.ioctls.measured_lines++; + hwc_data.ioctls.measured_chars += count; +#endif + return count; } @@ -659,38 +669,41 @@ if (hwc_data.current_servc) return -EBUSY; - - retval = sane_write_hwcb(); + + retval = sane_write_hwcb (); if (retval < 0) return retval; if (!OUT_HWCB_MTO) return -ENODATA; - condition_code = service_call(HWC_CMDW_WRITEDATA, OUT_HWCB); + condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB); -#ifdef DUMP_HWC_WRITE_ERROR +#ifdef DUMP_HWC_WRITE_ERROR if (condition_code != HWC_COMMAND_INITIATED) - __asm__("LHI 1,0xe20\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0 \n\t" - : - :"a"(&condition_code), "a"(OUT_HWCB) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe20\n\t" + "L 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0 \n\t" + : + : "a" (&condition_code), "a" (OUT_HWCB) + : "1", "2", "3"); +#endif switch (condition_code) { - case HWC_COMMAND_INITIATED : - hwc_data.current_servc = HWC_CMDW_WRITEDATA; - hwc_data.current_hwcb = OUT_HWCB; - retval = condition_code; - break; - case HWC_BUSY : - retval = -EBUSY; - break; - default : - retval = -EIO; + case HWC_COMMAND_INITIATED: + hwc_data.current_servc = HWC_CMDW_WRITEDATA; + hwc_data.current_hwcb = OUT_HWCB; + retval = condition_code; +#ifdef MEASURE_HWC_OUTPUT + hwc_data.ioctls.measured_wcalls++; +#endif + break; + case HWC_BUSY: + retval = -EBUSY; + break; + default: + retval = -EIO; } return retval; @@ -700,9 +713,9 @@ flush_hwcbs (void) { while (hwc_data.hwcb_count > 1) - release_write_hwcb(); + release_write_hwcb (); - release_write_hwcb(); + release_write_hwcb (); hwc_data.flags &= ~HWC_FLUSH; } @@ -716,7 +729,7 @@ #ifdef DUMP_HWC_WRITE_ERROR unsigned char *param; - param = ext_int_param(); + param = ext_int_param (); if (param != hwc_data.current_hwcb) { internal_print ( DELAYED_WRITE, @@ -734,42 +747,42 @@ #ifdef DUMP_HWC_WRITE_LIST_ERROR if (((unsigned char *) hwcb) != hwc_data.current_hwcb) { - __asm__("LHI 1,0xe22\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" - "J .+0 \n\t" - : - :"a"(OUT_HWCB), - "a"(hwc_data.current_hwcb), - "a"(BUF_HWCB), + __asm__ ("LHI 1,0xe22\n\t" + "LRA 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "LRA 4,0(0,%2)\n\t" + "LRA 5,0(0,%3)\n\t" + "J .+0 \n\t" + : + : "a" (OUT_HWCB), + "a" (hwc_data.current_hwcb), + "a" (BUF_HWCB), "a" (hwcb) - :"1", "2", "3", "4", "5"); + : "1", "2", "3", "4", "5"); } #endif #ifdef DUMP_HWC_WRITE_ERROR if (hwcb->response_code != 0x0020) { - __asm__("LHI 1,0xe21\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LH 5,0(0,%3)\n\t" - "SRL 5,8(0)\n\t" - "J .+0 \n\t" - : - :"a"(OUT_HWCB), "a"(hwc_data.current_hwcb), - "a"(BUF_HWCB), - "a"(&(hwc_data.hwcb_count)) - :"1", "2", "3", "4", "5"); + __asm__ ("LHI 1,0xe21\n\t" + "LRA 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "LRA 4,0(0,%2)\n\t" + "LH 5,0(0,%3)\n\t" + "SRL 5,8(0)\n\t" + "J .+0 \n\t" + : + : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb), + "a" (BUF_HWCB), + "a" (&(hwc_data.hwcb_count)) + : "1", "2", "3", "4", "5"); } -#endif +#endif if (hwcb->response_code == 0x0020) { retval = OUT_HWCB_CHAR; - release_write_hwcb(); + release_write_hwcb (); } else { internal_print ( DELAYED_WRITE, @@ -787,53 +800,53 @@ hwc_data.current_hwcb = NULL; if (hwc_data.flags & HWC_FLUSH) - flush_hwcbs(); + flush_hwcbs (); return retval; } static void do_put_line ( - unsigned char * message, - unsigned short count) + unsigned char *message, + unsigned short count) { - if (add_mto(message, count) != count) { + if (add_mto (message, count) != count) { + + if (allocate_write_hwcb () < 0) + reuse_write_hwcb (); - if (allocate_write_hwcb() < 0) - reuse_write_hwcb(); - -#ifdef DUMP_HWC_WRITE_LIST_ERROR - if (add_mto(message, count) != count) - __asm__("LHI 1,0xe32\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" - "J .+0 \n\t" - : - :"a"(message), "a"(&hwc_data.kmem_pages), - "a"(BUF_HWCB), "a"(OUT_HWCB) - :"1", "2", "3", "4", "5"); +#ifdef DUMP_HWC_WRITE_LIST_ERROR + if (add_mto (message, count) != count) + __asm__ ("LHI 1,0xe32\n\t" + "LRA 2,0(0,%0)\n\t" + "L 3,0(0,%1)\n\t" + "LRA 4,0(0,%2)\n\t" + "LRA 5,0(0,%3)\n\t" + "J .+0 \n\t" + : + : "a" (message), "a" (&hwc_data.kmem_pages), + "a" (BUF_HWCB), "a" (OUT_HWCB) + : "1", "2", "3", "4", "5"); #else - add_mto(message, count); -#endif + add_mto (message, count); +#endif } } static void put_line ( - unsigned char * message, - unsigned short count) + unsigned char *message, + unsigned short count) { - + if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) { - del_timer(&hwc_data.write_timer); + del_timer (&hwc_data.write_timer); hwc_data.flags &= ~HWC_TIMER_RUNS; } hwc_data.obuf_start += count; - do_put_line(message, count); + do_put_line (message, count); hwc_data.obuf_start -= count; } @@ -844,39 +857,39 @@ write_hwcb_t *hwcb; if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb)) - allocate_write_hwcb(); + allocate_write_hwcb (); hwcb = (write_hwcb_t *) BUF_HWCB; hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm; -} +} static void hwc_write_timeout (unsigned long data) { unsigned long flags; - - spin_lock_irqsave(&hwc_data.lock, flags); - + + spin_lock_irqsave (&hwc_data.lock, flags); + hwc_data.obuf_start = hwc_data.obuf_count; if (hwc_data.obuf_count) - put_line(hwc_data.obuf, hwc_data.obuf_count); + put_line (hwc_data.obuf, hwc_data.obuf_count); hwc_data.obuf_start = 0; hwc_data.obuf_cursor = 0; hwc_data.obuf_count = 0; - - write_event_data_1(); - spin_unlock_irqrestore(&hwc_data.lock, flags); + write_event_data_1 (); + + spin_unlock_irqrestore (&hwc_data.lock, flags); } static int do_hwc_write ( - int from_user, + int from_user, unsigned char *msg, - unsigned int count, - unsigned char code, - unsigned char write_time) + unsigned int count, + unsigned char code, + unsigned char write_time) { unsigned int i_msg = 0; unsigned short int spaces = 0; @@ -889,18 +902,18 @@ if (hwc_data.obuf_start) { obuf_cursor = 0; obuf_count = 0; - obuf_columns = MIN(hwc_data.ioctls.columns, - MAX_MESSAGE_SIZE - hwc_data.obuf_start); + obuf_columns = MIN (hwc_data.ioctls.columns, + MAX_MESSAGE_SIZE - hwc_data.obuf_start); } else { obuf_cursor = hwc_data.obuf_cursor; obuf_count = hwc_data.obuf_count; obuf_columns = hwc_data.ioctls.columns; } - + for (i_msg = 0; i_msg < count; i_msg++) { if (from_user) - get_user(orig_ch, msg + i_msg); + get_user (orig_ch, msg + i_msg); else orig_ch = msg[i_msg]; if (code == CODE_EBCDIC) @@ -909,42 +922,42 @@ ch = orig_ch; processed_characters++; - + if ((obuf_cursor == obuf_columns) && (ch != '\n') && (ch != '\t')) { - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_columns); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_columns); obuf_cursor = 0; obuf_count = 0; } switch (ch) { - case '\n' : + case '\n': - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_cursor = 0; obuf_count = 0; break; - case '\a' : + case '\a': hwc_data.obuf_start += obuf_count; - set_alarm(); + set_alarm (); hwc_data.obuf_start -= obuf_count; break; - case '\t' : + case '\t': do { if (obuf_cursor < obuf_columns) { hwc_data.obuf[hwc_data.obuf_start + - obuf_cursor] - = 0x20; + obuf_cursor] + = 0x20; obuf_cursor++; } else break; @@ -952,47 +965,47 @@ break; - case '\f' : - case '\v' : + case '\f': + case '\v': spaces = obuf_cursor; - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_count = obuf_cursor; while (spaces) { hwc_data.obuf[hwc_data.obuf_start + - obuf_cursor - spaces] - = 0x20; + obuf_cursor - spaces] + = 0x20; spaces--; } break; - case '\b' : + case '\b': if (obuf_cursor) obuf_cursor--; break; - case '\r' : + case '\r': obuf_cursor = 0; break; - case 0x00 : + case 0x00: - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_cursor = 0; obuf_count = 0; goto out; - default: + default: - if (isprint(ch)) + if (isprint (ch)) hwc_data.obuf[hwc_data.obuf_start + - obuf_cursor++] - = (code == CODE_ASCII) ? + obuf_cursor++] + = (code == CODE_ASCII) ? (MACHINE_IS_VM ? _ascebc[orig_ch] : _ascebc_500[orig_ch]) : @@ -1006,9 +1019,9 @@ if (hwc_data.obuf_start || (hwc_data.ioctls.final_nl == 0)) { - - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_cursor = 0; obuf_count = 0; } else { @@ -1018,34 +1031,34 @@ if (hwc_data.flags & HWC_TIMER_RUNS) { hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl*HZ/10; + jiffies + + hwc_data.ioctls.final_nl * HZ / 10; } else { - init_timer(&hwc_data.write_timer); + init_timer (&hwc_data.write_timer); hwc_data.write_timer.function = - hwc_write_timeout; + hwc_write_timeout; hwc_data.write_timer.data = - (unsigned long)NULL; + (unsigned long) NULL; hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl*HZ/10; - add_timer(&hwc_data.write_timer); + jiffies + + hwc_data.ioctls.final_nl * HZ / 10; + add_timer (&hwc_data.write_timer); hwc_data.flags |= HWC_TIMER_RUNS; } } else; - } + } } else; -out : + out: if (!hwc_data.obuf_start) { hwc_data.obuf_cursor = obuf_cursor; hwc_data.obuf_count = obuf_count; } if (write_time == IMMEDIATE_WRITE) - write_event_data_1(); + write_event_data_1 (); return processed_characters; } @@ -1055,14 +1068,14 @@ { unsigned long flags; int retval; - - spin_lock_irqsave(&hwc_data.lock, flags); + + spin_lock_irqsave (&hwc_data.lock, flags); retval = do_hwc_write (from_user, (unsigned char *) msg, count, hwc_data.ioctls.code, - IMMEDIATE_WRITE); + IMMEDIATE_WRITE); - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_unlock_irqrestore (&hwc_data.lock, flags); return retval; } @@ -1073,15 +1086,15 @@ unsigned short int number = 0; unsigned long flags; - spin_lock_irqsave(&hwc_data.lock, flags); + spin_lock_irqsave (&hwc_data.lock, flags); if (flag & IN_HWCB) number += ALL_HWCB_CHAR; - + if (flag & IN_WRITE_BUF) number += hwc_data.obuf_cursor; - - spin_unlock_irqrestore(&hwc_data.lock, flags); + + spin_unlock_irqrestore (&hwc_data.lock, flags); return number; } @@ -1092,7 +1105,7 @@ int i; int nr = 0; - for (i = 0; i < (sizeof(arg) << 3); i++) { + for (i = 0; i < (sizeof (arg) << 3); i++) { if (arg & 1) nr++; arg >>= 1; @@ -1107,24 +1120,24 @@ unsigned int number = 0; unsigned long flags; write_hwcb_t *hwcb; - - spin_lock_irqsave(&hwc_data.lock, flags); - if (flag & IN_HWCB) { + spin_lock_irqsave (&hwc_data.lock, flags); + + if (flag & IN_HWCB) { if (BUF_HWCB) { hwcb = (write_hwcb_t *) BUF_HWCB; - number += MAX_HWCB_ROOM - hwcb->length; + number += MAX_HWCB_ROOM - hwcb->length; } number += (hwc_data.ioctls.kmem_hwcb - - nr_setbits(hwc_data.kmem_pages)) * - (MAX_HWCB_ROOM - - (sizeof(write_hwcb_t) + sizeof(mto_t))); + nr_setbits (hwc_data.kmem_pages)) * + (MAX_HWCB_ROOM - + (sizeof (write_hwcb_t) + sizeof (mto_t))); } - if (flag & IN_WRITE_BUF) - number += MAX_HWCB_ROOM - hwc_data.obuf_cursor; + if (flag & IN_WRITE_BUF) + number += MAX_HWCB_ROOM - hwc_data.obuf_cursor; - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_unlock_irqrestore (&hwc_data.lock, flags); return number; } @@ -1134,19 +1147,19 @@ { unsigned long flags; - spin_lock_irqsave(&hwc_data.lock, flags); + spin_lock_irqsave (&hwc_data.lock, flags); if (flag & IN_HWCB) { if (hwc_data.current_servc != HWC_CMDW_WRITEDATA) - flush_hwcbs(); + flush_hwcbs (); else hwc_data.flags |= HWC_FLUSH; } if (flag & IN_WRITE_BUF) { - hwc_data.obuf_cursor = 0; + hwc_data.obuf_cursor = 0; hwc_data.obuf_count = 0; } - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_unlock_irqrestore (&hwc_data.lock, flags); } unsigned short int @@ -1170,7 +1183,7 @@ i_out++; - i_in++; + i_in++; } else _case = ~_case; @@ -1179,7 +1192,7 @@ if (_case) { - if (hwc_data.ioctls.tolower) + if (hwc_data.ioctls.tolower) buf[i_out] = _ebc_toupper[buf[i_in]]; else @@ -1203,43 +1216,43 @@ int retval = 0; switch (id) { - case GDS_ID_MDSMU : - name = "Multiple Domain Support Message Unit"; - break; - case GDS_ID_MDSRouteInfo : - name = "MDS Routing Information"; - break; - case GDS_ID_AgUnWrkCorr : - name = "Agent Unit of Work Correlator"; - break; - case GDS_ID_SNACondReport : - name = "SNA Condition Report"; - break; - case GDS_ID_CPMSU : - name = "CP Management Services Unit"; - break; - case GDS_ID_RoutTargInstr : - name = "Routing and Targeting Instructions"; - break; - case GDS_ID_OpReq : - name = "Operate Request"; - break; - case GDS_ID_TextCmd : - name = "Text Command"; - break; + case GDS_ID_MDSMU: + name = "Multiple Domain Support Message Unit"; + break; + case GDS_ID_MDSRouteInfo: + name = "MDS Routing Information"; + break; + case GDS_ID_AgUnWrkCorr: + name = "Agent Unit of Work Correlator"; + break; + case GDS_ID_SNACondReport: + name = "SNA Condition Report"; + break; + case GDS_ID_CPMSU: + name = "CP Management Services Unit"; + break; + case GDS_ID_RoutTargInstr: + name = "Routing and Targeting Instructions"; + break; + case GDS_ID_OpReq: + name = "Operate Request"; + break; + case GDS_ID_TextCmd: + name = "Text Command"; + break; - default : - name = "unknown GDS variable"; - retval = -EINVAL; + default: + name = "unknown GDS variable"; + retval = -EINVAL; } return retval; } -#endif +#endif inline static gds_vector_t * find_gds_vector ( - gds_vector_t *start, void *end, u16 id) + gds_vector_t * start, void *end, u16 id) { gds_vector_t *vec; gds_vector_t *retval = NULL; @@ -1247,31 +1260,31 @@ vec = start; while (((void *) vec) < end) { - if (vec->gds_id == id) { + if (vec->gds_id == id) { #ifdef DUMP_HWCB_INPUT int retval_name; unsigned char name[64]; - retval_name = gds_vector_name(id, name); - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "%s at 0x%x up to 0x%x, length: %d", - name, - (unsigned long) vec, - ((unsigned long) vec) + vec->length - 1, - vec->length); + retval_name = gds_vector_name (id, name); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "%s at 0x%x up to 0x%x, length: %d", + name, + (unsigned long) vec, + ((unsigned long) vec) + vec->length - 1, + vec->length); if (retval_name < 0) - internal_print( - IMMEDIATE_WRITE, - ", id: 0x%x\n", - vec->gds_id); + internal_print ( + IMMEDIATE_WRITE, + ", id: 0x%x\n", + vec->gds_id); else internal_print ( - IMMEDIATE_WRITE, - "\n"); -#endif + IMMEDIATE_WRITE, + "\n"); +#endif retval = vec; break; @@ -1284,7 +1297,7 @@ inline static gds_subvector_t * find_gds_subvector ( - gds_subvector_t *start, void *end, u8 key) + gds_subvector_t * start, void *end, u8 key) { gds_subvector_t *subvec; gds_subvector_t *retval = NULL; @@ -1292,12 +1305,12 @@ subvec = start; while (((void *) subvec) < end) { - if (subvec->key == key) { + if (subvec->key == key) { retval = subvec; break; } subvec = (gds_subvector_t *) - (((unsigned long) subvec) + subvec->length); + (((unsigned long) subvec) + subvec->length); } return retval; @@ -1311,17 +1324,17 @@ count = ((unsigned long) end) - ((unsigned long) start); if (hwc_data.ioctls.tolower) - EBC_TOLOWER(start, count); + EBC_TOLOWER (start, count); if (hwc_data.ioctls.delim) - count = seperate_cases(start, count); + count = seperate_cases (start, count); if (hwc_data.ioctls.echo) - do_hwc_write(0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE); + do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE); if (hwc_data.ioctls.code == CODE_ASCII) { if (MACHINE_IS_VM) - EBCASC(start, count); + EBCASC (start, count); else EBCASC_500 (start, count); } @@ -1343,15 +1356,15 @@ subvec = start; while (((void *) subvec) < end) { - subvec = find_gds_subvector(subvec, end, 0x30); + subvec = find_gds_subvector (subvec, end, 0x30); if (!subvec) break; subvec_data = (void *) - (((unsigned long) subvec) + - sizeof(gds_subvector_t)); + (((unsigned long) subvec) + + sizeof (gds_subvector_t)); subvec_end = (void *) - (((unsigned long) subvec) + subvec->length); - retval += get_input(subvec_data, subvec_end); + (((unsigned long) subvec) + subvec->length); + retval += get_input (subvec_data, subvec_end); subvec = (gds_subvector_t *) subvec_end; } @@ -1369,16 +1382,16 @@ subvec = start; while (((void *) subvec) < end) { - subvec = find_gds_subvector( - subvec, end, GDS_KEY_SelfDefTextMsg); + subvec = find_gds_subvector ( + subvec, end, GDS_KEY_SelfDefTextMsg); if (!subvec) break; subvec_data = (gds_subvector_t *) - (((unsigned long) subvec) + - sizeof(gds_subvector_t)); + (((unsigned long) subvec) + + sizeof (gds_subvector_t)); subvec_end = (void *) - (((unsigned long) subvec) + subvec->length); - retval += eval_selfdeftextmsg(subvec_data, subvec_end); + (((unsigned long) subvec) + subvec->length); + retval += eval_selfdeftextmsg (subvec_data, subvec_end); subvec = (gds_subvector_t *) subvec_end; } @@ -1396,13 +1409,13 @@ vec = start; while (((void *) vec) < end) { - vec = find_gds_vector(vec, end, GDS_ID_TextCmd); + vec = find_gds_vector (vec, end, GDS_ID_TextCmd); if (!vec) break; vec_data = (gds_subvector_t *) - (((unsigned long) vec) + sizeof(gds_vector_t)); + (((unsigned long) vec) + sizeof (gds_vector_t)); vec_end = (void *) (((unsigned long) vec) + vec->length); - retval += eval_textcmd(vec_data, vec_end); + retval += eval_textcmd (vec_data, vec_end); vec = (gds_vector_t *) vec_end; } @@ -1417,12 +1430,12 @@ void *vec_end; int retval = 0; - vec = find_gds_vector(start, end, GDS_ID_CPMSU); + vec = find_gds_vector (start, end, GDS_ID_CPMSU); if (vec) { vec_data = (gds_vector_t *) - (((unsigned long) vec) + sizeof(gds_vector_t)); + (((unsigned long) vec) + sizeof (gds_vector_t)); vec_end = (void *) (((unsigned long) vec) + vec->length); - retval = eval_cpmsu(vec_data, vec_end); + retval = eval_cpmsu (vec_data, vec_end); } return retval; } @@ -1435,12 +1448,12 @@ void *vec_end; int retval = 0; - vec = find_gds_vector(start, end, GDS_ID_MDSMU); + vec = find_gds_vector (start, end, GDS_ID_MDSMU); if (vec) { vec_data = (gds_vector_t *) - (((unsigned long) vec) + sizeof(gds_vector_t)); + (((unsigned long) vec) + sizeof (gds_vector_t)); vec_end = (void *) (((unsigned long) vec) + vec->length); - retval = eval_mdsmu(vec_data, vec_end); + retval = eval_mdsmu (vec_data, vec_end); } return retval; } @@ -1456,39 +1469,39 @@ evbuf = (evbuf_t *) start; while (((void *) evbuf) < end) { evbuf_data = (gds_vector_t *) - (((unsigned long) evbuf) + sizeof(evbuf_t)); + (((unsigned long) evbuf) + sizeof (evbuf_t)); evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length); switch (evbuf->type) { - case ET_OpCmd : - case ET_CntlProgOpCmd : - case ET_PMsgCmd : + case ET_OpCmd: + case ET_CntlProgOpCmd: + case ET_PMsgCmd: #ifdef DUMP_HWCB_INPUT - - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "event buffer " - "at 0x%x up to 0x%x, length: %d\n", - (unsigned long) evbuf, - (unsigned long) (evbuf_end - 1), - evbuf->length); - dump_storage_area((void *)evbuf, evbuf->length); + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "event buffer " + "at 0x%x up to 0x%x, length: %d\n", + (unsigned long) evbuf, + (unsigned long) (evbuf_end - 1), + evbuf->length); + dump_storage_area ((void *) evbuf, evbuf->length); #endif - retval += eval_evbuf(evbuf_data, evbuf_end); - break; - case ET_StateChange : - - retval = -ENOSYS; - break; - default : - printk( - KERN_WARNING - HWC_RW_PRINT_HEADER - "unconditional read: " - "unknown event buffer found, " - "type 0x%x", - evbuf->type); - retval = -ENOSYS; + retval += eval_evbuf (evbuf_data, evbuf_end); + break; + case ET_StateChange: + + retval = -ENOSYS; + break; + default: + printk ( + KERN_WARNING + HWC_RW_PRINT_HEADER + "unconditional read: " + "unknown event buffer found, " + "type 0x%x", + evbuf->type); + retval = -ENOSYS; } evbuf = (evbuf_t *) evbuf_end; } @@ -1501,40 +1514,40 @@ unsigned short int condition_code; read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; int retval; - + if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio)) return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; - - memset(hwcb, 0x00, PAGE_SIZE); - memcpy(hwcb, &read_hwcb_template, sizeof(read_hwcb_t)); - condition_code = service_call(HWC_CMDW_READDATA, hwc_data.page); + memset (hwcb, 0x00, PAGE_SIZE); + memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t)); -#ifdef DUMP_HWC_READ_ERROR + condition_code = service_call (HWC_CMDW_READDATA, hwc_data.page); + +#ifdef DUMP_HWC_READ_ERROR if (condition_code == HWC_NOT_OPERATIONAL) - __asm__("LHI 1,0xe40\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0 \n\t" - : - :"a"(&condition_code), "a"(hwc_data.page) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe40\n\t" + "L 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0 \n\t" + : + : "a" (&condition_code), "a" (hwc_data.page) + : "1", "2", "3"); +#endif switch (condition_code) { - case HWC_COMMAND_INITIATED : - hwc_data.current_servc = HWC_CMDW_READDATA; - hwc_data.current_hwcb = hwc_data.page; - retval = condition_code; - break; - case HWC_BUSY : - retval = -EBUSY; - break; - default : - retval = -EIO; + case HWC_COMMAND_INITIATED: + hwc_data.current_servc = HWC_CMDW_READDATA; + hwc_data.current_hwcb = hwc_data.page; + retval = condition_code; + break; + case HWC_BUSY: + retval = -EBUSY; + break; + default: + retval = -EIO; } return retval; @@ -1545,33 +1558,33 @@ { read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; -#ifdef DUMP_HWC_READ_ERROR +#ifdef DUMP_HWC_READ_ERROR if ((hwcb->response_code != 0x0020) && (hwcb->response_code != 0x0220) && (hwcb->response_code != 0x60F0) && (hwcb->response_code != 0x62F0)) - __asm__("LHI 1,0xe41\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "J .+0\n\t" - : - :"a"(hwc_data.page), "a"(&(hwcb->response_code)) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe41\n\t" + "LRA 2,0(0,%0)\n\t" + "L 3,0(0,%1)\n\t" + "J .+0\n\t" + : + : "a" (hwc_data.page), "a" (&(hwcb->response_code)) + : "1", "2", "3"); +#endif hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; switch (hwcb->response_code) { - case 0x0020 : - case 0x0220 : - return process_evbufs( - (void *) (((unsigned long) hwcb) + sizeof(read_hwcb_t)), - (void *) (((unsigned long) hwcb) + hwcb->length)); + case 0x0020: + case 0x0220: + return process_evbufs ( + (void *) (((unsigned long) hwcb) + sizeof (read_hwcb_t)), + (void *) (((unsigned long) hwcb) + hwcb->length)); - case 0x60F0 : - case 0x62F0 : + case 0x60F0: + case 0x62F0: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER @@ -1581,67 +1594,67 @@ hwcb->response_code); return 0; - case 0x0100 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: HWCB boundary violation - this " - "must not occur in a correct driver, please contact " - "author\n"); + case 0x0100: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: HWCB boundary violation - this " + "must not occur in a correct driver, please contact " + "author\n"); return -EIO; - case 0x0300 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: " + case 0x0300: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " "insufficient HWCB length - this must not occur in a " - "correct driver, please contact author\n"); + "correct driver, please contact author\n"); return -EIO; - case 0x01F0 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: " - "invalid command - this must not occur in a correct " - "driver, please contact author\n"); + case 0x01F0: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " + "invalid command - this must not occur in a correct " + "driver, please contact author\n"); return -EIO; - case 0x40F0 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: invalid function code - this " - "must not occur in a correct driver, please contact " - "author\n"); + case 0x40F0: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: invalid function code - this " + "must not occur in a correct driver, please contact " + "author\n"); return -EIO; - case 0x70F0 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: invalid selection mask - this " - "must not occur in a correct driver, please contact " - "author\n"); + case 0x70F0: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: invalid selection mask - this " + "must not occur in a correct driver, please contact " + "author\n"); return -EIO; - case 0x0040 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: HWC equipment check - don't " - "know how to handle this case\n"); + case 0x0040: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: HWC equipment check - don't " + "know how to handle this case\n"); return -EIO; - - default : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER + + default: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER "unconditional read: invalid response code %x - this " - "must not occur in a correct driver, please contact " - "author\n", - hwcb->response_code); + "must not occur in a correct driver, please contact " + "author\n", + hwcb->response_code); return -EIO; } } @@ -1651,32 +1664,32 @@ { unsigned int condition_code; int retval; - - condition_code = service_call(HWC_CMDW_WRITEMASK, hwc_data.page); + + condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page); #ifdef DUMP_HWC_INIT_ERROR if (condition_code == HWC_NOT_OPERATIONAL) - __asm__("LHI 1,0xe10\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0\n\t" - : - :"a"(&condition_code), "a"(hwc_data.page) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe10\n\t" + "L 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0\n\t" + : + : "a" (&condition_code), "a" (hwc_data.page) + : "1", "2", "3"); +#endif switch (condition_code) { - case HWC_COMMAND_INITIATED : - hwc_data.current_servc = HWC_CMDW_WRITEMASK; - hwc_data.current_hwcb = hwc_data.page; - retval = condition_code; - break; - case HWC_BUSY : - retval = -EBUSY; - break; - default : - retval = -EIO; + case HWC_COMMAND_INITIATED: + hwc_data.current_servc = HWC_CMDW_WRITEMASK; + hwc_data.current_hwcb = hwc_data.page; + retval = condition_code; + break; + case HWC_BUSY: + retval = -EBUSY; + break; + default: + retval = -EIO; } return retval; @@ -1690,10 +1703,10 @@ if (hwcb->hwc_receive_mask & ET_Msg_Mask) hwc_data.write_nonprio = 1; - + if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask) hwc_data.write_prio = 1; - + if (hwcb->hwc_send_mask & ET_OpCmd_Mask) { internal_print (DELAYED_WRITE, HWC_RW_PRINT_HEADER @@ -1710,16 +1723,16 @@ (!hwc_data.write_nonprio) || ((!hwc_data.read_nonprio) && (!hwc_data.read_prio))) #ifdef DUMP_HWC_INIT_ERROR - __asm__("LHI 1,0xe11\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "J .+0\n\t" - : - :"a"(hwcb), "a"(&(hwcb->response_code)) - :"1", "2", "3"); + __asm__ ("LHI 1,0xe11\n\t" + "LRA 2,0(0,%0)\n\t" + "L 3,0(0,%1)\n\t" + "J .+0\n\t" + : + : "a" (hwcb), "a" (&(hwcb->response_code)) + : "1", "2", "3"); #else retval = -EIO; -#endif +#endif hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -1732,7 +1745,7 @@ { int retval = 0; hwc_ioctls_t tmp; - + if (ioctls->width_htab > MAX_MESSAGE_SIZE) { if (correct) tmp.width_htab = MAX_MESSAGE_SIZE; @@ -1742,7 +1755,7 @@ tmp.width_htab = ioctls->width_htab; tmp.echo = ioctls->echo; - + if (ioctls->columns > MAX_MESSAGE_SIZE) { if (correct) tmp.columns = MAX_MESSAGE_SIZE; @@ -1750,21 +1763,21 @@ retval = -EINVAL; } else tmp.columns = ioctls->columns; - + switch (ioctls->code) { - case CODE_EBCDIC : - case CODE_ASCII : - tmp.code = ioctls->code; - break; - default : - if (correct) - tmp.code = CODE_ASCII; + case CODE_EBCDIC: + case CODE_ASCII: + tmp.code = ioctls->code; + break; + default: + if (correct) + tmp.code = CODE_ASCII; else retval = -EINVAL; } - + tmp.final_nl = ioctls->final_nl; - + if (ioctls->max_hwcb < 2) { if (correct) tmp.max_hwcb = 2; @@ -1772,9 +1785,9 @@ retval = -EINVAL; } else tmp.max_hwcb = ioctls->max_hwcb; - + tmp.tolower = ioctls->tolower; - + if (ioctls->kmem_hwcb > ioctls->max_hwcb) { if (correct) tmp.kmem_hwcb = ioctls->max_hwcb; @@ -1782,7 +1795,7 @@ retval = -EINVAL; } else tmp.kmem_hwcb = ioctls->kmem_hwcb; - + if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) { if (correct) ioctls->kmem_hwcb = MAX_KMEM_PAGES; @@ -1797,6 +1810,10 @@ } tmp.delim = ioctls->delim; + tmp.measured_lines = ioctls->measured_lines; + tmp.measured_chars = ioctls->measured_chars; + tmp.measured_wcalls = ioctls->measured_wcalls; + if (!(retval < 0)) hwc_data.ioctls = tmp; @@ -1864,7 +1881,7 @@ if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0) panic ("Couldn't request external interrupts 0x2401"); - spin_lock_init(&hwc_data.lock); + spin_lock_init (&hwc_data.lock); #ifdef USE_VM_DETECTION @@ -1880,7 +1897,7 @@ hwc_data.init_ioctls.delim = 0; } #endif - retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1); + retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1); *kmem_start = (*kmem_start + PAGE_SIZE - 1) & -4096L; hwc_data.kmem_start = *kmem_start; @@ -1889,26 +1906,26 @@ retval = do_hwc_init (); - ctl_set_bit(0, 9); + ctl_set_bit (0, 9); -#ifdef BUFFER_STRESS_TEST +#ifdef BUFFER_STRESS_TEST - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "use %i bytes for buffering.\n", - hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "use %i bytes for buffering.\n", + hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); for (i = 0; i < 500; i++) { hwcb = (init_hwcb_t *) BUF_HWCB; - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "This is stress test message #%i, free: %i bytes\n", - i, - MAX_HWCB_ROOM - (hwcb->length + sizeof(mto_t))); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "This is stress test message #%i, free: %i bytes\n", + i, + MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t))); } -#endif +#endif return /*retval */ 0; } @@ -1956,34 +1973,34 @@ " temporary breakdown\n"); } } else { - spin_lock(&hwc_data.lock); + spin_lock (&hwc_data.lock); - if (!hwc_data.current_servc) { + if (!hwc_data.current_servc) { - unconditional_read_1(); + unconditional_read_1 (); - } else { + } else { - switch (hwc_data.current_servc) { + switch (hwc_data.current_servc) { - case HWC_CMDW_WRITEMASK : + case HWC_CMDW_WRITEMASK: - write_event_mask_2(); + write_event_mask_2 (); break; - - case HWC_CMDW_WRITEDATA : - write_event_data_2(); + case HWC_CMDW_WRITEDATA: + + write_event_data_2 (); break; - case HWC_CMDW_READDATA : + case HWC_CMDW_READDATA: - unconditional_read_2(); + unconditional_read_2 (); break; - } + } - write_event_data_1(); - } + write_event_data_1 (); + } if (hwc_data.calls != NULL) if (hwc_data.calls->wake_up != NULL) (hwc_data.calls->wake_up) (); @@ -1996,7 +2013,7 @@ { spin_lock (&hwc_data.lock); - spin_unlock(&hwc_data.lock); + spin_unlock (&hwc_data.lock); asm volatile ("STCTL 0,0,%0":"=m" (cr0)); cr0_save = cr0; @@ -2021,39 +2038,45 @@ int retval = 0; unsigned long flags; unsigned int obuf; - - spin_lock_irqsave(&hwc_data.lock, flags); - + + spin_lock_irqsave (&hwc_data.lock, flags); + switch (cmd) { - case TIOCHWCSHTAB : - if (get_user(tmp.width_htab, (ioctl_htab_t *) arg)) + case TIOCHWCSMEAS: + hwc_data.ioctls.measured_lines = 0; + hwc_data.ioctls.measured_chars = 0; + hwc_data.ioctls.measured_wcalls = 0; + break; + + case TIOCHWCSHTAB: + if (get_user (tmp.width_htab, (ioctl_htab_t *) arg)) goto fault; break; - - case TIOCHWCSECHO : - if (get_user(tmp.echo, (ioctl_echo_t *) arg)) + + case TIOCHWCSECHO: + if (get_user (tmp.echo, (ioctl_echo_t *) arg)) goto fault; break; - - case TIOCHWCSCOLS : - if (get_user(tmp.columns, (ioctl_cols_t *) arg)) + + case TIOCHWCSCOLS: + if (get_user (tmp.columns, (ioctl_cols_t *) arg)) goto fault; break; - - case TIOCHWCSCODE : - if (get_user(tmp.code, (ioctl_code_t *) arg)) + + case TIOCHWCSCODE: + if (get_user (tmp.code, (ioctl_code_t *) arg)) goto fault; break; - - case TIOCHWCSNL : - if (get_user(tmp.final_nl, (ioctl_nl_t *) arg)) + + case TIOCHWCSNL: + if (get_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; break; - case TIOCHWCSOBUF : - if (get_user(obuf, (unsigned int *) arg)) + case TIOCHWCSOBUF: + if (get_user (obuf, (unsigned int *) arg)) goto fault; if (obuf & 0xFFF) tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12); @@ -2061,93 +2084,108 @@ tmp.max_hwcb = (obuf >> 12); break; - case TIOCHWCSCASE : - if (get_user(tmp.tolower, (ioctl_case_t *) arg)) + case TIOCHWCSCASE: + if (get_user (tmp.tolower, (ioctl_case_t *) arg)) goto fault; break; - - case TIOCHWCSDELIM : - if (get_user(tmp.delim, (ioctl_delim_t *) arg)) + + case TIOCHWCSDELIM: + if (get_user (tmp.delim, (ioctl_delim_t *) arg)) goto fault; break; - case TIOCHWCSINIT : - retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1); + case TIOCHWCSINIT: + retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1); break; - case TIOCHWCGHTAB : - if (put_user(tmp.width_htab, (ioctl_htab_t *) arg)) + case TIOCHWCGMEASL: + if (put_user (tmp.measured_lines, (ioctl_meas_t *) arg)) goto fault; break; - case TIOCHWCGECHO : - if (put_user(tmp.echo, (ioctl_echo_t *) arg)) + case TIOCHWCGMEASC: + if (put_user (tmp.measured_chars, (ioctl_meas_t *) arg)) goto fault; break; - case TIOCHWCGCOLS : - if (put_user(tmp.columns, (ioctl_cols_t *) arg)) + case TIOCHWCGMEASS: + if (put_user (tmp.measured_wcalls, (ioctl_meas_t *) arg)) goto fault; break; - case TIOCHWCGCODE : - if (put_user(tmp.code, (ioctl_code_t *) arg)) + case TIOCHWCGHTAB: + if (put_user (tmp.width_htab, (ioctl_htab_t *) arg)) goto fault; + break; + case TIOCHWCGECHO: + if (put_user (tmp.echo, (ioctl_echo_t *) arg)) + goto fault; break; - case TIOCHWCGNL : - if (put_user(tmp.final_nl, (ioctl_nl_t *) arg)) + case TIOCHWCGCOLS: + if (put_user (tmp.columns, (ioctl_cols_t *) arg)) goto fault; break; - case TIOCHWCGOBUF : - if (put_user(tmp.max_hwcb, (ioctl_obuf_t *) arg)) + case TIOCHWCGCODE: + if (put_user (tmp.code, (ioctl_code_t *) arg)) goto fault; + break; - case TIOCHWCGKBUF : - if (put_user(tmp.kmem_hwcb, (ioctl_obuf_t *) arg)) + case TIOCHWCGNL: + if (put_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; break; - case TIOCHWCGCASE : - if (put_user(tmp.tolower, (ioctl_case_t *) arg)) + case TIOCHWCGOBUF: + if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg)) goto fault; break; - - case TIOCHWCGDELIM : - if (put_user(tmp.delim, (ioctl_delim_t *) arg)) + + case TIOCHWCGKBUF: + if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg)) goto fault; break; -#if 0 - - case TIOCHWCGINIT : - if (put_user(&hwc_data.init_ioctls, (hwc_ioctls_t *) arg)) + + case TIOCHWCGCASE: + if (put_user (tmp.tolower, (ioctl_case_t *) arg)) goto fault; break; - case TIOCHWCGCURR : - if (put_user(&hwc_data.ioctls, (hwc_ioctls_t *) arg)) + case TIOCHWCGDELIM: + if (put_user (tmp.delim, (ioctl_delim_t *) arg)) + goto fault; + break; +#if 0 + + case TIOCHWCGINIT: + if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg)) + goto fault; + break; + + case TIOCHWCGCURR: + if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg)) goto fault; break; #endif - - default : + + default: goto noioctlcmd; } - if (_IOC_DIR(cmd) == _IOC_WRITE) - retval = set_hwc_ioctls(&tmp, 0); + if (_IOC_DIR (cmd) == _IOC_WRITE) + retval = set_hwc_ioctls (&tmp, 0); goto out; - fault: - retval = -EFAULT; - goto out; - noioctlcmd: - retval = -ENOIOCTLCMD; - out: - spin_unlock_irqrestore(&hwc_data.lock, flags); - return retval; + fault: + retval = -EFAULT; + goto out; + noioctlcmd: + retval = -ENOIOCTLCMD; + out: + spin_unlock_irqrestore (&hwc_data.lock, flags); + return retval; } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/char/hwc_rw.h linux/drivers/s390/char/hwc_rw.h --- v2.2.17/drivers/s390/char/hwc_rw.h Sun Jun 11 21:44:15 2000 +++ linux/drivers/s390/char/hwc_rw.h Wed Nov 8 23:05:32 2000 @@ -31,6 +31,7 @@ typedef unsigned short int ioctl_obuf_t; typedef unsigned char ioctl_case_t; typedef unsigned char ioctl_delim_t; +typedef unsigned long ioctl_meas_t; typedef struct { ioctl_htab_t width_htab; @@ -39,9 +40,12 @@ ioctl_code_t code; ioctl_nl_t final_nl; ioctl_obuf_t max_hwcb; - ioctl_obuf_t kmem_hwcb; + ioctl_obuf_t kmem_hwcb; ioctl_case_t tolower; ioctl_delim_t delim; + ioctl_meas_t measured_lines; + ioctl_meas_t measured_chars; + ioctl_meas_t measured_wcalls; } hwc_ioctls_t; static hwc_ioctls_t _hwc_ioctls; @@ -64,6 +68,8 @@ #define TIOCHWCSCASE _IOW(HWC_IOCTL_LETTER, 7, _hwc_ioctls.tolower) +#define TIOCHWCSMEAS _IO(HWC_IOCTL_LETTER, 8) + #define TIOCHWCSDELIM _IOW(HWC_IOCTL_LETTER, 9, _hwc_ioctls.delim) #define TIOCHWCGHTAB _IOR(HWC_IOCTL_LETTER, 10, _hwc_ioctls.width_htab) @@ -82,11 +88,17 @@ #define TIOCHWCGCASE _IOR(HWC_IOCTL_LETTER, 17, _hwc_ioctls.tolower) -#define TIOCHWCGDELIM _IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.delim) +#define TIOCHWCGDELIM _IOR(HWC_IOCTL_LETTER, 18, _hwc_ioctls.delim) + +#define TIOCHWCGKBUF _IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.max_hwcb) + +#define TIOCHWCGCURR _IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls) -#define TIOCHWCGKBUF _IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls.max_hwcb) +#define TIOCHWCGMEASL _IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls.measured_lines) -#define TIOCHWCGCURR _IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls) +#define TIOCHWCGMEASC _IOR(HWC_IOCTL_LETTER, 22, _hwc_ioctls.measured_chars) + +#define TIOCHWCGMEASS _IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls) #define CODE_ASCII 0x0 #define CODE_EBCDIC 0x1 @@ -117,4 +129,4 @@ #endif -#endif +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c --- v2.2.17/drivers/s390/char/hwc_tty.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/char/hwc_tty.c Wed Nov 8 23:05:32 2000 @@ -43,22 +43,22 @@ static hwc_tty_data_struct hwc_tty_data = { /* NULL/0 */ }; static struct tty_driver hwc_tty_driver; -static struct tty_struct * hwc_tty_table[1]; -static struct termios * hwc_tty_termios[1]; -static struct termios * hwc_tty_termios_locked[1]; +static struct tty_struct *hwc_tty_table[1]; +static struct termios *hwc_tty_termios[1]; +static struct termios *hwc_tty_termios_locked[1]; static int hwc_tty_refcount = 0; -extern struct termios tty_std_termios; +extern struct termios tty_std_termios; void hwc_tty_wake_up (void); void hwc_tty_input (unsigned char *, unsigned int); static int hwc_tty_open (struct tty_struct *tty, - struct file *filp) + struct file *filp) { - if (MINOR(tty->device) - tty->driver.minor_start) + if (MINOR (tty->device) - tty->driver.minor_start) return -ENODEV; tty->driver_data = &hwc_tty_data; @@ -75,10 +75,10 @@ static void hwc_tty_close (struct tty_struct *tty, - struct file *filp) + struct file *filp) { - if (MINOR(tty->device) != tty->driver.minor_start) { - printk(KERN_WARNING HWC_TTY_PRINT_HEADER + if (MINOR (tty->device) != tty->driver.minor_start) { + printk (KERN_WARNING HWC_TTY_PRINT_HEADER "do not close hwc tty because of wrong device number"); return; } @@ -95,40 +95,40 @@ { int retval; - retval = hwc_write_room(IN_BUFS_TOTAL); + retval = hwc_write_room (IN_BUFS_TOTAL); return retval; } static int hwc_tty_write (struct tty_struct *tty, - int from_user, - const unsigned char *buf, - int count) + int from_user, + const unsigned char *buf, + int count) { int retval; if (hwc_tty_data.buf_count > 0) { - hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count); + hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count); hwc_tty_data.buf_count = 0; } - retval = hwc_write(from_user, buf, count); + retval = hwc_write (from_user, buf, count); return retval; } static void hwc_tty_put_char (struct tty_struct *tty, - unsigned char ch) + unsigned char ch) { unsigned long flags; - spin_lock_irqsave(&hwc_tty_data.lock, flags); + spin_lock_irqsave (&hwc_tty_data.lock, flags); if (hwc_tty_data.buf_count >= HWC_TTY_BUF_SIZE) { - hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count); + hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count); hwc_tty_data.buf_count = 0; } hwc_tty_data.buf[hwc_tty_data.buf_count] = ch; hwc_tty_data.buf_count++; - spin_unlock_irqrestore(&hwc_tty_data.lock, flags); + spin_unlock_irqrestore (&hwc_tty_data.lock, flags); } static void @@ -136,10 +136,10 @@ { unsigned long flags; - spin_lock_irqsave(&hwc_tty_data.lock, flags); - hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count); + spin_lock_irqsave (&hwc_tty_data.lock, flags); + hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count); hwc_tty_data.buf_count = 0; - spin_unlock_irqrestore(&hwc_tty_data.lock, flags); + spin_unlock_irqrestore (&hwc_tty_data.lock, flags); } static int @@ -147,7 +147,7 @@ { int retval; - retval = hwc_chars_in_buffer(IN_BUFS_TOTAL); + retval = hwc_chars_in_buffer (IN_BUFS_TOTAL); return retval; } @@ -159,15 +159,15 @@ static int hwc_tty_ioctl ( - struct tty_struct *tty, - struct file * file, - unsigned int cmd, - unsigned long arg) + struct tty_struct *tty, + struct file *file, + unsigned int cmd, + unsigned long arg) { unsigned long count; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; switch (cmd) { case TIOCHWCTTYSINTRC: @@ -186,8 +186,8 @@ (long) hwc_tty_data.ioctl.intr_char_size); default: - return hwc_ioctl(cmd, arg); -} + return hwc_ioctl (cmd, arg); + } } void @@ -256,22 +256,22 @@ hwc_tty_data.ioctl.intr_char_size) == 0) { tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = INTR_CHAR(tty); + *tty->flip.char_buf_ptr++ = INTR_CHAR (tty); } else if (count == 2 && ( strncmp (buf, "^d", 2) == 0 || strncmp (buf, "\0252d", 2) == 0)) { tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = EOF_CHAR(tty); + *tty->flip.char_buf_ptr++ = EOF_CHAR (tty); } else if (count == 2 && ( strncmp (buf, "^z", 2) == 0 || strncmp (buf, "\0252z", 2) == 0)) { tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = SUSP_CHAR(tty); + *tty->flip.char_buf_ptr++ = SUSP_CHAR (tty); } else { - memcpy(tty->flip.char_buf_ptr, buf, count); + memcpy (tty->flip.char_buf_ptr, buf, count); if (count < 2 || ( strncmp (buf + count - 2, "^n", 2) || strncmp (buf + count - 2, "\0252n", 2))) { @@ -279,12 +279,12 @@ count++; } else count -= 2; - memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); + memset (tty->flip.flag_buf_ptr, TTY_NORMAL, count); tty->flip.char_buf_ptr += count; tty->flip.flag_buf_ptr += count; tty->flip.count += count; } - tty_flip_buffer_push(tty); + tty_flip_buffer_push (tty); hwc_tty_wake_up (); } #endif @@ -293,7 +293,7 @@ void hwc_tty_init (void) { - memset (&hwc_tty_driver, 0, sizeof(struct tty_driver)); + memset (&hwc_tty_driver, 0, sizeof (struct tty_driver)); memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct)); hwc_tty_driver.magic = TTY_DRIVER_MAGIC; hwc_tty_driver.driver_name = "tty_hwc"; @@ -310,7 +310,7 @@ hwc_tty_driver.init_termios.c_lflag = ISIG | ECHO; hwc_tty_driver.flags = TTY_DRIVER_REAL_RAW; hwc_tty_driver.refcount = &hwc_tty_refcount; - + hwc_tty_driver.table = hwc_tty_table; hwc_tty_driver.termios = hwc_tty_termios; hwc_tty_driver.termios_locked = hwc_tty_termios_locked; @@ -324,20 +324,20 @@ hwc_tty_driver.chars_in_buffer = hwc_tty_chars_in_buffer; hwc_tty_driver.flush_buffer = hwc_tty_flush_buffer; hwc_tty_driver.ioctl = hwc_tty_ioctl; - + hwc_tty_driver.throttle = NULL; hwc_tty_driver.unthrottle = NULL; hwc_tty_driver.send_xchar = NULL; hwc_tty_driver.set_termios = NULL; hwc_tty_driver.set_ldisc = NULL; - hwc_tty_driver.stop = NULL; - hwc_tty_driver.start = NULL; + hwc_tty_driver.stop = NULL; + hwc_tty_driver.start = NULL; hwc_tty_driver.hangup = NULL; hwc_tty_driver.break_ctl = NULL; hwc_tty_driver.wait_until_sent = NULL; hwc_tty_driver.read_proc = NULL; hwc_tty_driver.write_proc = NULL; - if (tty_register_driver(&hwc_tty_driver)) - panic("Couldn't register hwc_tty driver\n"); + if (tty_register_driver (&hwc_tty_driver)) + panic ("Couldn't register hwc_tty driver\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/idals.c linux/drivers/s390/idals.c --- v2.2.17/drivers/s390/idals.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/s390/idals.c Wed Nov 8 23:05:32 2000 @@ -0,0 +1,79 @@ +/* + * File...........: linux/drivers/s390x/idals.c + * Author(s)......: Holger Smolinski + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a + + * History of changes + * 07/24/00 new file + */ + +#include +#include +#include +#include + +#ifdef PRINTK_HEADER +#undef PRINTK_HEADER +#endif +#define PRINTK_HEADER "idals:" + +/* a name template for the cache-names */ +static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */ +/* the cache's names */ +static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1]; +/* the caches itself*/ +static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES]; + +void +free_idal ( ccw1_t *cp ) +{ + idaw_t *idal; + unsigned long upper2k,lower2k; + int nridaws,cacheind; + if ( cp -> flags & CCW_FLAG_IDA ) { + idal = cp -> cda; + lower2k = *idal & 0xfffffffffffff800; + upper2k = (*idal + cp -> count - 1) & 0xfffffffffffff800; + nridaws = ((upper2k - lower2k) >> 11) + 1; + for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ ); + kmem_cache_free ( idal_cache[cacheind], idal ); + } +} + +int +idal_support_init ( void ) +{ + int rc=0; + int cachind; + + for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { + int slabsize = 8 << cachind; + sprintf ( idal_cache_name[cachind], + "%s%d%c", idal_name_template, slabsize, 0); + idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind], + slabsize, 0, + SLAB_HWCACHE_ALIGN | SLAB_DMA, + NULL, NULL ); + if ( ! idal_cache [cachind] ) { + printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n"); + } + } + + return rc; +} + +void idal_support_cleanup ( void ) +{ + int cachind; + + /* Shrink the caches, if available */ + for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { + if ( idal_cache[cachind] ) { + if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) { + idal_cache[cachind] = NULL; + } + } + } + +} diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile --- v2.2.17/drivers/s390/net/Makefile Fri Apr 21 12:46:24 2000 +++ linux/drivers/s390/net/Makefile Sat Dec 9 20:56:03 2000 @@ -2,15 +2,23 @@ CFLAFS += O_TARGET := s390-net.o -O_OBJS := +O_OBJS := iucv.o M_OBJS := ifeq ($(CONFIG_CTC),y) O_OBJS += ctc.o +else + ifeq ($(CONFIG_CTC),m) + M_OBJS += ctc.o + endif endif ifeq ($(CONFIG_IUCV),y) - O_OBJS += iucv.o + O_OBJS += netiucv.o +else + ifeq ($(CONFIG_IUCV),m) + M_OBJS += netiucv.o + endif endif include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c --- v2.2.17/drivers/s390/net/ctc.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/net/ctc.c Sat Dec 9 20:56:00 2000 @@ -1,4 +1,6 @@ /* + * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $ + * * drivers/s390/net/ctc.c * CTC / ESCON network driver * @@ -7,7 +9,11 @@ * Author(s): Dieter Wellerdiek (wel@de.ibm.com) * * 2.3 Updates Martin Schwidefsky (schwidefsky@de.ibm.com) - * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * + * Modularization & Bugfixes by Fritz Elfert (fritz.elfert@millenux.de) + * + * Bugfixes by Jochen Röhrig (roehrig@de.ibm.com) * * * Description of the Kernel Parameter @@ -16,50 +22,142 @@ * order or doesn't want to have automatic channel selection on, you can do * this with the "ctc= kernel keyword". * - * ctc=0,0xrrrr,0xwwww,ddddd + * ctc=0,0xrrrr,0xwwww,ddddd * * Where: * - * "rrrr" is the read channel address - * "wwww" is the write channel address - * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 - * to escon7 for ESCON channels). + * "rrrr" is the read channel address + * "wwww" is the write channel address + * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 + * to escon7 for ESCON channels). * * To switch the automatic channel selection off use the ctc= keyword with * parameter "noauto". This may be necessary if you 3271 devices or other devices * which use the ctc device type and model, but operate with a different protocol. * - * ctc=noauto + * ctc=noauto + * + * $Log: ctc.c,v $ + * Revision 1.25.2.5 2000/10/11 15:08:59 bird + * ctc_tx(): Quick fix of possible underflow when calculating free block space + * + * Revision 1.25.2.4 2000/09/25 16:40:56 bird + * Some more debug information + * + * Revision 1.25.2.3 2000/09/20 13:28:19 bird + * - ctc_open(): fixed bug + * - ctc_release(): added timer for terminating in case of halt_io()-hang + * + * Revision 1.25.2.2 2000/09/20 09:48:27 bird + * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in + * instead of direct waiting on a wait queue + * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check(): + * print more debug information + * + * Revision 1.25.2.1 2000/09/19 09:09:56 bird + * Merged in changes from 1.25 to 1.26 + * + * Revision 1.25 2000/09/08 09:22:11 bird + * Proper cleanup and bugfixes in ctc_probe() + * + * Revision 1.24 2000/08/30 15:14:38 bird + * Some bugfixes and simplifications in ctc_probe() + * + * Revision 1.23 2000/08/28 16:50:35 bird + * - Suppress warning if discarding initial handshake block + * - Removed strstr() (now exported in arch/s390/kernel/s390_ksyms.c) + * + * Revision 1.22 2000/08/28 11:33:21 felfert + * Remove some dead code in ctc_open(). + * + * Revision 1.21 2000/08/28 09:31:06 bird + * init_module(): fixed pointer arithmetic (device name) + * + * Revision 1.20 2000/08/25 20:11:56 bird + * Didn´t build as non-module. + * + * Revision 1.19 2000/08/25 19:48:46 felfert + * Modularized version. + * + * Revision 1.18 2000/08/25 19:34:29 bird + * extract_channel_id(): + * - check for valid channel id; + * return -EINVAL in case of violation + * + * ctc_setup(): + * - check for valid channel id; + * return without doing anything in case of violation + * + * ctc_irq_bh(): + * - check for valid block length and packet length; + * discard block in case of invalid values + * (solves infinite loop problem that occurs if (for some unknown reason) + * the packet length = 0) + * + * Revision 1.17 2000/08/25 09:22:51 bird + * ctc_buffer_alloc(): + * fixed kmalloc()-bug (allocated buffer of wrong size) + * + * Revision 1.16 2000/08/24 17:46:19 bird + * ctc_write_retry(): + * - removed (presumably useless) loop for cleaning up the proc_anchor list. + * - inserted warning if proc_anchor (unexpectedly) != NULL + * + * Revision 1.15 2000/08/24 15:25:04 bird + * ctc_read_retry(): + * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set + * - removed some useless debug-messages + * ctc_write_retry(): + * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set + * + * Revision 1.14 2000/08/24 09:34:47 felfert + * Fixed bug in ctc_release: + * - ctc_unprotect_busy_irqrestore was called with wrong parameter. + * * - * Change History + * Old Change History * 0.50 Initial release shipped * 0.51 Bug fixes - * - CTC / ESCON network device can now handle up to 64 channels - * - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON - * - 3088-62 info message suppressed - OSA/D - * - channel: def ffffffed ... error message suppressed - * - CTC / ESCON device was not recoverable after a lost connection with - * IFCONFIG dev DOWN and IFCONFIG dev UP - * - Possibility to switch the automatic selection off - * - Minor bug fixes + * - CTC / ESCON network device can now handle up to 64 channels + * - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON + * - 3088-62 info message suppressed - OSA/D + * - channel: def ffffffed ... error message suppressed + * - CTC / ESCON device was not recoverable after a lost connection with + * IFCONFIG dev DOWN and IFCONFIG dev UP + * - Possibility to switch the automatic selection off + * - Minor bug fixes * 0.52 Bug fixes - * - Subchannel check message enhanced - * - Read / Write retry routine check for CTC_STOP added + * - Subchannel check message enhanced + * - Read / Write retry routine check for CTC_STOP added * 0.53 Enhancement - * - Connect time changed from 150 to 300 seconds - * This gives more a better chance to connect during IPL + * - Connect time changed from 150 to 300 seconds + * This gives more a better chance to connect during IPL * 0.54 Bug fixes - * - Out of memory message enhanced - * - Zero buffer problem in ctc_irq_hb solved - * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop, - * which could end in a out of memory situation. + * - Out of memory message enhanced + * - Zero buffer problem in ctc_irq_hb solved + * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop, + * which could end in a out of memory situation. * 0.55 Bug fixes - * - Connect problems with systems which IPL later - * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently - * not available. When systemB comes up it is nearly inpossible to setup a - * connection. + * - Connect problems with systems which IPL later + * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently + * not available. When systemB comes up it is nearly inpossible to setup a + * connection. + * + * 0.56 Bug fixes + * - ctc_open(): In case of failure stop read/write-retry timers before + * freeing buffers (stops kernel panics due to NULL-pointer + * dereferences in ctc_read_retry()) + * - Added some sanity checks concerning NULL-pointer dereferences + * - Added some comments + * + * 0.57 Bug fixes + * - CTC / ESCON network device can now handle up to 256 channels + * - ctc_read_retry(): added sanity check: if ctc->free_anchor == NULL + * print a warning and simply return */ + #include +#include #include #include #include @@ -78,6 +176,7 @@ #include #include #include +#include #include #include @@ -85,56 +184,67 @@ #include +#ifdef MODULE +MODULE_AUTHOR("(C) 2000 IBM Corp. by Dieter Wellerdiek (wel@de.ibm.com)"); +MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver"); +MODULE_PARM(setup,"s"); +MODULE_PARM_DESC(setup, +"One or more definitions in the same format like the kernel parameter line for ctc.\n" +"E.g.: \"ctc=0,0x700,0x701,ctc0 ctc=0,0x702,0x703,ctc1\".\n"); + +char *setup = NULL; +#endif + //#define DEBUG /* Redefine message level, so that all messages occur on 3215 console in DEBUG mode */ -#ifdef DEBUG - #undef KERN_INFO - #undef KERN_WARNING - #undef KERN_DEBUG - #define KERN_INFO KERN_EMERG - #define KERN_WARNING KERN_EMERG - #define KERN_DEBUG KERN_EMERG -#endif - - -#define CCW_CMD_WRITE 0x01 -#define CCW_CMD_READ 0x02 -#define CCW_CMD_SET_EXTENDED 0xc3 -#define CCW_CMD_PREPARE 0xe3 - -#define MAX_CHANNEL_DEVICES 64 -#define MAX_ADAPTERS 8 -#define CTC_DEFAULT_MTU_SIZE 1500 -#define READ 0 -#define WRITE 1 -#define CTC 0 -#define ESCON 1 -#define CHANNEL_MEDIA 2 -#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */ - -#define TB_TX 0 /* sk buffer handling in process */ -#define TB_STOP 1 /* network device stop in process */ -#define TB_RETRY 2 /* retry in process */ -#define TB_NOBUFFER 3 /* no buffer on free queue */ +#ifdef DEBUG + #undef KERN_INFO + #undef KERN_WARNING + #undef KERN_DEBUG + #define KERN_INFO KERN_EMERG + #define KERN_WARNING KERN_EMERG + #define KERN_DEBUG KERN_EMERG +#endif + + +#define CCW_CMD_WRITE 0x01 +#define CCW_CMD_READ 0x02 +#define CCW_CMD_SET_EXTENDED 0xc3 +#define CCW_CMD_PREPARE 0xe3 + +#define MAX_CHANNEL_DEVICES 256 +#define MAX_ADAPTERS 8 +#define CTC_DEFAULT_MTU_SIZE 1500 +#define READ 0 +#define WRITE 1 +#define CTC 0 +#define ESCON 1 +#define CHANNEL_MEDIA 2 +#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */ + +#define TB_TX 0 /* sk buffer handling in process */ +#define TB_STOP 1 /* network device stop in process */ +#define TB_RETRY 2 /* retry in process */ +#define TB_NOBUFFER 3 /* no buffer on free queue */ /* state machine codes used in ctc_irq_handler */ -#define CTC_STOP 0 -#define CTC_START_HALT_IO 1 -#define CTC_START_SET_X_MODE 2 -#define CTC_START_SELECT 4 -#define CTC_START_READ_TEST 32 -#define CTC_START_READ 33 -#define CTC_START_WRITE_TEST 64 -#define CTC_START_WRITE 65 +#define CTC_STOP 0 +#define CTC_START_HALT_IO 1 +#define CTC_START_SET_X_MODE 2 +#define CTC_START_SELECT 4 +#define CTC_START_READ_TEST 32 +#define CTC_START_READ 33 +#define CTC_START_WRITE_TEST 64 +#define CTC_START_WRITE 65 typedef enum { - channel_type_none, /* Device is not a channel */ - channel_type_undefined, /* Device is a channel but we don't know anything about it */ - channel_type_ctca, /* Device is a CTC/A and we can deal with it */ - channel_type_escon, /* Device is a ESCON channel and we can deal with it */ - channel_type_unsupported /* Device is a unsupported model */ + channel_type_none, /* Device is not a channel */ + channel_type_undefined, /* Device is a channel but we don't know anything about it */ + channel_type_ctca, /* Device is a CTC/A and we can deal with it */ + channel_type_escon, /* Device is a ESCON channel and we can deal with it */ + channel_type_unsupported /* Device is a unsupported model */ } channel_type_t; @@ -144,30 +254,39 @@ * */ -static int channel_tab_initialized = 0; /* channel[] structure initialized */ +static long channel_tab_initialized = 0; /* channel[] structure initialized */ struct devicelist { - unsigned int devno; - __u8 flag; -#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */ + unsigned int devno; + __u8 flag; +#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */ }; static struct { - struct devicelist list[MAX_CHANNEL_DEVICES]; - int count; - int left; + struct devicelist list[MAX_CHANNEL_DEVICES]; + int count; + int left; } channel[CHANNEL_MEDIA]; static int ctc_no_auto = 0; +#if LINUX_VERSION_CODE>=0x020300 +typedef struct net_device net_device; +#else +typedef struct device net_device; +typedef struct wait_queue* wait_queue_head_t; +#define init_waitqueue_head(nothing) +#endif + struct adapterlist{ - unsigned int devno[2]; - __u16 protocol; + unsigned int devno[2]; + __u16 protocol; + net_device *netdev; }; -static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */ +static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */ /* @@ -176,51 +295,43 @@ */ struct buffer { - struct buffer *next; - int packets; - struct block *block; + struct buffer *next; + int packets; + struct block *block; }; -#if LINUX_VERSION_CODE>=0x020300 -typedef struct net_device net_device; -#else -typedef struct device net_device; -typedef struct wait_queue* wait_queue_head_t; -#define DECLARE_WAITQUEUE(waitqname,waitqtask) struct wait_queue waitqname = {waitqtask, NULL } -#define init_waitqueue_head(nothing) -#endif - - struct channel { - unsigned int devno; - int irq; - unsigned long IO_active; - ccw1_t ccw[3]; - __u32 state; - int buffer_count; - struct buffer *free_anchor; - struct buffer *proc_anchor; - devstat_t *devstat; - net_device *dev; /* backward pointer to the network device */ + unsigned int devno; + int irq; + unsigned long IO_active; + ccw1_t ccw[3]; + __u32 state; + int buffer_count; + struct buffer *free_anchor; + struct buffer *proc_anchor; + devstat_t *devstat; + net_device *dev; /* backward pointer to the network device */ wait_queue_head_t wait; - struct tq_struct tq; - struct timer_list timer; - unsigned long flag_a; /* atomic flags */ -#define CTC_BH_ACTIVE 0 - __u8 last_dstat; - __u8 flag; -#define CTC_WRITE 0x01 /* - Set if this is a write channel */ -#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ + struct tq_struct tq; + int initial_block_received; /* only used for read channel */ + struct timer_list timer; + unsigned long flag_a; /* atomic flags */ +#define CTC_BH_ACTIVE 0 + __u8 last_dstat; + __u8 flag; +#define CTC_WRITE 0x01 /* - Set if this is a write channel */ +#define CTC_WAKEUP 0x02 /* - Set if this channel should wake up from waiting for an event */ +#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ }; -struct ctc_priv { - struct net_device_stats stats; +struct ctc_priv { + struct net_device_stats stats; #if LINUX_VERSION_CODE>=0x02032D - int tbusy; + unsigned long tbusy; #endif - struct channel channel[2]; - __u16 protocol; + struct channel channel[2]; + __u16 protocol; }; /* @@ -230,16 +341,16 @@ #define PACKET_HEADER_LENGTH 6 struct packet { - __u16 length; - __u16 type; - __u16 unused; - __u8 data; + __u16 length; + __u16 type; + __u16 unused; + __u8 data; }; #define BLOCK_HEADER_LENGTH 2 struct block { - __u16 length; - struct packet data; + __u16 length; + struct packet data; }; #if LINUX_VERSION_CODE>=0x02032D @@ -275,7 +386,7 @@ static __inline__ void ctc_setbit_busy(int nr,net_device *dev) { set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); - netif_stop_queue(dev); + netif_stop_queue(dev); } static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) @@ -318,17 +429,17 @@ static __inline__ void ctc_setbit_busy(int nr,net_device *dev) { - set_bit(nr,(void *)&dev->tbusy); + set_bit(nr,&dev->tbusy); } static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) { - clear_bit(nr,(void *)&dev->tbusy); + clear_bit(nr,&dev->tbusy); } static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev) { - return(test_and_set_bit(nr,(void *)&dev->tbusy)); + return(test_and_set_bit(nr,&dev->tbusy)); } #endif @@ -338,9 +449,9 @@ /* Interrupt handler */ static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs); -static void ctc_irq_bh(struct channel *ctc); -static void ctc_read_retry (struct channel *ctc); -static void ctc_write_retry (struct channel *ctc); +static void ctc_irq_bh(void *data); +static void ctc_read_retry (unsigned long data); +static void ctc_write_retry (unsigned long data); /* Functions for the DEV methods */ @@ -348,7 +459,7 @@ static int ctc_open(net_device *dev); -static void ctc_timer (struct channel *ctc); +static void ctc_timer (unsigned long data); static int ctc_release(net_device *dev); static int ctc_tx(struct sk_buff *skb, net_device *dev); static int ctc_change_mtu(net_device *dev, int new_mtu); @@ -370,35 +481,55 @@ /* + * misc. + */ +static void print_banner(void) { + static int printed = 0; + char vbuf[] = "$Revision: 1.25.2.5 $"; + char *version = vbuf; + + if (printed) + return; + if ((version = strchr(version, ':'))) { + char *p = strchr(version + 1, '$'); + if (p) + *p = '\0'; + } else + version = " ??? "; + printk(KERN_INFO "CTC driver Version%s initialized\n", version); + printed = 1; +} + +/* * initialize the channel[].list */ static void channel_init(void) { - int m; + int m; #ifdef DEBUG - int c; + int c; #endif - if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){ - channel_scan(); - for (m = 0; m < CHANNEL_MEDIA; m++) { - channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); - channel[m].left = channel[m].count; - } - if (channel[CTC].count == 0 && channel[ESCON].count == 0) - printk(KERN_INFO "channel: no Channel devices recognized\n"); - else - printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n", - channel[CTC].count, channel[ESCON].count); + if (!test_and_set_bit(0, &channel_tab_initialized)){ + channel_scan(); + for (m = 0; m < CHANNEL_MEDIA; m++) { + channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); + channel[m].left = channel[m].count; + } + if (channel[CTC].count == 0 && channel[ESCON].count == 0) + printk(KERN_INFO "channel: no Channel devices recognized\n"); + else + printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n", + channel[CTC].count, channel[ESCON].count); #ifdef DEBUG - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ - printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", - m, c, channel[m].list[c].devno); - } - } + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (c = 0; c < channel[m].count; c++){ + printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", + m, c, channel[m].list[c].devno); + } + } #endif - } + } } @@ -407,38 +538,37 @@ */ static void channel_scan(void) { - int m; - int c; - int irq; - dev_info_t temp; - - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ - channel[m].list[c].devno = -ENODEV; - } - } - - for (irq = 0; irq < NR_IRQS; irq++) { - /* CTC/A */ - if (channel[CTC].count < MAX_CHANNEL_DEVICES ) { - if (get_dev_info(irq, &temp) == 0 && - channel_check_for_type(&temp.sid_data) == channel_type_ctca) { - channel[CTC].list[channel[CTC].count].devno = temp.devno; - channel[CTC].count++; - } - } - - /* ESCON */ - if (channel[ESCON].count < MAX_CHANNEL_DEVICES ) { - if (get_dev_info(irq, &temp) == 0 && - channel_check_for_type(&temp.sid_data) == channel_type_escon) { - channel[ESCON].list[channel[ESCON].count].devno = temp.devno; - channel[ESCON].count++; - - } - } - } -} + int m; + int c; + int irq; + dev_info_t temp; + + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ + channel[m].list[c].devno = -ENODEV; + } + } + + for (irq = 0; irq < NR_IRQS; irq++) { + if (get_dev_info_by_irq(irq, &temp) == 0) { + if ((temp.status == DEVSTAT_NOT_OPER) || + (temp.status == DEVSTAT_DEVICE_OWNED)) + continue; + /* CTC/A */ + if ((channel[CTC].count < MAX_CHANNEL_DEVICES ) && + (channel_check_for_type(&temp.sid_data) == channel_type_ctca)) { + channel[CTC].list[channel[CTC].count].devno = temp.devno; + channel[CTC].count++; + } + /* ESCON */ + if ((channel[ESCON].count < MAX_CHANNEL_DEVICES ) && + (channel_check_for_type(&temp.sid_data) == channel_type_escon)) { + channel[ESCON].list[channel[ESCON].count].devno = temp.devno; + channel[ESCON].count++; + } + } + } +} /* @@ -446,17 +576,17 @@ */ static int channel_free(int media, int devno) { - int i; + int i; - for (i = 0; i < channel[media].count; i++) { - if ((devno == channel[media].list[i].devno) && - ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) { - channel[media].list[i].flag &= ~CHANNEL_IN_USE; - return 0; - } - } - printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); - return -ENODEV; + for (i = 0; i < channel[media].count; i++) { + if ((devno == channel[media].list[i].devno) && + ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) { + channel[media].list[i].flag &= ~CHANNEL_IN_USE; + return 0; + } + } + printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); + return -ENODEV; } @@ -465,17 +595,17 @@ */ static int channel_get(int media, int devno) { - int i; + int i; - for (i = 0; i < channel[media].count; i++) { - if ((devno == channel[media].list[i].devno) && - ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) { - channel[media].list[i].flag |= CHANNEL_IN_USE; - return channel[media].list[i].devno; - } - } - printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); - return -ENODEV; + for (i = 0; i < channel[media].count; i++) { + if ((devno == channel[media].list[i].devno) && + ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) { + channel[media].list[i].flag |= CHANNEL_IN_USE; + return channel[media].list[i].devno; + } + } + printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); + return -ENODEV; } @@ -485,18 +615,18 @@ */ static int channel_get_next(int media) { - int i; + int i; - for (i = 0; i < channel[media].count; i++) { - if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) { + for (i = 0; i < channel[media].count; i++) { + if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) { #ifdef DEBUG - printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno); + printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno); #endif - channel[media].list[i].flag |= CHANNEL_IN_USE; - return channel[media].list[i].devno; - } - } - return -ENODEV; + channel[media].list[i].flag |= CHANNEL_IN_USE; + return channel[media].list[i].devno; + } + } + return -ENODEV; } @@ -505,7 +635,7 @@ */ static int channel_left(int media) { - return channel[media].left; + return channel[media].left; } @@ -514,38 +644,38 @@ */ static channel_type_t channel_check_for_type (senseid_t *id) { - channel_type_t type; + channel_type_t type; - switch (id->cu_type) { - case 0x3088: + switch (id->cu_type) { + case 0x3088: - switch (id->cu_model) { - case 0x08: - type = channel_type_ctca; /* 3088-08 ==> CTCA */ - break; - - case 0x1F: - type = channel_type_escon; /* 3088-1F ==> ESCON channel */ - break; + switch (id->cu_model) { + case 0x08: + type = channel_type_ctca; /* 3088-08 ==> CTCA */ + break; + + case 0x1F: + type = channel_type_escon; /* 3088-1F ==> ESCON channel */ + break; - case 0x01: /* 3088-01 ==> P390 OSA emulation */ - case 0x60: /* 3088-60 ==> OSA/2 adapter */ - case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */ - case 0x62: /* 3088-62 ==> OSA/D device */ - type = channel_type_unsupported; - break; - - default: - type = channel_type_undefined; - printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model); - } - break; + case 0x01: /* 3088-01 ==> P390 OSA emulation */ + case 0x60: /* 3088-60 ==> OSA/2 adapter */ + case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */ + case 0x62: /* 3088-62 ==> OSA/D device */ + type = channel_type_unsupported; + break; + + default: + type = channel_type_undefined; + printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model); + } + break; - default: - type = channel_type_none; + default: + type = channel_type_none; - } - return type; + } + return type; } @@ -554,22 +684,22 @@ */ static void channel_sort(struct devicelist list[], int n) { - int i; - int sorted = 0; - struct devicelist tmp; - - while (!sorted) { - sorted = 1; - - for (i = 0; i < n-1; i++) { - if (list[i].devno > list[i+1].devno) { - tmp = list[i]; - list[i] = list[i+1]; - list[i+1] = tmp; - sorted = 0; - } - } - } + int i; + int sorted = 0; + struct devicelist tmp; + + while (!sorted) { + sorted = 1; + + for (i = 0; i < n-1; i++) { + if (list[i].devno > list[i+1].devno) { + tmp = list[i]; + list[i] = list[i+1]; + list[i+1] = tmp; + sorted = 0; + } + } + } } @@ -580,182 +710,216 @@ static int inline extract_channel_id(char *name) { - if (name[0] == 'c') - return (name[3]-'0'); - else - return (name[5]-'0'); + int rv = -1; + + if (name[0] == 'c') + rv = name[3]-'0'; + else + rv = name[5]-'0'; + + if ((rv < 0) || (rv >= MAX_ADAPTERS)) + rv= -EINVAL; + + return rv; } static int inline extract_channel_media(char *name) { - if (name[0] == 'c') - return CTC; - else - return ESCON; + if (name[0] == 'c') + return CTC; + else + return ESCON; } static void ctc_tab_init(void) -{ - int m; - int i; - static int t; - - if (t == 0){ - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (i = 0; i < MAX_ADAPTERS; i++) { - ctc_adapter[m][i].devno[WRITE] = -ENODEV; - ctc_adapter[m][i].devno[READ] = -ENODEV; - } - } - t = 1; - } +{ + int m; + int i; + static int t; + + if (t == 0){ + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (i = 0; i < MAX_ADAPTERS; i++) { + ctc_adapter[m][i].devno[WRITE] = -ENODEV; + ctc_adapter[m][i].devno[READ] = -ENODEV; + ctc_adapter[m][i].netdev = NULL; + } + } + t = 1; + } } static int ctc_buffer_alloc(struct channel *ctc) { - - struct buffer *p; - struct buffer *q; - - p = kmalloc(sizeof(p), GFP_KERNEL); - if (p == NULL) - return -ENOMEM; - else { - p->next = NULL; - p->packets = 0; - p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4); - if (p->block == NULL) { - kfree(p); - return -ENOMEM; - } - p->block->length = 0; - } + + struct buffer *p; + struct buffer *q; + + p = kmalloc(sizeof(struct buffer), GFP_KERNEL); + if (p == NULL) + return -ENOMEM; + else { + p->next = NULL; + p->packets = 0; + p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4); + if (p->block == NULL) { + kfree(p); + return -ENOMEM; + } + p->block->length = 0; + } - if (ctc->free_anchor == NULL) - ctc->free_anchor = p; - else { - q = ctc->free_anchor; - while (q->next != NULL) - q = q->next; - q->next = p; - } - ctc->buffer_count++; + if (ctc->free_anchor == NULL) + ctc->free_anchor = p; + else { + q = ctc->free_anchor; + while (q->next != NULL) + q = q->next; + q->next = p; + } + ctc->buffer_count++; return 0; } static int ctc_buffer_free(struct channel *ctc) { - - struct buffer *p; + + struct buffer *p; - - if (ctc->free_anchor == NULL) - return -ENOMEM; - - p = ctc->free_anchor; - ctc->free_anchor = p->next; - free_pages((__u32)p->block, 4); - kfree(p); - - return 0; + + if (ctc->free_anchor == NULL) + return -ENOMEM; + + p = ctc->free_anchor; + ctc->free_anchor = p->next; + free_pages((unsigned long)p->block, 4); + kfree(p); + + return 0; } -static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) { - - struct buffer *p = NULL; - struct buffer *q = NULL; +static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to, net_device *dev) { + + struct buffer *p = NULL; + struct buffer *q = NULL; - if (*from == NULL) - return -ENOMEM; - - p = *from; - *from = p->next; - p->next = NULL; - - if (*to == NULL) - *to = p; - else { - q = *to; - while (q->next != NULL) - q = q->next; - q->next = p; - - } - return 0; -} - - + if (*from == NULL) + { + printk(KERN_DEBUG + "%s: %s(): Trying to swap buffer from empty list - doing nothing\n", dev ? dev->name : "", __FUNCTION__); + + return -ENOMEM; + } + + p = *from; + *from = p->next; + p->next = NULL; + + if (*to == NULL) + *to = p; + else { + q = *to; + while (q->next != NULL) + q = q->next; + q->next = p; + + } + return 0; +} + +#ifdef MODULE + static void ctc_setup(char *dev_name,int *ints) +# define ctc_setup_return return +#else +# if LINUX_VERSION_CODE>=0x020300 + static int __init ctc_setup(char *dev_name) +# define ctc_setup_return return(1) +# else + __initfunc(void ctc_setup(char *dev_name,int *ints)) +# define ctc_setup_return return +# endif +#endif /* * ctc_setup function * this function is called for each ctc= keyword passed into the kernel * * valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx - * where n is the channel protocol always 0 - * 0xnnnn is the cu number read - * 0xnnnn is the cu number write - * ctcx can be ctc0 to ctc7 or escon0 to escon7 + * where n is the channel protocol always 0 + * 0xnnnn is the cu number read + * 0xnnnn is the cu number write + * ctcx can be ctc0 to ctc7 or escon0 to escon7 */ -#if LINUX_VERSION_CODE>=0x020300 -static int __init ctc_setup(char *dev_name) -#else -__initfunc(void ctc_setup(char *dev_name,int *ints)) -#endif + { - struct adapterlist tmp; + struct adapterlist tmp; + int id; #if LINUX_VERSION_CODE>=0x020300 #define CTC_MAX_PARMS 4 - int ints[CTC_MAX_PARMS+1]; - get_options(dev_name,CTC_MAX_PARMS,ints); - #define ctc_setup_return return(1) -#else - #define ctc_setup_return return + int ints[CTC_MAX_PARMS+1]; + dev_name = get_options(dev_name, CTC_MAX_PARMS, ints); #endif - ctc_tab_init(); - - ctc_no_auto = 1; - - if (!strcmp(dev_name,"noauto")) { - printk(KERN_INFO "ctc: automatic channel selection deactivated\n"); - ctc_setup_return; - } - - tmp.devno[WRITE] = -ENODEV; - tmp.devno[READ] = -ENODEV; - - switch (ints[0]) { - - case 3: /* write channel passed */ - tmp.devno[WRITE] = ints[3]; - - case 2: /* read channel passed */ - tmp.devno[READ] = ints[2]; - if (tmp.devno[WRITE] == -ENODEV) - tmp.devno[WRITE] = tmp.devno[READ] + 1; - - case 1: /* protocol type passed */ - tmp.protocol = ints[1]; - if (tmp.protocol == 0) { - break; - } else { - printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name); - ctc_setup_return; - } - break; - - default: - printk(KERN_WARNING "ctc: wrong number of parameter passed\n"); - ctc_setup_return; - } - ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp; -#ifdef DEBUG - printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n", - dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]); -#endif - ctc_setup_return; - + ctc_tab_init(); + + ctc_no_auto = 1; + + if (!dev_name) { /* happens if device name is not specified in + parameter line (cf. init/main.c:get_options() */ + printk(KERN_WARNING + "ctc: %s(): Device name not specified\n", + __FUNCTION__); + ctc_setup_return; + } + + if (!strcmp(dev_name,"noauto")) { + printk(KERN_INFO "ctc: automatic channel selection deactivated\n"); + ctc_setup_return; + } + + if ((id = extract_channel_id(dev_name)) == -EINVAL) + { + printk(KERN_WARNING + "ctc: %s(): Invalid device name specified: %s\n", + __FUNCTION__, dev_name); + ctc_setup_return; + } + + tmp.devno[WRITE] = -ENODEV; + tmp.devno[READ] = -ENODEV; + + switch (ints[0]) { + + case 3: /* write channel passed */ + tmp.devno[WRITE] = ints[3]; + + case 2: /* read channel passed */ + tmp.devno[READ] = ints[2]; + if (tmp.devno[WRITE] == -ENODEV) + tmp.devno[WRITE] = tmp.devno[READ] + 1; + + case 1: /* protocol type passed */ + tmp.protocol = ints[1]; + if (tmp.protocol == 0) { + break; + } else { + printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name); + ctc_setup_return; + } + break; + + default: + printk(KERN_WARNING "ctc: wrong number of parameter passed\n"); + ctc_setup_return; + } + ctc_adapter[extract_channel_media(dev_name)][id] = tmp; +#ifdef DEBUG + printk(KERN_DEBUG "%s: protocol=%x read=%04x write=%04x\n", + dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]); +#endif + ctc_setup_return; + } #if LINUX_VERSION_CODE>=0x020300 __setup("ctc=", ctc_setup); @@ -763,102 +927,131 @@ /* * ctc_probe - * this function is called for each channel network device, - * which is defined in the /init/main.c + * this function is called for each channel network device, + * which is defined in the /init/main.c */ int ctc_probe(net_device *dev) -{ - int rc; - int c; - int i; - int m; - - struct ctc_priv *privptr; - - /* Only the first time the ctc_probe gets control */ - if (channel_tab_initialized == 0) { - channel_init(); - - - } - - ctc_tab_init(); - - m = extract_channel_media(dev->name); - i = extract_channel_id(dev->name); - - if (channel_left(m) <=1) - return -ENODEV; - - if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV)) - return -ENODEV; - - dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ctc_priv)); - privptr = (struct ctc_priv *) (dev->priv); - - - for (c = 0; c < 2; c++) { - - privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL); - if (privptr->channel[c].devstat == NULL){ - if (i == WRITE) - kfree(privptr->channel[READ].devstat); - return -ENOMEM; - } - memset(privptr->channel[c].devstat, 0, sizeof(devstat_t)); - - if (ctc_no_auto == 0) - ctc_adapter[m][i].devno[c] = channel_get_next(m); - else - ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]); - - if ( ctc_adapter[m][i].devno[c] != -ENODEV){ - rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), - (void *)ctc_irq_handler, SA_INTERRUPT, dev->name, - privptr->channel[c].devstat); - if (rc) { - printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc); - return -EBUSY; - } - } else { - if (i == WRITE) { - free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat); - channel_free(m, ctc_adapter[m][i].devno[READ]); - kfree(privptr->channel[READ].devstat); - } - kfree(privptr->channel[i].devstat); - return -ENODEV; - } - } - - privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ]; - privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]); - privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE]; - privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]); - privptr->protocol = ctc_adapter[m][i].protocol; - channel[m].left = channel[m].left - 2; - - printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n", - dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq, - privptr->channel[WRITE].devno, privptr->channel[WRITE].irq); - - dev->mtu = CTC_DEFAULT_MTU_SIZE; - dev->hard_start_xmit = ctc_tx; - dev->open = ctc_open; - dev->stop = ctc_release; - dev->get_stats = ctc_stats; - dev->change_mtu = ctc_change_mtu; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_SLIP; - dev->tx_queue_len = 100; - dev_init_buffers(dev); - dev->flags = IFF_POINTOPOINT | IFF_NOARP; +{ + int rc; + int c; + int i; + int m; + struct ctc_priv *privptr; + + /* Only the first time the ctc_probe gets control */ + if (channel_tab_initialized == 0) { + channel_init(); + } + + ctc_tab_init(); + + m = extract_channel_media(dev->name); + i = extract_channel_id(dev->name); + + if (channel_left(m) <= 1) + return -ENODEV; + + if (i < 0 || i >= MAX_ADAPTERS) + return -ENODEV; + + if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV)) + return -ENODEV; + + dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL|GFP_DMA); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct ctc_priv)); + privptr = (struct ctc_priv *) (dev->priv); + + + for (c = 0; c < 2; c++) { + devstat_t *devstat; + unsigned int devno; + + privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL); + devstat = privptr->channel[c].devstat; + if (devstat == NULL) { + if (c == 1) { + free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat); + channel_free(m, ctc_adapter[m][i].devno[0]); + kfree(privptr->channel[0].devstat); + } + kfree(dev->priv); + dev->priv = NULL; + return -ENOMEM; + } + + memset(devstat, 0, sizeof(devstat_t)); + + if (ctc_no_auto == 0) { + ctc_adapter[m][i].devno[c] = channel_get_next(m); + devno = ctc_adapter[m][i].devno[c]; + } + else { + ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]); + devno = ctc_adapter[m][i].devno[c]; + } + + + if (devno != -ENODEV) { + rc = request_irq(get_irq_by_devno(devno), + ctc_irq_handler, SA_INTERRUPT, dev->name, + devstat); + if (rc) { + printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc); + if (c == 1) { + free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), + privptr->channel[0].devstat); + channel_free(m, ctc_adapter[m][i].devno[0]); + kfree(privptr->channel[0].devstat); + } + channel_free(m, devno); + kfree(devstat); + kfree(dev->priv); + dev->priv = NULL; + return -EBUSY; + } + } else { + if (c == 1) { + free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat); + channel_free(m, ctc_adapter[m][i].devno[0]); + kfree(privptr->channel[0].devstat); + } + kfree(devstat); + kfree(dev->priv); + dev->priv = NULL; + return -ENODEV; + } + } + + privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ]; + privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]); + privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE]; + privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]); + privptr->channel[READ].dev = privptr->channel[WRITE].dev = dev; + privptr->protocol = ctc_adapter[m][i].protocol; + channel[m].left = channel[m].left - 2; + + print_banner(); + printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n", + dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq, + privptr->channel[WRITE].devno, privptr->channel[WRITE].irq); + + dev->mtu = CTC_DEFAULT_MTU_SIZE; + dev->hard_start_xmit = ctc_tx; + dev->open = ctc_open; + dev->stop = ctc_release; + dev->get_stats = ctc_stats; + dev->change_mtu = ctc_change_mtu; + dev->hard_header_len = 6; + dev->addr_len = 0; + dev->type = ARPHRD_SLIP; + dev->tx_queue_len = 100; + dev_init_buffers(dev); + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + ctc_adapter[m][i].netdev = dev; - return 0; + return 0; } @@ -867,456 +1060,563 @@ * */ -static void inline ccw_check_return_code (net_device *dev, int return_code) +static void inline ccw_check_return_code (net_device *dev, int return_code, char *caller) { - if (return_code != 0) { - switch (return_code) { - case -EBUSY: - printk(KERN_INFO "%s: Busy !\n", dev->name); - break; - case -ENODEV: - printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name); - break; - case -EIO: - printk(KERN_EMERG "%s: Status pending... \n", dev->name); - break; - default: - printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n", - dev->name, return_code); - } - } + if (return_code != 0) { + switch (return_code) { + case -EBUSY: + printk(KERN_INFO "%s: %s: Busy !\n", dev->name, caller); + break; + case -ENODEV: + printk(KERN_EMERG "%s: %s: Invalid device called for IO\n", dev->name, caller); + break; + case -EIO: + printk(KERN_EMERG "%s: %s: Status pending... \n", dev->name, caller); + break; + default: + printk(KERN_EMERG "%s: %s: Unknown error in Do_IO %04x\n", + dev->name, caller, return_code); + } + } } -static void inline ccw_check_unit_check (net_device *dev, char sense) +static void inline ccw_check_unit_check (net_device *dev, char sense, char *caller) { #ifdef DEBUG - printk(KERN_INFO "%s: Unit Check with sense code: %02x\n", - dev->name, sense); + printk(KERN_INFO "%s: %s: Unit Check with sense code: %02x\n", + dev->name, caller, sense); #endif - if (sense & 0x40) { + if (sense & 0x40) { #ifdef DEBUG - if (sense & 0x01) - printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name); - else - printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name); -#endif - } else if (sense & 0x20) { - if (sense & 0x04) - printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name); - else - printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name); - } else if (sense & 0x10) { - if (sense & 0x20) - printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name); - else - printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name); - } + if (sense & 0x01) + printk(KERN_DEBUG "%s: %s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name, caller); + else + printk(KERN_DEBUG "%s: %s: System reset occured (remote side)\n", dev->name, caller); +#endif + } else if (sense & 0x20) { + if (sense & 0x04) + printk(KERN_WARNING "%s: %s: Data-streaming timeout)\n", dev->name, caller); + else + printk(KERN_WARNING "%s: %s: Data-transfer parity error\n", dev->name, caller); + } else if (sense & 0x10) { + if (sense & 0x20) + printk(KERN_WARNING "%s: %s: Hardware malfunction (remote side)\n", dev->name, caller); + else + printk(KERN_WARNING "%s: %s: Read-data parity error (remote side)\n", dev->name, caller); + } } - + static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) { - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - struct channel *ctc = NULL; - struct ctc_priv *privptr = NULL; - net_device *dev = NULL; - - /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL}, - {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */ - - ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, NULL}, - {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; + int rc = 0; + __u32 parm; + __u8 flags = 0x00; + struct channel *ctc = NULL; + struct ctc_priv *privptr = NULL; + net_device *dev = NULL; + + /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL}, + {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */ + + static ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, 0}, + {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, 0}}; - devstat_t *devstat = ((devstat_t *)initparm); + devstat_t *devstat = ((devstat_t *)initparm); - /* Bypass all 'unsolicited interrupts' */ - if (devstat->intparm == 0) { + /* Bypass all 'unsolicited interrupts' */ + if (devstat->intparm == 0) { #ifdef DEBUG - printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received c-%02x d-%02x f-%02x\n", - devstat->devno, devstat->cstat, devstat->dstat, devstat->flag); + printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received cstat: %02x dstat: %02x flag: %02x\n", + devstat->devno, devstat->cstat, devstat->dstat, devstat->flag); #endif - /* FIXME - find the related intparm!!! No IO outstanding!!!! */ - return; - } - - ctc = (struct channel *) (devstat->intparm); - dev = (net_device *) ctc->dev; - privptr = dev->priv; + /* FIXME - find the related intparm!!! No IO outstanding!!!! */ + return; + } + + ctc = (struct channel *) (devstat->intparm); + if(ctc==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler ctc=NULL irq=%d\n",irq); + return; + } + + dev = (net_device *) ctc->dev; + if(dev==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler dev=NULL irq=%d, ctc=0x%p\n", + irq, ctc); + return; + } + + privptr = dev->priv; + if(privptr==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler privptr=NULL " + "irq=%d, ctc=0x%p, dev=0x%p\n", irq, ctc, privptr); + return; + } #ifdef DEBUG - printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n", - dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state); + printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n", + dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state); #endif - /* Check for good subchannel return code, otherwise error message */ - if (devstat->cstat) { - printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n", - dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag); - return; - } + /* Check for good subchannel return code, otherwise error message */ + if (devstat->cstat) { + printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n", + dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag); + return; + } - /* Check the reason-code of a unit check */ - if (devstat->dstat & DEV_STAT_UNIT_CHECK) - ccw_check_unit_check(dev, devstat->ii.sense.data[0]); + /* Check the reason-code of a unit check */ + if (devstat->dstat & DEV_STAT_UNIT_CHECK) + ccw_check_unit_check(dev, devstat->ii.sense.data[0], __FUNCTION__ "()"); - /* State machine to bring the connection up / down and to restart */ + /* State machine to bring the connection up / down and to restart */ - ctc->last_dstat = devstat->dstat; + ctc->last_dstat = devstat->dstat; - switch (ctc->state) { + switch (ctc->state) { - case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */ - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - wake_up(&ctc->wait); /* wake up ctc_release */ - return; + case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */ +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_STOP"); +#endif + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_release */ + return; - case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - - ctc->state = CTC_START_SET_X_MODE; - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; + case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_HALT_IO"); +#endif + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + + ctc->state = CTC_START_SET_X_MODE; + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + return; - - case CTC_START_SET_X_MODE: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) != 0x41 || - (devstat->ii.sense.data[0] & 0x40) != 0x40) { - wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */ - return; - } - } - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - ctc->state = CTC_START_SELECT; + + case CTC_START_SET_X_MODE: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SET_X_MODE"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) != 0x41 || + (devstat->ii.sense.data[0] & 0x40) != 0x40) { + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */ + return; + } + } + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + ctc->state = CTC_START_SELECT; - case CTC_START_SELECT: - if (!ctc->flag & CTC_WRITE) { - ctc->state = CTC_START_READ_TEST; - ctc->free_anchor->block->length = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - wake_up(&ctc->wait); /* wake up ctc_open (READ) */ - - } else { - ctc->state = CTC_START_WRITE_TEST; - /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ - ctc->free_anchor->block->length = 0; - ctc->ccw[1].count = 2; /* Transfer only length */ - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags); - if (rc != 0) - ccw_check_return_code(dev, rc); - } - return; - - - case CTC_START_READ_TEST: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_read_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 10*HZ; - add_timer(&ctc->timer); + case CTC_START_SELECT: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SELECT"); +#endif + if(ctc->free_anchor==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_SELECT ctc_free_anchor=NULL " + "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr); + return; + } + if (!(ctc->flag & CTC_WRITE)) { + ctc->state = CTC_START_READ_TEST; + ctc->free_anchor->block->length = 0; + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[2]"); + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_open (READ) */ + + } else { + ctc->state = CTC_START_WRITE_TEST; + /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ + ctc->free_anchor->block->length = 0; + ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */ + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[3]"); + } + return; + + + case CTC_START_READ_TEST: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ_TEST"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || + (devstat->ii.sense.data[0] & 0x40) == 0x40 || + devstat->ii.sense.data[0] == 0 ) { + init_timer(&ctc->timer); + ctc->timer.function = ctc_read_retry; + ctc->timer.data = (unsigned long)ctc; + ctc->timer.expires = jiffies + 10*HZ; + add_timer(&ctc->timer); #ifdef DEBUG - printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); + printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); #endif - } - return; - } - - if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { - if ((devstat->dstat & DEV_STAT_ATTENTION) && - (devstat->dstat & DEV_STAT_BUSY)) { - printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name); - } - wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */ - return; - } - - ctc->state = CTC_START_READ; - set_bit(0, (void *)&ctc->IO_active); - - /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ - /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ - - - case CTC_START_READ: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - privptr->stats.rx_errors++; + } + return; + } + + if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { + if ((devstat->dstat & DEV_STAT_ATTENTION) && + (devstat->dstat & DEV_STAT_BUSY)) { + printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name); + } + privptr->channel[WRITE].flag |= CTC_WAKEUP; + wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */ + return; + } + + ctc->state = CTC_START_READ; + set_bit(0, &ctc->IO_active); + + /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ + /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ + + + case CTC_START_READ: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || + (devstat->ii.sense.data[0] & 0x40) == 0x40 || + devstat->ii.sense.data[0] == 0 ) { + privptr->stats.rx_errors++; /* Need protection here cos we are in the read irq */ /* handler the tbusy is for the write subchannel */ ctc_protect_busy(dev); - ctc_setbit_busy(TB_RETRY,dev); + ctc_setbit_busy(TB_RETRY,dev); ctc_unprotect_busy(dev); - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_read_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 30*HZ; - add_timer(&ctc->timer); - printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name); - } - return; - } + init_timer(&ctc->timer); + ctc->timer.function = ctc_read_retry; + ctc->timer.data = (unsigned long)ctc; + ctc->timer.expires = jiffies + 30*HZ; + add_timer(&ctc->timer); + printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name); + } + return; + } - if(!devstat->flag & DEVSTAT_FINAL_STATUS) - return; + if(!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; ctc_protect_busy(dev); ctc_clearbit_busy(TB_RETRY,dev); ctc_unprotect_busy(dev); - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); + ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); + + if (ctc->free_anchor != NULL) { + ctc->free_anchor->block->length = 0; + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[4]"); + } else { + clear_bit(0, &ctc->IO_active); +#ifdef DEBUG + printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name); +#endif + } + + if (test_and_set_bit(CTC_BH_ACTIVE, &ctc->flag_a) == 0) { + queue_task(&ctc->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + return; - if (ctc->free_anchor != NULL) { - ctc->free_anchor->block->length = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - } else { - clear_bit(0, (void *)&ctc->IO_active); -#ifdef DEBUG - printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name); -#endif - } - - if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) { - queue_task(&ctc->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - return; - - - case CTC_START_WRITE_TEST: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_write_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 10*HZ; - add_timer(&ctc->timer); -#ifdef DEBUG - printk(KERN_DEBUG "%s: write connection restarted\n",dev->name); -#endif - } - return; - } - - ctc->state = CTC_START_WRITE; - wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ - return; + + case CTC_START_WRITE_TEST: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE_TEST"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || + (devstat->ii.sense.data[0] & 0x40) == 0x40 || + devstat->ii.sense.data[0] == 0 ) { + init_timer(&ctc->timer); + ctc->timer.function = ctc_write_retry; + ctc->timer.data = (unsigned long)ctc; + ctc->timer.expires = jiffies + 10*HZ; + add_timer(&ctc->timer); +#ifdef DEBUG + printk(KERN_DEBUG "%s: write connection restarted\n",dev->name); +#endif + } + return; + } + + ctc->state = CTC_START_WRITE; + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ + return; - case CTC_START_WRITE: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - privptr->stats.tx_errors += ctc->proc_anchor->packets; -#ifdef DEBUG - printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name); -#endif - } else { - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - privptr->stats.tx_packets += ctc->proc_anchor->packets; - } - - ctc->proc_anchor->block->length = 0; - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - ctc_clearbit_busy(TB_NOBUFFER,dev); - if (ctc->proc_anchor != NULL) { -#ifdef DEBUG - printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); -#endif - ctc->ccw[1].count = ctc->proc_anchor->block->length; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - dev->trans_start = jiffies; - return; - - } - - if (ctc->free_anchor->block->length != 0) { - if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { - /* set transmission to busy */ - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); - ctc_clearbit_busy(TB_TX,dev); -#ifdef DEBUG - printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); -#endif - ctc->ccw[1].count = ctc->proc_anchor->block->length; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - dev->trans_start = jiffies; - return; - } - } + case CTC_START_WRITE: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + privptr->stats.tx_errors += ctc->proc_anchor->packets; +#ifdef DEBUG + printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name); +#endif + } else { + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + privptr->stats.tx_packets += ctc->proc_anchor->packets; + } + + ctc->proc_anchor->block->length = 0; + ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev); + ctc_clearbit_busy(TB_NOBUFFER, dev); + if (ctc->proc_anchor != NULL) { +#ifdef DEBUG + printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); +#endif + ctc->ccw[1].count = ctc->proc_anchor->block->length; + ctc->ccw[1].cda = __pa(ctc->proc_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[5]"); + dev->trans_start = jiffies; + return; + + } + if (ctc->free_anchor==NULL) { + printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_WRITE ctc_free_anchor=NULL " + "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr); + return; + } + if (ctc->free_anchor->block->length != 0) { + if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { + /* set transmission to busy */ + ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); + ctc_clearbit_busy(TB_TX,dev); +#ifdef DEBUG + printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); +#endif + ctc->ccw[1].count = ctc->proc_anchor->block->length; + ctc->ccw[1].cda = __pa(ctc->proc_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[6]"); + dev->trans_start = jiffies; + return; + } + } - clear_bit(0, (void *)&ctc->IO_active); /* set by ctc_tx or ctc_bh */ - return; + clear_bit(0, &ctc->IO_active); /* set by ctc_tx or ctc_bh */ + return; - default: - printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name); - return; - } + default: + printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name); + return; + } } -static void ctc_irq_bh (struct channel *ctc) +static void ctc_irq_bh (void *data) { - int rc = 0; - __u16 data_len; - __u32 parm; - - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; - struct ctc_priv *privptr; - struct packet *lp; - struct sk_buff *skb; + struct channel *ctc = (struct channel *) data; + net_device *dev = (net_device *) ctc->dev; + struct ctc_priv *privptr = (struct ctc_priv *) dev->priv; + + int rc = 0; + __u16 data_len; + __u32 parm; + + __u8 flags = 0x00; + unsigned long saveflags; + struct block *block; + struct packet *lp; + struct sk_buff *skb; - dev = (net_device *) ctc->dev; - privptr = (struct ctc_priv *) dev->priv; #ifdef DEBUG - printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state); + printk(KERN_DEBUG "%s: %s(): initial_block_received = %d\n" ,dev->name, __FUNCTION__, ctc->initial_block_received); + printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state); #endif - while (ctc->proc_anchor != NULL) { - - if (ctc->proc_anchor->block->length != 0) { - - lp = &ctc->proc_anchor->block->data; - while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) { - data_len = lp->length - PACKET_HEADER_LENGTH; - skb = dev_alloc_skb(data_len); - if (skb) { - memcpy(skb_put(skb, data_len),&lp->data, data_len); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->protocol = htons(ETH_P_IP); - skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */ - netif_rx(skb); - privptr->stats.rx_packets++; - } else { - privptr->stats.rx_dropped++; - printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name); - } - (__u8 *)lp += lp->length; - } - } + while (ctc->proc_anchor != NULL) { + block = ctc->proc_anchor->block; + if (block->length < BLOCK_HEADER_LENGTH) { + if(block->length == 0 && !ctc->initial_block_received) + ctc->initial_block_received = 1; + else + printk(KERN_INFO "%s: %s(): discarding block at 0x%p: " + "block length=%d<%d=block header length\n", + dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH); + } + else { + lp = &block->data; + while ((__u8 *) lp < (__u8 *) block + block->length) { + if(lp->length < PACKET_HEADER_LENGTH) { + printk(KERN_INFO "%s: %s(): discarding rest of block at 0x%p (block length=%d:) " + "packet at 0x%p, packet length=%d<%d=packet header length\n", + dev->name, __FUNCTION__, + block, block->length, lp, lp->length, PACKET_HEADER_LENGTH); + break; + } + + data_len = lp->length - PACKET_HEADER_LENGTH; +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): block=0x%p, block->length=%d, lp=0x%p, " + "lp->length=%d, data_len=%d\n", + dev->name, __FUNCTION__, block, block->length, lp, lp->length, data_len); +#endif + skb = dev_alloc_skb(data_len); + if (skb) { + memcpy(skb_put(skb, data_len),&lp->data, data_len); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->protocol = htons(ETH_P_IP); + skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */ + netif_rx(skb); + privptr->stats.rx_packets++; + } else { + privptr->stats.rx_dropped++; + printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name); + } + (__u8 *)lp += lp->length; + } + } - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); + s390irq_spin_lock_irqsave(ctc->irq, saveflags); + ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev); - if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) { + if (test_and_set_bit(0, &ctc->IO_active) == 0) { +#ifdef DEBUG + printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name); +#endif + if(ctc->free_anchor==NULL || ctc->free_anchor->block==NULL) + { + printk(KERN_CRIT "ctc: bad anchor free_anchor " + "ctc=0x%p, ctc->free_anchor=0x%p, ctc->irq=%d\n", + ctc, ctc->free_anchor, ctc->irq); + } + else + { + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + } + } + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + } + clear_bit(CTC_BH_ACTIVE, &ctc->flag_a); #ifdef DEBUG - printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name); + printk(KERN_DEBUG "%s: end bh routine - state-%02x\n" ,dev->name, ctc->state); #endif - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - } - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - } - clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a); - return; + return; } -static void ctc_read_retry (struct channel *ctc) +static void ctc_read_retry (unsigned long data) { - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; + struct channel *ctc = (struct channel *) data; + net_device *dev = (net_device *) ctc->dev; + int rc = 0; + __u32 parm; + __u8 flags = 0x00; + unsigned long saveflags; + - dev = (net_device *) ctc->dev; - #ifdef DEBUG - printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state); -#endif - if (ctc->state == CTC_STOP) - return; - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc->free_anchor->block->length = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; + printk(KERN_DEBUG "%s: read retry - state-%02x\n", + dev->name, ctc->state); +#endif + s390irq_spin_lock_irqsave(ctc->irq, saveflags); + if (ctc->state != CTC_STOP) { + if (!ctc->free_anchor) { + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + printk(KERN_WARNING + "%s: %s(): ctc->free_anchor=NULL, ctc=0x%p\n", + dev->name, __FUNCTION__, ctc); + return; + } + + ctc->free_anchor->block->length = 0; + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags); + } + + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + + return; } -static void ctc_write_retry (struct channel *ctc) +static void ctc_write_retry (unsigned long data) { - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; + struct channel *ctc = (struct channel *) data; + net_device *dev = (net_device *) ctc->dev; + int rc = 0; + __u32 parm; + __u8 flags = 0x00; + unsigned long saveflags; - dev = (net_device *) ctc->dev; #ifdef DEBUG - printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state); -#endif - if (ctc->state == CTC_STOP) - return; - - while (ctc->proc_anchor != NULL) { - ctc->proc_anchor->block->length = 0; - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - } - - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc->ccw[1].count = 2; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; + printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state); +#endif + + if (ctc->proc_anchor != NULL) { + printk(KERN_WARNING "%s: %s(): ctc->proc_anchor != NULL\n" ,dev->name, __FUNCTION__); + } + + s390irq_spin_lock_irqsave(ctc->irq, saveflags); + + if (ctc->state != CTC_STOP) + { + ctc->ccw[1].count = 2; + ctc->ccw[1].cda = __pa(ctc->proc_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + } + + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + + return; } @@ -1327,123 +1627,139 @@ */ static int ctc_open(net_device *dev) { - int rc; - int i; - int j; - __u8 flags = 0x00; - __u32 saveflags; - __u32 parm; - struct ctc_priv *privptr; - DECLARE_WAITQUEUE(wait, current); - struct timer_list timer; - - - ctc_set_busy(dev); - - privptr = (struct ctc_priv *) (dev->priv); - - privptr->channel[READ].flag = 0x00; - privptr->channel[WRITE].flag = CTC_WRITE; - - for (i = 0; i < 2; i++) { - for (j = 0; j < CTC_BLOCKS; j++) { - rc = ctc_buffer_alloc(&privptr->channel[i]); - if (rc != 0) - return -ENOMEM; - } - init_waitqueue_head(&privptr->channel[i].wait); - privptr->channel[i].tq.next = NULL; - privptr->channel[i].tq.sync = 0; - privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh; - privptr->channel[i].tq.data = &privptr->channel[i]; - - privptr->channel[i].dev = dev; - - privptr->channel[i].flag_a = 0; - privptr->channel[i].IO_active = 0; - - privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE; - privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; - privptr->channel[i].ccw[0].count = 0; - privptr->channel[i].ccw[0].cda = NULL; - if (i == READ) { - privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ; - privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI; - privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */ - privptr->channel[i].ccw[1].cda = NULL; - } else { - privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE; - privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC; - privptr->channel[i].ccw[1].count = 0; - privptr->channel[i].ccw[1].cda = NULL; - } - privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */ - privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI; - privptr->channel[i].ccw[2].count = 0; - privptr->channel[i].ccw[2].cda = NULL; - - privptr->channel[i].flag &= ~CTC_TIMER; - init_timer(&timer); - timer.function = (void *)ctc_timer; - timer.data = (__u32)&privptr->channel[i]; - timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */ - add_timer(&timer); - - s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - parm = (unsigned long) &privptr->channel[i]; - privptr->channel[i].state = CTC_START_HALT_IO; - rc = halt_IO(privptr->channel[i].irq, parm, flags); - add_wait_queue(&privptr->channel[i].wait, &wait); - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - schedule(); - remove_wait_queue(&privptr->channel[i].wait, &wait); - if(rc != 0) - ccw_check_return_code(dev, rc); - if((privptr->channel[i].flag & CTC_TIMER) == 0x00) - del_timer(&timer); - } - - if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & - ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || - (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) { + int rc, wait_rc; + int i, ii; + int j; + __u8 flags = 0x00; + unsigned long saveflags; + __u32 parm; + struct ctc_priv *privptr; + struct timer_list timer; + + + ctc_set_busy(dev); + + privptr = (struct ctc_priv *) (dev->priv); + + privptr->channel[READ].flag = 0x00; + privptr->channel[WRITE].flag = CTC_WRITE; + + for (i = 0; i < 2; i++) { + privptr->channel[i].free_anchor = NULL; + privptr->channel[i].proc_anchor = NULL;; + for (j = 0; j < CTC_BLOCKS; j++) { + rc = ctc_buffer_alloc(&privptr->channel[i]); + if (rc != 0) + return -ENOMEM; + } + init_waitqueue_head(&privptr->channel[i].wait); + privptr->channel[i].tq.next = NULL; + privptr->channel[i].tq.sync = 0; + privptr->channel[i].tq.routine = ctc_irq_bh; + privptr->channel[i].tq.data = &privptr->channel[i]; + + privptr->channel[i].initial_block_received = 0; + + privptr->channel[i].dev = dev; + + privptr->channel[i].flag_a = 0; + privptr->channel[i].IO_active = 0; + + privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE; + privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; + privptr->channel[i].ccw[0].count = 0; + privptr->channel[i].ccw[0].cda = 0; + if (i == READ) { + privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ; + privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI; + privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */ + privptr->channel[i].ccw[1].cda = 0; + } else { + privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE; + privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC; + privptr->channel[i].ccw[1].count = 0; + privptr->channel[i].ccw[1].cda = 0; + } + privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */ + privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI; + privptr->channel[i].ccw[2].count = 0; + privptr->channel[i].ccw[2].cda = 0; + + privptr->channel[i].flag &= ~(CTC_TIMER | CTC_WAKEUP); + init_timer(&timer); + timer.function = ctc_timer; + timer.data = (unsigned long)&privptr->channel[i]; + timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */ + add_timer(&timer); + + s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); + parm = (unsigned long) &privptr->channel[i]; + privptr->channel[i].state = CTC_START_HALT_IO; + rc = halt_IO(privptr->channel[i].irq, parm, flags); + s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); + + wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); + + del_timer(&timer); + + if(rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + + if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */ + for (ii=0; ii<=i; ii++) { + + del_timer(&privptr->channel[ii].timer); + + for (j=0; privptr->channel[ii].free_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_free(&privptr->channel[ii]); + + if (privptr->channel[ii].free_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + } + return -ERESTARTSYS; + } + } + + if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & + ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || + (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) { #ifdef DEBUG - printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n", - dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); + printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n", + dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); #endif - printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name); - - for (i = 0; i < 2; i++) { - /* s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - parm = (unsigned long) &privptr->channel[i]; - privptr->channel[i].state = CTC_STOP; - rc = halt_IO(privptr->channel[i].irq, parm, flags); / - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); */ - for (j = 0; j < CTC_BLOCKS; j++) - ctc_buffer_free(&privptr->channel[i]); - } - return -EIO; - } - - printk(KERN_INFO "%s: connected with remote side\n",dev->name); - ctc_clear_busy(dev); - return 0; + printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name); + + for (i = 0; i < 2; i++) { + del_timer(&privptr->channel[i].timer); + + for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_free(&privptr->channel[i]); + + if (privptr->channel[i].free_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + } + return -EIO; + } + + printk(KERN_INFO "%s: connected with remote side\n",dev->name); + ctc_clear_busy(dev); + MOD_INC_USE_COUNT; + return 0; } -static void ctc_timer (struct channel *ctc) -{ -#ifdef DEBUG - net_device *dev; - - dev = (net_device *) ctc->dev; - printk(KERN_DEBUG "%s: timer return\n" ,dev->name); -#endif - ctc->flag |= CTC_TIMER; - wake_up(&ctc->wait); - return; +static void ctc_timer (unsigned long data) +{ + struct channel *ctc = (struct channel *) data; +#ifdef DEBUG + net_device *dev = (net_device *) ctc->dev; + printk(KERN_DEBUG "%s: timer return\n" ,dev->name); +#endif + ctc->flag |= (CTC_TIMER|CTC_WAKEUP); + wake_up(&ctc->wait); + return; } /* @@ -1452,49 +1768,75 @@ */ static int ctc_release(net_device *dev) { - int rc; - int i; - int j; - __u8 flags = 0x00; - __u32 saveflags; - __u32 parm; - struct ctc_priv *privptr; - DECLARE_WAITQUEUE(wait, current); - - privptr = (struct ctc_priv *) dev->priv; - - ctc_protect_busy_irqsave(dev,saveflags); - ctc_setbit_busy(TB_STOP,dev); - ctc_unprotect_busy_irqrestore(dev,flags); - for (i = 0; i < 2; i++) { - s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - del_timer(&privptr->channel[READ].timer); - privptr->channel[i].state = CTC_STOP; - parm = (__u32) &privptr->channel[i]; - rc = halt_IO (privptr->channel[i].irq, parm, flags ); - add_wait_queue(&privptr->channel[i].wait, &wait); - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - schedule(); - remove_wait_queue(&privptr->channel[i].wait, &wait); - if (rc != 0) { - ccw_check_return_code(dev, rc); - } - - for (j = 0; j < CTC_BLOCKS; j++) { - ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor); - ctc_buffer_free(&privptr->channel[i]); - } - } - - if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & - ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { - printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n", - dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); - return -EIO; - } + int rc; + int i; + int j; + __u8 flags = 0x00; + unsigned long saveflags; + __u32 parm; + struct ctc_priv *privptr; + struct timer_list timer; + + privptr = (struct ctc_priv *) dev->priv; + + ctc_protect_busy_irqsave(dev, saveflags); + ctc_setbit_busy(TB_STOP,dev); + ctc_unprotect_busy_irqrestore(dev, saveflags); + + for (i = 0; i < 2; i++) { + privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER); + init_timer(&timer); + timer.function = ctc_timer; + timer.data = (unsigned long)&privptr->channel[i]; + timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */ + add_timer(&timer); + + s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); + del_timer(&privptr->channel[i].timer); + privptr->channel[i].state = CTC_STOP; + parm = (__u32)(long) &privptr->channel[i]; + rc = halt_IO (privptr->channel[i].irq, parm, flags ); + s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); + + wait_event(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); + + del_timer(&timer); + + if (rc != 0) { + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + } + + if(privptr->channel[i].flag & CTC_TIMER) + { + printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n", + dev->name, __FUNCTION__); + } + + + for (j=0; privptr->channel[i].proc_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor, dev); + + if (privptr->channel[i].proc_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to move more than maximal number %d of blocks to free list\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + + for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_free(&privptr->channel[i]); + + if (privptr->channel[i].free_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + } + + if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & + ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { + printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n", + dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); + return -EIO; + } - return 0; + MOD_DEC_USE_COUNT; + return 0; } @@ -1505,80 +1847,80 @@ */ static int ctc_tx(struct sk_buff *skb, net_device *dev) { - int rc=0,rc2; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - struct ctc_priv *privptr; - struct packet *lp; - + int rc=0,rc2; + __u32 parm; + __u8 flags = 0x00; + unsigned long saveflags; + struct ctc_priv *privptr; + struct packet *lp; + - privptr = (struct ctc_priv *) (dev->priv); + privptr = (struct ctc_priv *) (dev->priv); - if (skb == NULL) { - printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name); - privptr->stats.tx_dropped++; - return -EIO; - } - - s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags); - if (ctc_check_busy(dev)) { - rc=-EBUSY; + if (skb == NULL) { + printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name); + privptr->stats.tx_dropped++; + return -EIO; + } + + s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags); + if (ctc_check_busy(dev)) { + rc=-EBUSY; goto Done; - } + } - if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */ - rc=-EBUSY; + if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */ + rc=-EBUSY; goto Done; - } + } - if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) { + if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) { #ifdef DEBUG - printk(KERN_DEBUG "%s: early swap\n", dev->name); + printk(KERN_DEBUG "%s: early swap\n", dev->name); #endif - - ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor); - if (privptr->channel[WRITE].free_anchor == NULL){ - ctc_setbit_busy(TB_NOBUFFER,dev); - rc=-EBUSY; + + ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor, dev); + if (privptr->channel[WRITE].free_anchor == NULL){ + ctc_setbit_busy(TB_NOBUFFER,dev); + rc=-EBUSY; goto Done2; - } - } - - if (privptr->channel[WRITE].free_anchor->block->length == 0) { - privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; - privptr->channel[WRITE].free_anchor->packets = 0; - } - - - (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + privptr->channel[WRITE].free_anchor->block->length; - privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH; - lp->length = skb->len + PACKET_HEADER_LENGTH; - lp->type = 0x0800; - lp->unused = 0; - memcpy(&lp->data, skb->data, skb->len); - (__u8 *) lp += lp->length; - lp->length = 0; - dev_kfree_skb(skb); - privptr->channel[WRITE].free_anchor->packets++; - - if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) { - ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor); - privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length; - privptr->channel[WRITE].ccw[1].cda = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block); - parm = (__u32) &privptr->channel[WRITE]; - rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags ); - if (rc2 != 0) - ccw_check_return_code(dev, rc2); - dev->trans_start = jiffies; - } - if (privptr->channel[WRITE].free_anchor == NULL) - ctc_setbit_busy(TB_NOBUFFER,dev); + } + } + + if (privptr->channel[WRITE].free_anchor->block->length == 0) { + privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; + privptr->channel[WRITE].free_anchor->packets = 0; + } + + + (__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length; + privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH; + lp->length = skb->len + PACKET_HEADER_LENGTH; + lp->type = 0x0800; + lp->unused = 0; + memcpy(&lp->data, skb->data, skb->len); + (__u8 *) lp += lp->length; + lp->length = 0; + dev_kfree_skb(skb); + privptr->channel[WRITE].free_anchor->packets++; + + if (test_and_set_bit(0, &privptr->channel[WRITE].IO_active) == 0) { + ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor, dev); + privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length; + privptr->channel[WRITE].ccw[1].cda = __pa(privptr->channel[WRITE].proc_anchor->block); + parm = (__u32)(long) &privptr->channel[WRITE]; + rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags ); + if (rc2 != 0) + ccw_check_return_code(dev, rc2, __FUNCTION__ "()[1]"); + dev->trans_start = jiffies; + } + if (privptr->channel[WRITE].free_anchor == NULL) + ctc_setbit_busy(TB_NOBUFFER,dev); Done2: - ctc_clearbit_busy(TB_TX,dev); + ctc_clearbit_busy(TB_TX,dev); Done: s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags); - return(rc); + return(rc); } @@ -1586,15 +1928,15 @@ * ctc_change_mtu * * S/390 can handle MTU sizes from 576 to 32760 for VM, VSE - * 576 to 65527 for OS/390 + * 576 to 65527 for OS/390 * */ static int ctc_change_mtu(net_device *dev, int new_mtu) { - if ((new_mtu < 576) || (new_mtu > 65528)) - return -EINVAL; - dev->mtu = new_mtu; - return 0; + if ((new_mtu < 576) || (new_mtu > 65528)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; } @@ -1604,18 +1946,129 @@ */ struct net_device_stats *ctc_stats(net_device *dev) { - struct ctc_priv *privptr; + struct ctc_priv *privptr; - privptr = dev->priv; - return &privptr->stats; + privptr = dev->priv; + return &privptr->stats; } - /* Module code goes here */ -/* - free_irq(privptr->channel[i].irq, privptr->channel[i].devstat); - kfree(privptr->channel[i].devstat); +#ifdef MODULE +void cleanup_module(void) { + int m; + int i; + int c; + + /* we are called if all interfaces are down only, so no need + * to bother around with locking stuff + */ + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (i = 0; i < MAX_ADAPTERS; i++) + if (ctc_adapter[m][i].netdev) { + struct ctc_priv *privptr = ctc_adapter[m][i].netdev->priv; + + unregister_netdev(ctc_adapter[m][i].netdev); + for (c = 0; c < 2; c++) { + free_irq(privptr->channel[c].irq, privptr->channel[c].devstat); + kfree(privptr->channel[c].devstat); + } + kfree(privptr); + kfree(ctc_adapter[m][i].netdev); + } + } + printk(KERN_INFO "CTC driver unloaded\n"); +} + +static char *parse_opts(char *str, int *ints) { + char *cur = str; + int i = 1; + + while (cur && (*cur == '-' || isdigit(*cur)) && i <= 10) { + ints[i++] = simple_strtoul(cur, NULL, 0); + if ((cur = strchr(cur, ',')) != NULL) + cur++; + } + ints[0] = i - 1; + return(cur); +} + +int init_module(void) { + char *p = setup; /* This string is set by insmod, it is writeable */ + int cnt; + int itype; + int activated; + int ints[10]; + + print_banner(); + + /** + * Parse setup string just like in init/main.c + */ + while (p && *p) { + char *q = strstr(p, "ctc="); + if (q) { + /** + * Found "ctc=" in string + */ + q += 4; + if ((p = parse_opts(q, ints))) { + /** + * p is now pointing to the first non-number parameter + * + */ + if ((q = strchr(p, ' '))) + *q = '\0'; + ctc_setup(p, ints); + if (q) + p = q + 1; + else + p = NULL; + } + } else + p = NULL; + } + + activated = 0; + for (itype = 0; itype < 2; itype++) { + cnt = 0; + do { + net_device *dev = kmalloc(sizeof(net_device) + 11 /* name + trailing zero */ , GFP_KERNEL); + if (!dev) { + return -ENOMEM; + } + memset((unsigned char *)dev, 0, sizeof(net_device)); + dev->name = (unsigned char *)dev + sizeof(net_device); + sprintf(dev->name, "%s%d", (itype) ? "escon" : "ctc", cnt++); + if (ctc_probe(dev) == 0) { + if (register_netdev(dev) != 0) { + struct ctc_priv *privptr = dev->priv; + int m = extract_channel_media(dev->name); + int i = extract_channel_id(dev->name); + + printk(KERN_WARNING "ctc: Couldn't register %s\n", dev->name); + free_irq(privptr->channel[READ].irq, privptr->channel[READ].devstat); + kfree(privptr->channel[READ].devstat); + free_irq(privptr->channel[WRITE].irq, privptr->channel[WRITE].devstat); + kfree(privptr->channel[WRITE].devstat); + channel_free(m, ctc_adapter[m][i].devno[READ]); + channel_free(m, ctc_adapter[m][i].devno[WRITE]); + kfree(dev->priv); + kfree(dev); + } else + activated++; + } else { + kfree(dev); + cnt = MAX_ADAPTERS; + } + } while (cnt < MAX_ADAPTERS); + } + if (!activated) { + printk(KERN_WARNING "ctc: No devices registered\n"); + return -ENODEV; + } + return 0; +} +#endif -*/ /* --- This is the END my friend --- */ diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c --- v2.2.17/drivers/s390/net/iucv.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/s390/net/iucv.c Sat Dec 9 20:56:03 2000 @@ -1,1181 +1,2041 @@ /* * drivers/s390/net/iucv.c - * Network driver for VM using iucv + * Support for VM IUCV functions for use by other part of the + * kernel or loadable modules. * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Stefan Hegewald - * Hartmut Penner - * - * - * 2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * Martin Schwidefsky (schwidefsky@de.ibm.com) - * Alan Altmark (Alan_Altmark@us.ibm.com) - * - + * Copyright (C) 2000 IBM Corporation + * Author(s): Xenia Tkatschow (xenia@us.ibm.com) + * Alan Altmark (Alan_Altmark@us.ibm.com) */ -#ifndef __KERNEL__ -#define __KERNEL__ -#endif - #include -#include -#include /* printk() */ -#include /* kmalloc() */ -#include /* error codes */ -#include /* size_t */ -#include /* mark_bh */ -#include /* struct net_device, and other headers */ -#include /* struct net_device, and other headers */ -#include -#include -#include /* struct iphdr */ -#include /* struct tcphdr */ -#include +#include +#include #include -#include -#include +#include +#include +#include +#include "iucv.h" #include -#include #include +#include +#include -#include "iucv.h" - - - -#define DEBUG123 -#define MAX_DEVICES 10 - - -extern char _ascebc[]; - -/* - * global structures - */ -static char iucv_userid[MAX_DEVICES][8]; -static char iucv_ascii_userid[MAX_DEVICES][8]; -static int iucv_pathid[MAX_DEVICES] = {0}; -static unsigned char iucv_ext_int_buffer[40] __attribute__((aligned (8))) ={0}; -static unsigned char glob_command_buffer[40] __attribute__((aligned (8))); - -#if LINUX_VERSION_CODE>=0x20300 -typedef struct net_device net_device; -#else -typedef struct device net_device; -#endif -net_device iucv_devs[]; - - -/* This structure is private to each device. It is used to pass */ -/* packets in and out, so there is place for a packet */ -struct iucv_priv { - struct net_device_stats stats; - int packetlen; - int status; - u8 *packetdata; - int pathid; /* used device */ - unsigned char command_buffer[40] __attribute__((aligned (8))); - unsigned char ext_int_buffer[40] __attribute__((aligned (8))); - u8* receive_buffer; - int receive_buffer_len; - u8* send_buffer; - int send_buffer_len; - char * new_send_buf; /* send buffer ptr */ - unsigned char recv_buf[2048]; /* size is just a guess */ - unsigned char userid[8]; -}; - -struct iucv_header { - short len; -}; - - - -static __inline__ int netif_is_busy(net_device *dev) -{ -#if LINUX_VERSION_CODE<0x02032D - return(dev->tbusy); -#else - return(test_bit(LINK_STATE_XOFF,&dev->flags)); -#endif -} - - - -#if LINUX_VERSION_CODE<0x02032D -#define netif_enter_interrupt(dev) dev->interrupt=1 -#define netif_exit_interrupt(dev) dev->interrupt=0 -#define netif_start(dev) dev->start=1 -#define netif_stop(dev) dev->start=0 - -static __inline__ void netif_stop_queue(net_device *dev) -{ - dev->tbusy=1; -} - -static __inline__ void netif_start_queue(net_device *dev) -{ - dev->tbusy=0; -} - -static __inline__ void netif_wake_queue(net_device *dev) -{ - dev->tbusy=0; - mark_bh(NET_BH); -} - -#else -#define netif_enter_interrupt(dev) -#define netif_exit_interrupt(dev) -#define netif_start(dev) -#define netif_stop(dev) -#endif - - - -/* - * Following the iucv primitives - */ - - -extern inline void b2f0(int code,void* parm) -{ - asm volatile ("LR 1,%1\n\tLR 0,%0\n\t.long 0xb2f01000" :: - "d" (code) ,"a" (parm) :"0", "1"); -} - -int iucv_enable(void *parms) -{ - MASK_T *parm = parms; - memset(parms,0,sizeof(parm)); - parm->ipmask = 0xF8; - b2f0(SETMASK,parm); - memset(parms,0,sizeof(parm)); - parm->ipmask = 0xF8; - b2f0(SETCMASK,parm); - return parm->iprcode; -} - - -int iucv_declare_buffer(void *parms, DCLBFR_T *buffer) -{ - DCLBFR_T *parm = parms; - memset(parms,0,sizeof(parm)); - parm->ipflags1= 0x00; - parm->ipbfadr1 = virt_to_phys(buffer); - b2f0(DECLARE_BUFFER, parm); - return parm->iprcode; -} - - -int iucv_retrieve_buffer(void *parms) -{ - DCLBFR_T *parm = parms; - memset(parms,0x0,sizeof(parm)); - parm->iprcode = 0x0; - b2f0(RETRIEVE_BUFFER, parm); - return parm->iprcode; -} - - -int iucv_connect(void *parms, - const char *userid, - const char *host, - const char *ipusr, - unsigned short * used_pathid) -{ - CONNECT_T *parm = parms; /* ipflags was 0x60*/ - memset(parms,0x0,sizeof(parm)); - parm->ipflags1 = 0x80; - parm->ipmsglim = 0x0a; - memcpy(parm->ipvmid,userid,8); - if (ipusr) - memcpy(parm->ipuser,ipusr,16); - memcpy(parm->iptarget,host,8); - b2f0(CONNECT, parm); - *used_pathid = parm->ippathid; - return parm->iprcode; -} - - - -int iucv_accept(void *parms,int pathid) -{ -#ifdef DEBUG - int i=0; -#endif - ACCEPT_T *parm = parms; - memset(parms,0,sizeof(parm)); - parm->ippathid = pathid; - parm->ipflags1 = 0x80; - parm->ipmsglim = 0x0a; +#undef KERN_DEBUG +#define KERN_DEBUG KERN_EMERG +//#define DEBUG3 +//#define DEBUG /* Turns Printk's on */ +//#define DEBUG2 /* This prints the parameter list before and */ + /* after the b2f0 call to cp */ +#define EXPORT_SYMTAB +#include +#undef NULL +#define NULL 0 +#define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */ +ulong declare_flag = 0; +static uchar iucv_external_int_buffer[40]; +struct tq_struct short_task; /* automatically initialized to zero */ +static iucv_interrupt_ops_t my_ops; +spinlock_t lock = SPIN_LOCK_UNLOCKED; + +static void do_int (iucv_ConnectionPending *); + +/***************INTERRUPT HANDLING DEFINITIONS***************/ +typedef struct _iucv_packet { + struct _iucv_packet *next; + uchar data[40]; +} iucv_packet; +struct tq_struct short_task; +static spinlock_t iucv_packets_lock = SPIN_LOCK_UNLOCKED; +iucv_packet *iucv_packets_head, *iucv_packets_tail; + +static atomic_t bh_scheduled = ATOMIC_INIT (0); +void bottom_half_interrupt (void); + +/************FUNCTION ID'S****************************/ +#define accept 10 +#define connect 11 +#define declare_buffer 12 +#define purge 9 +#define query 0 +#define quiesc 13 +#define receive 5 +#define reject 8 +#define reply 6 +#define resume 14 +#define retrieve_buffer 2 +#define send 4 +#define setmask 16 +#define sever 15 + +/*****************************************************************/ +/* Structure: handler */ +/* members: next - is a pointer to next handler on chain */ +/* prev - is a pointer to prev handler on chain */ +/* vmid - 8 char array of machine identification */ +/* user_data - 16 char array for user identification */ +/* mask - 24 char array used to compare the 2 previous */ +/* interrupt_table - functions for interrupts */ +/* start - pointer to start of block of pointers to */ +/* handler_table_entries */ +/* end - pointer to end of block of pointers to */ +/* handler_table_entries */ +/* size - ulong, size of block */ +/* pgm_data - ulong, program data */ +/* NOTE: Keep vmid and user_data together in this order */ +/*****************************************************************/ +typedef struct { + ulong *next; + ulong *prev; + uchar vmid[8]; + uchar user_data[16]; + uchar mask[24]; + iucv_interrupt_ops_t *interrupt_table; + ulong *start; + ulong *end; + ulong size; + ulong pgm_data; +} handler; + +/*******************************************************************/ +/* Structure: handler_table_entry */ +/* members: addrs - pointer to a handler */ +/* pathid - ushort containing path identification */ +/* pgm_data - ulong, program data */ +/*******************************************************************/ +typedef struct { + handler *addrs; + ushort pathid; + ulong pgm_data; +} handler_table_entry; + +/* main_table: array of pointers to handler_tables */ +static handler_table_entry *main_table[128]; +/* handler_anchor: points to first handler on chain */ +static handler *handler_anchor; + +/****************FIVE STRUCTURES************************************/ +/* Data struct 1: iparml_control */ +/* Used for iucv_accept */ +/* iucv_connect */ +/* iucv_quiesce */ +/* iucv_resume */ +/* iucv_sever */ +/* iucv_retrieve_buffer */ +/* Data struct 2: iparml_dpl (data in parameter list) */ +/* Used for iucv_send_prmmsg */ +/* iucv_send2way_prmmsg */ +/* iucv_send2way_prmmsg_array */ +/* iucv_reply_prmmsg */ +/* Data struct 3: iparml_db (data in a buffer) */ +/* Used for iucv_receive */ +/* iucv_receive_array */ +/* iucv_receive_simple */ +/* iucv_reject */ +/* iucv_reply */ +/* iucv_reply_array */ +/* iucv_send */ +/* iucv_send_simple */ +/* iucv_send_array */ +/* iucv_send2way */ +/* iucv_send2way_array */ +/* iucv_declare_buffer */ +/* Data struct 4: iparml_purge */ +/* Used for iucv_purge */ +/* iucv_query */ +/* Data struct 5: iparml_set_mask */ +/* Used for iucv_set_mask */ +/********************************************************************/ +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iprcode; + ushort ipmsglim; + ushort res1; + uchar ipvmid[8]; + uchar ipuser[16]; + uchar iptarget[8]; +} iparml_control; + +/******************/ +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iprcode; + ulong ipmsgid; + ulong iptrgcls; + uchar iprmmsg[8]; + ulong ipsrccls; + ulong ipmsgtag; + ulong ipbfadr2; + ulong ipbfln2f; + ulong res; +} iparml_dpl; + +/*******************/ +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iprcode; + ulong ipmsgid; + ulong iptrgcls; + ulong ipbfadr1; + ulong ipbfln1f; + ulong ipsrccls; + ulong ipmsgtag; + ulong ipbfadr2; + ulong ipbfln2f; + ulong res; +} iparml_db; + +/********************/ +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iprcode; + ulong ipmsgid; + uchar ipaudit[4]; + uchar res1[4]; + ulong res2; + ulong ipsrccls; + ulong ipmsgtag; + ulong res3[3]; +} iparml_purge; + +/*******************/ +typedef struct { + uchar ipmask; + uchar res1[2]; + uchar iprcode; + ulong res2[9]; +} iparml_set_mask; + +/*********************INTERNAL FUNCTIONS*****************************/ +/********************************************************************/ +/* Name: b2f0 */ +/* Purpose: this function calls cp to execute iucv commands. */ +/* Input: code - int, identifier of iucv call to cp. */ +/* parm - void *, pointer to 40 byte iparml area passed to cp */ +/* Output: iprcode- return code from iucv call to cp */ +/********************************************************************/ +/* Assembler code performing iucv call */ +/*******************************************************************/ +inline ulong +b2f0 (int code, void *parm) +{ + uchar *iprcode; /* used to extract iprcode */ +#ifdef DEBUG2 + int i; + uchar *prt_parm; + prt_parm = (uchar *) (parm); + printk (KERN_DEBUG "parameter list before b2f0 call\n"); + for (i = 0; i < 40; i++) + printk (KERN_DEBUG "%02x ", prt_parm[i]); + printk (KERN_DEBUG "\n"); +#endif + asm volatile ("LRA 1,0(%1)\n\t" + "LR 0,%0\n\t" + ".long 0xb2f01000" + : : "d" (code), "a" (parm) : "0", "1"); +#ifdef DEBUG2 + printk (KERN_DEBUG "parameter list after b2f0 call\n"); + for (i = 0; i < 40; i++) + printk (KERN_DEBUG "%02x ", prt_parm[i]); + printk (KERN_DEBUG "\n"); +#endif + iprcode = (uchar *) (parm + 3); + return (ulong) (*iprcode); +} + +/**************************************************************/ +/* Name: iucv_retrieve_buffer */ +/* Purpose: terminates all use of iucv */ +/* Input: void */ +/* Output: Return code from CP */ +/**************************************************************/ +int +iucv_retrieve_buffer (void) +{ + iparml_control parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_retrieve_buffer\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + b2f0_result = b2f0 (retrieve_buffer, &parm); + if (b2f0_result == NULL) + declare_flag = 0; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_retrieve_buffer\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_declare_buffer */ +/* Purpose: specifies the guests real address of an external */ +/* interrupt. */ +/* Input: bfr - pointer to buffer */ +/* Output: iprcode - return code from b2f0 call */ +/* Note : See output options for b2f0 call */ +/**************************************************************/ +int +iucv_declare_buffer (uchar * bfr) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "Entering iucv_declare_buffer\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ipbfadr1 = virt_to_phys (bfr); + b2f0_result = b2f0 (declare_buffer, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "Address of EIB = %p\n", bfr); + printk (KERN_DEBUG "Exiting iucv_declare_buffer\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: add_pathid */ +/* Purpose: adds a path id to the system */ +/* Input: pathid - ushort, pathid to enter system */ +/* handle - iucv_handle_t, address of handler to add to */ +/* pgm_data - ulong, pathid identifier. */ +/* Output: 0: successful addition of pathid */ +/**************************************************************/ +int +add_pathid (ushort pathid, iucv_handle_t handle, ulong pgm_data) +{ + ulong index1, index2; /* index1 into main_table */ + ulong add_flag = 0; + ulong old_size = 0, new_size = 0; + uchar *to, *from; /* pointer for copying the table */ + handler_table_entry *P = 0; /*P is a pointer to H_T_E */ + handler *Q = 0; /*Q is a pointer to handler */ + ulong *X = 0; /*Points to array of pointers */ +#ifdef DEBUG + printk (KERN_DEBUG "entering add_pathid\n"); +#endif + Q = (handler *) handle; /* Q points to a handler */ + /* + * main_table has 128 entries. + * 128*512 = 65536 maximum number of pathid's allowed + */ + index1 = ((ulong) pathid) / 512; + index2 = ((ulong) pathid) % 512; +#ifdef DEBUG + printk (KERN_DEBUG "index1 = %d\n ", (int) index1); + printk (KERN_DEBUG "index2 = %d\n ", (int) index2); + printk (KERN_DEBUG "Q is pointing to %p ", Q); +#endif + spin_lock (&lock); + /* + * If NULL then handler table does not exist and need to get storage + * and have main_table[index1] point to it + * If allocating storage failed, return + */ + if (main_table[index1] == NULL) { + main_table[index1] = (handler_table_entry *) kmalloc + (512 * sizeof (handler_table_entry), GFP_KERNEL); + if (main_table[index1] == NULL) { + spin_unlock (&lock); + return -ENOBUFS; + } + memset (main_table[index1], 0, + 512 * sizeof (handler_table_entry)); #ifdef DEBUG - printk("iucv: iucv_accept input.\n"); - for (i=0;i<40; i++) - { - printk("%02x ",((char *)parms)[i]); - } - printk("\n"); + printk (KERN_DEBUG "address of table H_T is %p \n", + main_table[index1]); #endif - b2f0(ACCEPT, parm); - return parm->iprcode; -} - - - -int iucv_receive(void *parms,void *bufferarray,int len) -{ -#ifdef DEBUG - int i=0; + } + /* + * P points to a handler table entry (H_T_E) in which all entries in + * that structure should be NULL. If they're not NULL, then there + * is a bad pointer and it will return(-2) immediately, otherwise + * data will be entered into H_T_E. + */ + P = main_table[index1]; + if ((P + index2)->addrs) { +#ifdef DEBUG + printk (KERN_DEBUG "main_table[index1] = %p \n", + main_table[index1]); + printk (KERN_DEBUG "P+index2 = %p \n", P + index2); + printk (KERN_DEBUG "(P+index2)->addrs is %p \n", + (P + index2)->addrs); +#endif + spin_unlock (&lock); + printk (KERN_DEBUG "bad pointer1\n"); + return (-2); + } + (P + index2)->addrs = handle; + /* + * checking if address of handle is valid, if it's not valid, + * unlock the lock and return(-2) immediately. + */ + if ((P + index2)->addrs == NULL) { + spin_unlock (&lock); + printk (KERN_DEBUG "bad pointer2\n"); + return (-2); + } + (P + index2)->pathid = pathid; + if (pgm_data) + (P + index2)->pgm_data = pgm_data; + else + (P + index2)->pgm_data = Q->pgm_data; + /* + * Step thru the table of addresses of pathid's to find the first + * available entry (NULL). If an entry is found, add the pathid, + * unlock and exit. If an available entry is not found, allocate a + * new, larger table, copy over the old table and deallocate the + * old table and add the pathid. + */ +#ifdef DEBUG + printk (KERN_DEBUG "address of handle is %p\n", handle); + printk (KERN_DEBUG "&(Q->start) is %p\n", &(Q->start)); + printk (KERN_DEBUG "&(Q->end) is %p\n", &(Q->end)); + printk (KERN_DEBUG "start of pathid table is %p\n", (Q->start)); + printk (KERN_DEBUG "end of pathid table is %p\n", (Q->end)); + for (X = (Q->start); X < (Q->end); X++) + printk (KERN_DEBUG "X = %p ", X); + printk (KERN_DEBUG "\n"); +#endif + for (X = (Q->start); X < (Q->end); X++) { + if (*X == NULL) { +#ifdef DEBUG + printk (KERN_DEBUG "adding pathid, %p = P+index2\n", + (P + index2)); +#endif + *X = (ulong) (P + index2); + add_flag = 1; + } + if (add_flag == 1) + break; + } + if (add_flag == 0) { /* element not added to list */ + X = Q->start; + old_size = Q->size; + new_size = old_size + ADDED_STOR; /* size of new table */ + from = (uchar *) (Q->start); /* address of old table */ + (*Q).start = kmalloc (new_size * sizeof (ulong), GFP_KERNEL); + if ((Q->start) == NULL) { + spin_unlock (&lock); + return -ENOBUFS; + } + memset ((*Q).start, 0, new_size * sizeof (ulong)); + to = (uchar *) (Q->start); /* address of new table */ + /* copy old table to new */ + memcpy (to, from, old_size * (sizeof (ulong))); +#ifdef DEBUG + printk (KERN_DEBUG "Getting a new pathid table\n"); + printk (KERN_DEBUG "to is %p \n", to); + printk (KERN_DEBUG "from is %p \n", from); +#endif + Q->size = new_size; /* storing new size of table */ + Q->end = (Q->start) + (Q->size); + X = Q->start + old_size; /* next blank in table */ + *X = (ulong) (P + index2); /* adding element to new table */ +#ifdef DEBUG + printk (KERN_DEBUG "Q->size is %u \n", (int) (Q->size)); + printk (KERN_DEBUG "Q->end is %p \n", Q->end); + printk (KERN_DEBUG "Q->start is %p \n", Q->start); + printk (KERN_DEBUG "X is %p \n", X); + printk (KERN_DEBUG "*X is %u \n", (int) (*X)); #endif - RECEIVE_T *parm = parms; - memset(parms,0x0,sizeof(parm)); - /*parm->ipflags1 = 0x42;*/ - parm->ipflags1 = 0x0; - parm->ipmsgid = 0x0; - parm->iptrgcls = 0x0; - parm->ipbfadr1 = (ULONG) virt_to_phys(bufferarray); - parm->ipbfln1f = len; - parm->ipbfln2f = 0x0; - b2f0(RECEIVE, parm); - if (parm->iprcode == 0) - len = parm->ipbfln1f; -// len = len-parm->ipbfln1f; + kfree (from); /* free old table */ + } + spin_unlock (&lock); #ifdef DEBUG - printk("iucv: iucv_receive command input:\n"); - for (i=0;i<40;i++) /* show iucv buffer before send */ - { - printk("%02x ",((char *)parms)[i]); - } - printk("\n"); - - printk("iucv: iucv_receive data buffer:\n"); - for (i=0;iiprcode; -} - + return (0); +} /* end of add_pathid function */ -int iucv_send(void *parms,int pathid,void *bufferarray,int len, - void *recv_buf, int recv_len) -{ +/***********************EXTERNAL FUNCTIONS***************************/ +/**************************************************************/ +/* Name: iucv_query */ +/* Purpose: determines how large an external interrupt buffer */ +/* IUCV requires to store information */ +/* Input : bufsize - ulong: size of interrupt buffer */ +/* - filled in by function and returned to caller */ +/* conmax - ulong: maximum number of connections that */ +/* can be outstanding for this VM */ +/* - filled in by function and returned to caller */ +/* Output: void */ +/**************************************************************/ +void +iucv_query (ulong * bufsize, ulong * conmax) +{ + iparml_purge parm; /* DOESN'T MATTER WHICH IPARML IS USED */ +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_purge\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + /* + * Assembler instruction calling b2f0 and storing R0 and R1 + */ + asm volatile ("LRA 1,0(%3)\n\t" + "LR 0,%2\n\t" + ".long 0xb2f01000\n\t" + "ST 0,%0\n\t" + "ST 1,%1\n\t":"=m" (*bufsize), + "=m" (*conmax):"d" (query), "a" (&parm):"0", "1"); + return; +} + +/**************************************************************/ +/* Name: iucv_purge */ +/* Purpose: cancels a message you have sent */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong, mid of message */ +/* srccls - ulong, sourse message class */ +/* audit - uchar[4], info about ansync. error condit. */ +/* filled in by function and passed back */ +/* Output: void */ +/* NOTE: pathid is required, flag is always turned on */ +/**************************************************************/ +int +iucv_purge (ulong msgid, ushort pathid, ulong srccls, uchar audit[4]) +{ + iparml_purge parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_purge\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ipmsgid = msgid; + parm.ippathid = pathid; + parm.ipsrccls = srccls; + parm.ipflags1 |= specify_pathid; /* pathid id flag */ + if (parm.ipmsgid) + parm.ipflags1 |= specify_msgid; + if (parm.ipsrccls) + parm.ipflags1 |= source_class; + b2f0_result = b2f0 (purge, &parm); + if (b2f0_result != NULL) + return b2f0_result; + memcpy (audit, parm.ipaudit, 4); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_purge\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_quiesce */ +/* Purpose: temporarily suspends incoming messages */ +/* Input: pathid - ushort, pathid */ +/* user_data - uchar[16], user id */ +/* Output: iprcode - return code from b2f0 call */ +/* NOTE: see b2f0 output list */ +/**************************************************************/ +int +iucv_quiesce (ushort pathid, uchar user_data[16]) +{ + iparml_control parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_quiesce\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + memcpy (parm.ipuser, user_data, 16); + parm.ippathid = pathid; + b2f0_result = b2f0 (quiesc, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_quiesce\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_resume */ +/* Purpose: restores communication over a quiesced path */ +/* Input: pathid - ushort, pathid */ +/* user_data - uchar[16], user id */ +/* Output: iprcode - return code from b2f0 call */ +/* NOTE: see b2f0 output list */ +/**************************************************************/ +int +iucv_resume (ushort pathid, uchar user_data[16]) +{ + iparml_control parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_resume\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + memcpy (parm.ipuser, user_data, 16); + parm.ippathid = pathid; + b2f0_result = b2f0 (resume, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_resume\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_reject */ +/* Purpose: rejects a message */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong, mid of message */ +/* trgcls - ulong, target message class */ +/* Output: iprcode - return code from b2f0 call */ +/* NOTE: pathid is required field, flag always turned on */ +/* RESTRICTION: target class cannot be zero */ +/* NOTE: see b2f0 output list */ +/**************************************************************/ +int +iucv_reject (ushort pathid, ulong msgid, ulong trgcls) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_reject\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ipmsgid = msgid; + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipflags1 |= specify_pathid; /* flag for pathid */ + if (parm.ipmsgid) + parm.ipflags1 |= specify_msgid; + if (parm.iptrgcls) + parm.ipflags1 |= target_class; + b2f0_result = b2f0 (reject, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_reject\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_setmask */ +/* Purpose: enables or disables certain iucv external interr. */ +/* Input: non_priority_interrupts - uchar */ +/* priority_interrupts - uchar */ +/* non_priority_completion_interrupts - uchar */ +/* priority_completion_interrupts) - uchar */ +/* Output: iprcode - return code from b2f0 call */ +/* NOTE: see b2f0 output list */ +/**************************************************************/ +int +iucv_setmask (uchar non_priority_interrupts, + uchar priority_interrupts, + uchar non_priority_completion_interrupts, + uchar priority_completion_interrupts) +{ + iparml_set_mask parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_setmask\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + if (non_priority_interrupts) + parm.ipmask |= 0x80; + if (priority_interrupts) + parm.ipmask |= 0x40; + if (non_priority_completion_interrupts) + parm.ipmask |= 0x20; + if (priority_completion_interrupts) + parm.ipmask |= 0x10; + b2f0_result = b2f0 (setmask, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_setmask\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_sever */ +/* Purpose: terminates an iucv path to another machine */ +/* Input: pathid - ushort, pathid */ +/* user_data - uchar[16], user id */ +/* Output: iprcode - return code from b2f0 call */ +/* NOTE: see b2f0 output list */ +/**************************************************************/ +int +iucv_sever (ushort pathid, uchar user_data[16]) +{ + ulong index1, index2; + ulong b2f0_result; + handler_table_entry *P = 0; + handler *Q = 0; + ulong *X; + iparml_control parm; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_sever\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + memcpy (parm.ipuser, user_data, 16); + parm.ippathid = pathid; + b2f0_result = b2f0 (sever, &parm); + if (b2f0_result) + return b2f0_result; + index1 = ((ulong) pathid) / 512; + index2 = ((ulong) pathid) % 512; + spin_lock (&lock); + P = main_table[index1]; + if (((P + index2)->addrs) == NULL) { /* called from interrupt code */ + spin_unlock (&lock); + return (-2); /* bad pointer */ + } + Q = (*(P + index2)).addrs; #ifdef DEBUG - int i=0; -#endif - SEND_T *parm = parms; - memset(parms,0x0,sizeof(parm)); - /* parm->ipflags1 = 0x48; ??*/ - parm->ippathid = pathid; - parm->ipflags1 = 0x14; /* any options ?? */ - parm->ipmsgid = 0x0; - parm->iptrgcls = 0x0; - parm->ipbfadr1 = virt_to_phys(bufferarray); - parm->ipbfln1f = len; - parm->ipsrccls = 0x0; - parm->ipmsgtag = 0x0; - parm->ipbfadr2 = virt_to_phys(recv_buf); - parm->ipbfln2f = recv_len; - - + printk (KERN_DEBUG "pathid is %d\n", pathid); + printk (KERN_DEBUG "index1 is %d\n", (int) index1); + printk (KERN_DEBUG "index2 is %d\n", (int) index2); + printk (KERN_DEBUG "H_T_E is %p\n", P); + printk (KERN_DEBUG "address of handler is %p\n", Q); + for (X = ((*Q).start); X < ((*Q).end); X++) + printk (KERN_DEBUG " %x ", (int) (*X)); + printk (KERN_DEBUG "\n above is pathid table\n"); +#endif +/********************************************************************/ +/* Searching the pathid address table for matching address, once */ +/* found, NULL the field. Then Null the H_T_E fields. */ +/********************************************************************/ + for (X = ((*Q).start); X < ((*Q).end); X++) + if (*X == (ulong) (P + index2)) { +#ifdef DEBUG + printk (KERN_DEBUG "found a path to sever\n"); + printk (KERN_DEBUG "severing %d \n", (int) (*X)); +#endif + *X = NULL; + (*(P + index2)).addrs = NULL; /*clearing the fields */ + (*(P + index2)).pathid = 0; + (*(P + index2)).pgm_data = 0; + } + spin_unlock (&lock); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_sever\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_receive */ +/* Purpose: receives incoming message */ +/* Input: pathid - ushort, pathid */ +/* msgid - *ulong, mid of message */ +/* trgcls - *ulong, target message class */ +/* buffer - pointer of buffer */ +/* buflen - length of buffer */ +/* adds_curr_buffer - pointer to updated buffer address*/ +/* to write to */ +/* adds_curr_length - pointer to updated length in */ +/* buffer available to write to */ +/* reply_required - uchar *, flag */ +/* priority_msg - uchar *, flag */ +/* Output: iprcode - return code from b2f0 call */ +/* NOTE: pathid must be specified, flag being turned on */ +/* RESTRICTIONS: target class CANNOT be zero because the code */ +/* checks for a non-NULL value to turn flag on, therefore if */ +/* target class = zero, flag will not be turned on. */ +/**************************************************************/ +int +iucv_receive (ushort pathid, ulong * msgid, ulong * trgcls, + void *buffer, ulong buflen, + uchar * reply_required, + uchar * priority_msg, + ulong * adds_curr_buffer, ulong * adds_curr_length) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_receive\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ipmsgid = *msgid; + parm.ippathid = pathid; + parm.iptrgcls = *trgcls; + parm.ipflags1 |= specify_pathid; /* turning pathid flag */ + if (parm.ipmsgid) + parm.ipflags1 |= 0x05; + if (parm.iptrgcls) + parm.ipflags1 |= target_class; + parm.ipbfadr1 = (ulong) buffer; + parm.ipbfln1f = buflen; + b2f0_result = b2f0 (receive, &parm); + if (b2f0_result) + return b2f0_result; + if (msgid) + *msgid = parm.ipmsgid; + if (trgcls) + *trgcls = parm.iptrgcls; + if (parm.ipflags1 & prior_msg) + if (priority_msg) + *priority_msg = 0x01; /*yes, priority msg */ + if (!(parm.ipflags1 & 0x10)) /*& with X'10' */ + if (reply_required) + *reply_required = 0x01; /*yes, reply required */ + if (!(parm.ipflags1 & parm_data)) { /*msg not in parmlist */ + if (adds_curr_length) + *adds_curr_length = parm.ipbfln1f; + if (adds_curr_buffer) + *adds_curr_buffer = parm.ipbfadr1; + } else { + if ((buflen) >= 8) { + if (buffer) + memcpy ((char *) buffer, + (char *) parm.ipbfadr1, 8); + if (adds_curr_length) + *adds_curr_length = ((buflen) - 8); + if (adds_curr_buffer) + *adds_curr_buffer = (ulong) buffer + 8; + } else { + parm.iprcode |= 0x05; + b2f0_result = (ulong) parm.iprcode; + } + } #ifdef DEBUG - printk("iucv: iucv_send command input:\n"); - for (i=0;i<40;i++) /* show iucv buffer before send */ - { - printk("%02x ",((char *)parms)[i]); - } - printk("\n"); - - printk("iucv: iucv_send data buffer:\n"); - for (i=0;iiprcode; -} - - - -int iucv_sever(void *parms) -{ - SEVER_T *parm = parms; - memset(parms,0x0,sizeof(parm)); - parm->ippathid = 0x0; - parm->ipflags1 = 0x0; - parm->iprcode = 0xF; - memset(parm->ipuser,0,16); - b2f0(SEVER, parm); - return parm->iprcode; + return b2f0_result; } - -#ifdef DEBUG -/*--------------------------*/ -/* Dump buffer formatted */ -/*--------------------------*/ -static void dumpit(char* buf, int len) -{ - int i; - for (i=0;ipriv); - if (memcmp(privptr->userid,userid,8)==0) - return &iucv_devs[i]; - } - printk("iucv: get_device_from_uid: no device for userid %s\n",userid); - return 0; +/**************************************************************/ +/* Name: iucv_receive_simple */ +/* Purpose: receives fully-qualified message */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong, id of message */ +/* trgcls - ulong, target message class */ +/* buffer - pointer of buffer */ +/* buflen - length of buffer */ +/* Output: iprcode - return code from b2f0 call */ +/**************************************************************/ +int +iucv_receive_simple (ushort pathid, ulong msgid, ulong trgcls, + void *buffer, ulong buflen) +{ + iparml_db parm; + ulong b2f0_result; + pr_debug ("entering iucv_receive_simple\n"); + + memset (&(parm), 0, sizeof (parm)); + parm.ipmsgid = msgid; + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipflags1 = IPFGMID + IPFGPID + IPFGMCL; + parm.ipbfadr1 = (ulong) buffer; + parm.ipbfln1f = buflen; + + b2f0_result = b2f0 (receive, &parm); + if (b2f0_result) + return b2f0_result; + + if (parm.ipflags1 & IPRMDATA) { /*msg in parmlist */ + if ((buflen) >= 8) + memcpy ((char *) buffer, (char *) parm.ipbfadr1, 8); + else + b2f0_result = 5; + } + pr_debug ("exiting iucv_receive_simple\n"); + return b2f0_result; } - -/*--------------------------*/ -/* Open iucv Device Driver */ -/*--------------------------*/ -int iucv_open(net_device *dev) -{ - int rc; - unsigned short iucv_used_pathid; - struct iucv_priv *privptr; - char iucv_host[8] ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - char vmident[16] ={0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40}; - -#ifdef DEBUG - printk( "iucv: iucv_open, device: %s\n",dev->name); -#endif - - privptr = (struct iucv_priv *)(dev->priv); - if(privptr->pathid != -1) { - netif_start(dev); - netif_start_queue(dev); - return 0; - } - if ((rc = iucv_connect(privptr->command_buffer, - privptr->userid, - iucv_host, - vmident, - &iucv_used_pathid))!=0) { - printk( "iucv: iucv connect failed with rc %X\n",rc); - iucv_retrieve_buffer(privptr->command_buffer); - return -ENODEV; - } - - privptr->pathid = iucv_used_pathid; - iucv_pathid[dev-iucv_devs]=privptr->pathid; - +/**************************************************************/ +/* Name: iucv_receive_array */ +/* Purpose: receives incoming message */ +/* Input: pathid - ushort, pathid */ +/* msgid -* ulong, mid of message */ +/* trgcls -* ulong, target message class */ +/* buffer - pointer of iucv_array_t */ +/* buflen - ulong , length of buffer */ +/* reply_required - uchar *, flag returned to caller */ +/* priority_msg - uchar *, flag returned to caller */ +/* adds_curr_buffer - pointer to updated buffer array */ +/* to write to */ +/* adds_curr_length - pointer to updated length in */ +/* buffer available to write to */ +/* Output: iprcode - return code from b2f0 call */ +/* NOTE: pathid must be specified, flag being turned on */ +/* RESTRICTIONS: target class CANNOT be zero because the code */ +/* checks for a non-NULL value to turn flag on, therefore if */ +/* target class = if target class = zero flag will not be */ +/* turned on, therefore if target class is specified it cannot */ +/* be zero. */ +/**************************************************************/ +int +iucv_receive_array (ushort pathid, ulong * msgid, ulong * trgcls, + iucv_array_t * buffer, ulong * buflen, + uchar * reply_required, + uchar * priority_msg, + ulong * adds_curr_buffer, ulong * adds_curr_length) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_receive_array\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ipmsgid = *msgid; + parm.ippathid = pathid; + parm.iptrgcls = *trgcls; + parm.ipflags1 |= array; /* using an address list */ + parm.ipflags1 |= specify_pathid; /*turning on pathid flag */ + if (parm.ipmsgid) + parm.ipflags1 |= 0x05; + if (parm.iptrgcls) + parm.ipflags1 |= target_class; + parm.ipbfadr1 = (ulong) buffer; + parm.ipbfln1f = *buflen; + b2f0_result = b2f0 (receive, &parm); + if (b2f0_result) + return b2f0_result; + if (msgid) + *msgid = parm.ipmsgid; + if (trgcls) + *trgcls = parm.iptrgcls; + if (parm.ipflags1 & prior_msg) + if (priority_msg) + *priority_msg = 0x01; /*yes, priority msg */ + if (!(parm.ipflags1 & 0x10)) /*& with X'10' */ + if (reply_required) + *reply_required = 0x01; /*yes, reply required */ + if (!(parm.ipflags1 & parm_data)) { /*msg not in parmlist */ + if (adds_curr_length) + *adds_curr_length = parm.ipbfln1f; + if (adds_curr_buffer) + *adds_curr_buffer = parm.ipbfadr1; + } else { + if ((buffer->length) >= 8) { + memcpy ((char *) buffer->address, + (char *) parm.ipbfadr1, 8); + if (adds_curr_buffer) + *adds_curr_buffer = + (ulong) ((buffer->address) + 8); + if (adds_curr_length) + *adds_curr_length = ((buffer->length) - 8); + + } else { + parm.iprcode |= 0x05; + b2f0_result = (ulong) parm.iprcode; + } + } #ifdef DEBUG - printk( "iucv: iucv_connect ended with rc: %X\n",rc); - printk( "iucv[%d] pathid %X \n",(int)(dev-iucv_devs),privptr->pathid); + printk (KERN_DEBUG "exiting iucv_receive\n"); #endif - netif_start(dev); - netif_start_queue(dev); - return 0; + return b2f0_result; } - - -/*-----------------------------------------------------------------------*/ -/* Receive a packet: retrieve, encapsulate and pass over to upper levels */ -/*-----------------------------------------------------------------------*/ -void iucv_rx(net_device *dev, int len, unsigned char *buf) -{ - - struct sk_buff *skb; - struct iucv_priv *privptr = (struct iucv_priv *)dev->priv; - -#ifdef DEBUG - printk( "iucv: iucv_rx len: %X, device %s\n",len,dev->name); - printk( "iucv rx: received orig:\n"); - dumpit(buf,len); -#endif - - /* strip iucv header now */ - len = len - 2; /* short header */ - buf = buf + 2; /* short header */ - - skb = dev_alloc_skb(len+2); /* why +2 ? alignment ? */ - if (!skb) { - printk( "iucv rx: low on mem, returning...\n"); - return; - } - skb_reserve(skb, 2); /* align IP on 16B boundary*/ - memcpy(skb_put(skb, len), buf, len); -#ifdef DEBUG - printk( "iucv rx: data before netif_rx()\n"); - dumpit(buf,len); -#endif - - /* Write metadata, and then pass to the receive level */ - skb->mac.raw = skb->data; - skb->pkt_type = PACKET_HOST; - skb->dev = dev; - skb->protocol = htons(ETH_P_IP); - skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it*/ - privptr->stats.rx_packets++; - netif_rx(skb); - - return; -} /* end iucv_rx() */ - - - - -/*----------------------------*/ -/* handle interrupts */ -/*----------------------------*/ -void do_iucv_interrupt(struct pt_regs *regs, __u16 code) -{ - int rc; - struct in_device *indev; - struct in_ifaddr *inaddr; - unsigned long len=0; - net_device *dev=0; - struct iucv_priv *privptr; - INTERRUPT_T * extern_int_buffer; - unsigned short iucv_data_len=0; - unsigned short iucv_next=0; - unsigned char * rcvptr; - - /* get own buffer: */ - extern_int_buffer = (INTERRUPT_T*) iucv_ext_int_buffer; - -#ifdef DEBUG - printk( "iucv: do_iucv_interrupt %x received; pathid: %02X\n", - extern_int_buffer->iptype,extern_int_buffer->ippathid); - printk( "iucv: extern_int_buffer:\n"); - dumpit((char *)&extern_int_buffer[0],40); -#endif - - if (extern_int_buffer->iptype == 0x01) - dev = get_device_from_userid(&((char*) extern_int_buffer)[8]); - else - dev = get_device_from_pathid(extern_int_buffer->ippathid); - - netif_enter_interrupt(dev); /* lock ! */ - privptr = (struct iucv_priv *)(dev->priv); - - switch (extern_int_buffer->iptype) - { - case 0x01: /* connection pending ext interrrupt */ -#ifdef DEBUG - printk( "iucv: connection pending IRQ.\n"); -#endif - - rc = iucv_accept(glob_command_buffer, - extern_int_buffer->ippathid); - if (rc != 0) { - printk( "iucv: iucv_accept failed with rc: %X\n",rc); - iucv_retrieve_buffer(glob_command_buffer); - break; - } - - privptr->pathid = extern_int_buffer->ippathid; - -#ifdef DEBUG - printk( "iucv: iucv_accept ended with rc: %X\n",rc); - printk( "iucv: device %s found.\n",dev->name); -#endif - break; - - case 0x02: /* connection completed ext interrrupt */ - /* set own global IP address */ - /* & set global routing addr */ -#ifdef DEBUG - printk( "connection completed.\n"); -#endif - - if( extern_int_buffer->ipmsgtag !=0) - { - /* get ptr's to kernel struct with local & broadcast address */ - indev = dev->ip_ptr; - inaddr = (struct in_ifaddr*) indev->ifa_list; +/**************************************************************/ +/* Name: iucv_send */ +/* Purpose: sends messages */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong *, id of message returned to caller */ +/* trgcls - ulong, target message class */ +/* srccls - ulong, source message class */ +/* msgtag - ulong, message tag */ +/* priority_msg - uchar, flag */ +/* buffer - pointer to buffer */ +/* buflen - ulong, length of buffer */ +/* Output: iprcode - return code from b2f0 call */ +/* msgid - returns message id */ +/**************************************************************/ +int +iucv_send (ushort pathid, ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, uchar priority_msg, void *buffer, ulong buflen) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_send\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipbfadr1 = (ulong) buffer; + parm.ipbfln1f = buflen; /* length of message */ + parm.ipsrccls = srccls; + parm.ipmsgtag = msgtag; + parm.ipflags1 |= one_way_msg; /* one way message */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + b2f0_result = b2f0 (send, &parm); + if (b2f0_result) + return b2f0_result; + if (msgid) + *msgid = parm.ipmsgid; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_send\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_send_array */ +/* Purpose: sends messages in buffer array */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong *, id of message returned to caller */ +/* trgcls - ulong, target message class */ +/* srccls - ulong, source message class */ +/* msgtag - ulong, message tag */ +/* priority_msg - uchar, flag */ +/* buffer - pointer to iucv_array_t */ +/* buflen - ulong, length of buffer */ +/* Output: iprcode - return code from b2f0 call */ +/* msgid - returns message id */ +/**************************************************************/ +int +iucv_send_array (ushort pathid, ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, uchar priority_msg, + iucv_array_t * buffer, ulong buflen) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_send_array\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipbfadr1 = (ulong) buffer; + parm.ipbfln1f = buflen; /* length of message */ + parm.ipsrccls = srccls; + parm.ipmsgtag = msgtag; + parm.ipflags1 |= one_way_msg; /* one way message */ + parm.ipflags1 |= array; /* one way w/ array */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + b2f0_result = b2f0 (send, &parm); + if (msgid) + *msgid = parm.ipmsgid; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_send_array\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_send_prmmsg */ +/* Purpose: sends messages in parameter list */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong *, id of message */ +/* trgcls - ulong, target message class */ +/* srccls - ulong, source message class */ +/* msgtag - ulong, message tag */ +/* priority_msg - uchar, flag */ +/* prmmsg - uchar[8], message being sent */ +/* Output: iprcode - return code from b2f0 call */ +/* msgid - returns message id */ +/**************************************************************/ +int +iucv_send_prmmsg (ushort pathid, ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, uchar priority_msg, uchar prmmsg[8]) +{ + iparml_dpl parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_send_prmmsg\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipsrccls = srccls; + parm.ipmsgtag = msgtag; + parm.ipflags1 |= parm_data; /* message in prmlist */ + parm.ipflags1 |= one_way_msg; /* one way message */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + memcpy (parm.iprmmsg, prmmsg, 8); + b2f0_result = b2f0 (send, &parm); + if (msgid) + *msgid = parm.ipmsgid; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_send_prmmsg\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_send2way */ +/* Purpose: sends messages in both directions */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong *, id of message */ +/* trgcls - ulong, target message class */ +/* srccls - ulong, source message class */ +/* msgtag - ulong, message tag */ +/* priority_msg - uchar, flag */ +/* buffer - pointer to buffer */ +/* buflen - ulong, length of buffer */ +/* ansbuf - pointer to buffer on reply */ +/* anslen - length of ansbuf buffer */ +/* Output: iprcode - return code from b2f0 call */ +/* msgid - returns message id */ +/**************************************************************/ +int +iucv_send2way (ushort pathid, ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, uchar priority_msg, + void *buffer, ulong buflen, void *ansbuf, ulong anslen) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_send2way\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipbfadr1 = (ulong) buffer; + parm.ipbfln1f = buflen; /* length of message */ + parm.ipbfadr2 = (ulong) ansbuf; + parm.ipbfln2f = anslen; + parm.ipsrccls = srccls; + parm.ipmsgtag = msgtag; + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + b2f0_result = b2f0 (send, &parm); + if (msgid) + *msgid = parm.ipmsgid; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_send2way\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_send2way_array */ +/* Purpose: sends messages in both directions in arrays */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong *, id of message */ +/* trgcls - ulong, target message class */ +/* srccls - ulong, source message class */ +/* msgtag - ulong, message tag */ +/* priority_msg - uchar, flag */ +/* buffer - pointer to iucv_array_t */ +/* buflen - ulong, length of buffer */ +/* ansbuf - pointer to iucv_array_t on reply */ +/* anslen - length of ansbuf buffer */ +/* Output: iprcode - return code from b2f0 call */ +/* msgid - returns message id */ +/**************************************************************/ +int +iucv_send2way_array (ushort pathid, ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, uchar priority_msg, + iucv_array_t * buffer, ulong buflen, + iucv_array_t * ansbuf, ulong anslen) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_send2way_array\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipbfadr1 = (ulong) buffer; + parm.ipbfln1f = buflen; /* length of message */ + parm.ipbfadr2 = (ulong) ansbuf; + parm.ipbfln2f = anslen; + parm.ipsrccls = srccls; + parm.ipmsgtag = msgtag; + parm.ipflags1 |= array; /* send w/ array */ + parm.ipflags1 |= reply_array; /* reply w/ array */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + b2f0_result = b2f0 (send, &parm); + if (msgid) + *msgid = parm.ipmsgid; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_send2way_array\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_send2way_prmmsg */ +/* Purpose: sends messages in both directions w/parameter lst */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong *, id of message */ +/* trgcls - ulong, target message class */ +/* srccls - ulong, source message class */ +/* msgtag - ulong, message tag */ +/* priority_msg - uchar, flag */ +/* prmmsg - uchar[8], message being sent in parameter */ +/* ansbuf - pointer to buffer */ +/* anslen - length of ansbuf buffer */ +/* Output: iprcode - return code from b2f0 call */ +/* msgid - returns message id */ +/**************************************************************/ +int +iucv_send2way_prmmsg (ushort pathid, ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, uchar priority_msg, + uchar prmmsg[8], void *ansbuf, ulong anslen) +{ + iparml_dpl parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipsrccls = srccls; + parm.ipmsgtag = msgtag; + parm.ipbfadr2 = (ulong) ansbuf; + parm.ipbfln2f = anslen; + parm.ipflags1 |= parm_data; /* message in prmlist */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + memcpy (parm.iprmmsg, prmmsg, 8); + b2f0_result = b2f0 (send, &parm); + if (msgid) + *msgid = parm.ipmsgid; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_reply */ +/* Purpose: responds to the two-way messages that you receive */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong, id of message */ +/* trgcls - ulong, target message class */ +/* priority_msg - uchar, flag */ +/* buf - pointer, address of buffer */ +/* buflen - length of buffer */ +/* Output: iprcode - return code from b2f0 call */ +/**************************************************************/ +int +iucv_reply (ushort pathid, ulong msgid, ulong trgcls, + uchar priority_msg, void *buf, ulong buflen) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_reply\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.ipmsgid = msgid; + parm.iptrgcls = trgcls; + parm.ipbfadr2 = (ulong) buf; + parm.ipbfln2f = buflen; /* length of message */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + b2f0_result = b2f0 (reply, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_reply\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_reply_array */ +/* Purpose: responds to the two-way messages that you receive */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong, id of message */ +/* trgcls - ulong, target message class */ +/* priority_msg - uchar, flag */ +/* buf - pointer, address of array */ +/* buflen - length of buffer */ +/* Output: iprcode - return code from b2f0 call */ +/**************************************************************/ +int +iucv_reply_array (ushort pathid, ulong msgid, ulong trgcls, + uchar priority_msg, iucv_array_t * buffer, ulong buflen) +{ + iparml_db parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_reply_array\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.ipmsgid = msgid; + parm.iptrgcls = trgcls; + parm.ipbfadr2 = (ulong) buffer; + parm.ipbfln2f = buflen; /* length of message */ + parm.ipflags1 |= reply_array; /* reply w/ array */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + b2f0_result = b2f0 (reply, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_reply_array\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_reply_prmmsg */ +/* Purpose: responds to the two-way messages in parameter list */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong, id of message */ +/* trgcls - ulong, target message class */ +/* priority_msg - uchar, flag */ +/* prmmsg - uchar[8], message in parameter list */ +/* Output: iprcode - return code from b2f0 call */ +/**************************************************************/ +int +iucv_reply_prmmsg (ushort pathid, ulong msgid, ulong trgcls, + uchar priority_msg, uchar prmmsg[8]) +{ + iparml_dpl parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_reply_prmmsg\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.ipmsgid = msgid; + parm.iptrgcls = trgcls; + memcpy (parm.iprmmsg, prmmsg, 8); + parm.ipflags1 |= parm_data; + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + b2f0_result = b2f0 (reply, &parm); +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_reply_prmmsg\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_connect */ +/* Purpose: establishes an IUCV path to another vm */ +/* Input: pathid - ushort *, pathid returned to user */ +/* msglim - ushort, limit of outstanding messages */ +/* user_data - uchar[16], user data */ +/* userid - uchar[8], user's id */ +/* system_name - uchar[8], system identification */ +/* priority_requested - uchar- flag */ +/* prmdata - uchar, flag prgrm can handler messages */ +/* in parameter list */ +/* quiesce - uchar, flag to quiesce a path being establ */ +/* control - uchar, flag, option not used */ +/* local - uchar, flag, establish connection only on */ +/* local system */ +/* priority_permitted - uchar *, flag returned to user */ +/* handle - address of handler */ +/* pgm_data - ulong */ +/* Output: iprcode - return code from b2f0 call */ +/**************************************************************/ +int +iucv_connect (ushort * pathid, ushort msglim, uchar user_data[16], + uchar userid[8], uchar system_name[8], + uchar priority_requested, uchar prmdata, + uchar quiesce, uchar control, + uchar local, uchar * priority_permitted, + iucv_handle_t handle, ulong pgm_data) +{ + iparml_control parm; + ulong b2f0_result; + int add_pathid_result, rc; + handler *R; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_connect\n"); +#endif + memset (&parm, 0, sizeof (parm)); + if (declare_flag == NULL) { + rc = iucv_declare_buffer (iucv_external_int_buffer); + if (rc) { + printk (KERN_DEBUG "IUCV: registration failed\n"); +#ifdef DEBUG + printk (KERN_DEBUG "rc from declare buffer is: %i\n", + rc); +#endif + return rc; + } else + declare_flag = 1; } - break; - - - case 0x03: /* connection severed ext interrrupt */ - /* we do not handle this one at this time */ -#ifdef DEBUG - printk( "connection severed.\n"); -#endif - break; - - - case 0x04: /* connection quiesced ext interrrupt */ - /* we do not handle this one at this time */ -#ifdef DEBUG - printk( "connection quiesced.\n"); -#endif - break; - - - case 0x05: /* connection resumed ext interrrupt */ - /* we do not handle this one at this time */ + /* Checking if handle is valid */ + spin_lock (&lock); + for (R = handler_anchor; R != NULL; R = (handler *) R->next) + if (R == handle) + break; + if (R == NULL) { + spin_unlock (&lock); #ifdef DEBUG - printk( "connection resumed.\n"); + printk (KERN_DEBUG "iucv_connect: Invalid Handle\n"); #endif - break; - - - case 0x06: /* priority message complete ext interrupt */ - case 0x07: /* non priority message complete ext interrupt */ - /* send it to iucv_rx for handling */ -#ifdef DEBUG - printk( "message completed.\n"); -#endif - - if (extern_int_buffer->ipaudit ==0) /* ok case */ - { + return (-2); + } + if (pathid == NULL) { + spin_unlock (&lock); #ifdef DEBUG - printk( "iucv: msg complete interrupt successful, rc: %X\n", - (unsigned int)extern_int_buffer->ipaudit); + printk (KERN_DEBUG "iucv_connect: invalid pathid pointer\n"); #endif - ; + return (-3); } - else - { - printk( "iucv: msg complete interrupt error, rc: %X\n", - (unsigned int)extern_int_buffer->ipaudit); + spin_unlock (&lock); + parm.ipmsglim = msglim; + memcpy (parm.ipuser, user_data, 16); + memcpy (parm.ipvmid, userid, 8); + memcpy (parm.iptarget, system_name, 8); + if (parm.iptarget) + ASCEBC (parm.iptarget, 8); + if (parm.ipvmid) { + ASCEBC (parm.ipvmid, 8); + EBC_TOUPPER(parm.ipvmid, 8); } - /* a transmission is over: tell we are no more busy */ - privptr->stats.tx_packets++; - netif_wake_queue(dev); /* transmission is no longer busy*/ - break; - - - case 0x08: /* priority message pending */ - case 0x09: /* non priority message pending */ -#ifdef DEBUG - printk( "message pending.\n"); -#endif - rcvptr = &privptr->receive_buffer[0]; - - /* re-set receive buffer */ - memset(privptr->receive_buffer,0,privptr->receive_buffer_len); - len = privptr->receive_buffer_len; - - /* get data now */ - if (extern_int_buffer->ipflags1 & 0x80) - { /* data is in the message */ + if (priority_requested) + parm.ipflags1 |= prior_msg; + if (prmdata) + parm.ipflags1 |= parm_data; /*data in parameter list */ + if (quiesce) + parm.ipflags1 |= quiesce_msg; + if (control) { + /* do nothing at the time being */ + /*control not provided yet */ + } + if (local) + parm.ipflags1 |= local_conn; /*connect on local system */ + b2f0_result = b2f0 (connect, &parm); + if (b2f0_result) + return b2f0_result; + add_pathid_result = add_pathid (parm.ippathid, handle, pgm_data); + if (add_pathid_result) { #ifdef DEBUG - printk( "iucv: iucv_receive data is in header!\n"); + printk (KERN_DEBUG "iucv_connect: add_pathid failed \n"); #endif - memcpy(privptr->receive_buffer, - (char *)extern_int_buffer->iprmmsg1, - (unsigned long)(extern_int_buffer->iprmmsg2)); - } - else /* data is in buffer, do a receive */ - { - rc = iucv_receive(privptr->command_buffer,rcvptr,len); - if (rc != 0 || len == 0) - { - printk( "iucv: iucv_receive failed with rc: %X, length: %lX\n",rc,len); - iucv_retrieve_buffer(privptr->command_buffer); - break; - } - } /* end else */ - - iucv_next = 0; - /* get next packet offset */ - iucv_data_len= *((unsigned short*)rcvptr); - do{ /* until receive buffer is empty, i.e. iucv_next == 0 ! */ + return (add_pathid_result); + } + *pathid = parm.ippathid; + if (parm.ipflags1 & prior_msg) + if (priority_permitted) + *priority_permitted = 0x01; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_connect\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_accept */ +/* Purpose: completes the iucv communication path */ +/* Input: pathid - ushort , pathid */ +/* msglim - ushort, limit of outstanding messages */ +/* user_data - uchar[16], user data */ +/* priority_requested - uchar- flag */ +/* prmdata - uchar, flag prgrm can handler messages */ +/* in parameter list */ +/* quiesce - uchar, flag to quiesce a path being establ*/ +/* control - uchar, flag, option not used */ +/* priority_permitted -uchar *, flag returned to caller*/ +/* handle - address of handler */ +/* pgm_data - ulong */ +/* Output: iprcode - return code from b2f0 call */ +/**************************************************************/ +int +iucv_accept (ushort pathid, ushort msglim, uchar user_data[16], + uchar priority_requested, + uchar prmdata, uchar quiesce, uchar control, + uchar * priority_permitted, iucv_handle_t handle, ulong pgm_data) +{ + ulong index1, index2; + handler_table_entry *P = 0; + iparml_control parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_accept\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.ipmsglim = msglim; + memcpy (parm.ipuser, user_data, 16); + if (priority_requested) + parm.ipflags1 |= prior_msg; + if (prmdata) + parm.ipflags1 |= parm_data; /*data in parameter list */ + if (quiesce) + parm.ipflags1 |= quiesce_msg; + if (control) { + /* do nothing at the time being */ + /*control not provided yet */ + } + b2f0_result = b2f0 (accept, &parm); + if (b2f0_result) + return b2f0_result; + index1 = ((ulong) pathid) / 512; + index2 = ((ulong) pathid) % 512; + spin_lock (&lock); + if (pgm_data) { + P = main_table[index1]; + (P + index2)->pgm_data = pgm_data; + } + spin_unlock (&lock); + if (parm.ipflags1 & prior_msg) + if (priority_permitted) + *priority_permitted = 0x01; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_accept\n"); +#endif + return b2f0_result; +} + +/**************************************************************/ +/* Name: iucv_send2way_prmmsg_array */ +/* Purpose: sends messages in both directions w/parameter lst */ +/* Input: pathid - ushort, pathid */ +/* msgid - ulong *, id of message returned to caller */ +/* trgcls - ulong, target message class */ +/* srccls - ulong, source message class */ +/* msgtag - ulong, message tag */ +/* priority_msg - uchar, flag */ +/* prmmsg - uchar[8], message being sent in parameter */ +/* ansbuf - pointer to array of buffers */ +/* anslen - length of ansbuf buffer */ +/* Output: iprcode - return code from b2f0 call */ +/* msgid - returns message id */ +/**************************************************************/ +int +iucv_send2way_prmmsg_array (ushort pathid, ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, uchar priority_msg, + uchar prmmsg[8], + iucv_array_t * ansbuf, ulong anslen) +{ + iparml_dpl parm; + ulong b2f0_result; +#ifdef DEBUG + printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n"); +#endif + memset (&(parm), 0, sizeof (parm)); + parm.ippathid = pathid; + parm.iptrgcls = trgcls; + parm.ipsrccls = srccls; + parm.ipmsgtag = msgtag; + parm.ipbfadr2 = (ulong) ansbuf; + parm.ipbfln2f = anslen; + parm.ipflags1 |= 0x88; /* message in prmlist */ + if (priority_msg) + parm.ipflags1 |= prior_msg; /* priority message */ + memcpy (parm.iprmmsg, prmmsg, 8); + b2f0_result = b2f0 (send, &parm); + if (msgid) + *msgid = parm.ipmsgid; +#ifdef DEBUG + printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n"); +#endif + return b2f0_result; +} + +/******************************************************************/ +/* Name: top_half_handler */ +/* Purpose: handle minimum amount of interrupt in fastest time */ +/* possible and then pass interrupt to bottom half handler. */ +/* Input: external interrupt buffer */ +/* Output: void */ +/******************************************************************/ + +inline void +top_half_interrupt (struct pt_regs *regs, __u16 code) +{ + iucv_packet *pkt; + pkt = (iucv_packet *) kmalloc + (sizeof (iucv_packet), GFP_KERNEL | GFP_ATOMIC); + if (pkt == NULL) { + printk (KERN_DEBUG "out of memory\n"); + return; + } + memcpy (pkt->data, iucv_external_int_buffer, 40); +#ifdef DEBUG3 +printk (KERN_EMERG "TH: Got INT: %08x\n", *(int *)(pkt->data+4)); +#endif + /* put new packet on the list */ + spin_lock (&iucv_packets_lock); + pkt->next = NULL; + if (iucv_packets_tail != NULL) + iucv_packets_tail->next = pkt; + else + iucv_packets_head = pkt; + iucv_packets_tail = pkt; + spin_unlock (&iucv_packets_lock); + + if (atomic_compare_and_swap (0, 1, &bh_scheduled) == 0) { +#ifdef DEBUG3 +printk (KERN_EMERG "TH: Queuing BH\n"); +#endif + short_task.routine = (void *) bottom_half_interrupt; + queue_task (&short_task, &tq_immediate); + mark_bh (IMMEDIATE_BH); + } + return; +} - /* get data length: */ - iucv_data_len= iucv_data_len - iucv_next; - -#ifdef DEBUG - printk( "iucv: iucv_receive: len is %02X, last: %02X\n", - iucv_data_len,iucv_next); -#endif - /* transmit upstairs */ - iucv_rx(dev,(iucv_data_len),rcvptr); - -#ifdef DEBUG - printk( "iucv: transaction complete now.\n"); -#endif - iucv_next = *((unsigned short*)rcvptr); - rcvptr = rcvptr + iucv_data_len; - /* get next packet offset */ - iucv_data_len= *((unsigned short*)rcvptr); - - } while (iucv_data_len != 0); - netif_start_queue(dev); /* transmission is no longer busy*/ - break; - - default: - printk( "unknown iucv interrupt \n"); - break; - - } /* end switch */ - netif_exit_interrupt(dev); /* release lock*/ - -#ifdef DEBUG - printk( "iucv: leaving do_iucv_interrupt.\n"); +/*******************************************************************/ +/* Name: bottom_half_interrupt */ +/* Purpose: Handle interrupt at a more safer time */ +/* Input: void */ +/* Output: void */ +/*******************************************************************/ +void +bottom_half_interrupt (void) +{ + iucv_packet *iucv_packet_list; + iucv_packet *tmp; + ulong flags; + + atomic_set (&bh_scheduled, 0); + spin_lock_irqsave (&iucv_packets_lock, flags); + iucv_packet_list = iucv_packets_head; + iucv_packets_head = iucv_packets_tail = NULL; + spin_unlock_irqrestore (&iucv_packets_lock, flags); + + /* now process all the request in the iucv_packet_list */ +#ifdef DEBUG3 + printk (KERN_EMERG "BH: Process all packets\n"); +#endif + while (iucv_packet_list != NULL) { +#ifdef DEBUG3 + printk( KERN_EMERG "BH:> %08x\n", + *(int *)(iucv_packet_list->data+4)); +#endif + do_int ((iucv_ConnectionPending *) iucv_packet_list->data); +#ifdef DEBUG3 + printk( KERN_EMERG "BH:< %08x\n", + *(int *)(iucv_packet_list->data+4)); +#endif + tmp = iucv_packet_list; + iucv_packet_list = iucv_packet_list->next; + kfree (tmp); + } +#ifdef DEBUG3 + printk (KERN_EMERG "BH: Done\n"); #endif - -} /* end do_iucv_interrupt() */ - - - -/*-------------------------------------------*/ -/* Transmit a packet (low level interface) */ -/*-------------------------------------------*/ -int iucv_hw_tx(char *send_buf, int len,net_device *dev) -{ - /* This function deals with hw details. */ - /* This interface strips off the ethernet header details. */ - /* In other words, this function implements the iucv behaviour,*/ - /* while all other procedures are rather device-independent */ - struct iucv_priv *privptr; - int rc, recv_len=2000; - - privptr = (struct iucv_priv *)(dev->priv); - -#ifdef DEBUG - printk( "iucv: iucv_hw_tx, device %s\n",dev->name); - printk( "iucv: hw_TX_data len: %X\n",len); - dumpit(send_buf,len); + return; +} +/*******************************************************************/ +/* Name: do_int */ +/* Purpose: Handle interrupt in a more safe environment */ +/* Inuput: int_buf - pointer to copy of external interrupt buffer */ +/* Output: void */ +/*******************************************************************/ +void +do_int (iucv_ConnectionPending * int_buf) +{ + ulong index1 = 0, index2 = 0; + handler_table_entry *P = 0; /* P is a pointer */ + handler *Q = 0, *R; /* Q and R are pointers */ + iucv_interrupt_ops_t *interrupt = 0; /* interrupt addresses */ + uchar temp_buff1[24], temp_buff2[24]; /* masked handler id. */ + int add_pathid_result = 0, j = 0; + uchar no_listener[16] = "NO LISTENER"; +#ifdef DEBUG + int i; + uchar *prt_parm; +#endif +#ifdef DEBUG3 + printk (KERN_DEBUG "BH:- Entered do_int " + "pathid %d, type %02X\n", + int_buf->ippathid, int_buf->iptype); +#endif +#ifdef DEBUG + prt_parm = (uchar *) (int_buf); + printk (KERN_DEBUG "External Interrupt Buffer\n"); + for (i = 0; i < 40; i++) + printk (KERN_DEBUG "%02x ", prt_parm[i]); + printk (KERN_DEBUG "\n"); +#endif + ASCEBC (no_listener, 16); + if (int_buf->iptype != 01) { + index1 = ((ulong) (int_buf->ippathid)) / 512; + index2 = ((ulong) (int_buf->ippathid)) % 512; + spin_lock (&lock); + + P = main_table[index1]; + Q = (P + index2)->addrs; + interrupt = Q->interrupt_table; /* interrupt functions */ + spin_unlock (&lock); +#ifdef DEBUG + printk (KERN_DEBUG "Handler is: \n"); + prt_parm = (uchar *) Q; + for (i = 0; i < sizeof (handler); i++) + printk (KERN_DEBUG " %02x ", prt_parm[i]); + printk (KERN_DEBUG "\n"); +#endif + } /* end of if statement */ + switch (int_buf->iptype) { + case 0x01: /* connection pending */ + spin_lock (&lock); + for (R = handler_anchor; R != NULL; R = (handler *) R->next) { + memcpy (temp_buff1, &(int_buf->ipvmid), 24); + memcpy (temp_buff2, &(R->vmid), 24); + for (j = 0; j < 24; j++) { + temp_buff1[j] = (temp_buff1[j]) & (R->mask)[j]; + temp_buff2[j] = (temp_buff2[j]) & (R->mask)[j]; + } +#ifdef DEBUG + for (i = 0; i < sizeof (temp_buff1); i++) + printk (KERN_DEBUG " %c ", temp_buff1[i]); + printk (KERN_DEBUG "\n"); + for (i = 0; i < sizeof (temp_buff2); i++) + printk (KERN_DEBUG " %c ", temp_buff2[i]); + printk (KERN_DEBUG "\n"); +#endif + if (memcmp((void *) temp_buff1, + (void *) temp_buff2, 24) == 0) { +#ifdef DEBUG + printk (KERN_DEBUG + "found a matching handler\n"); +#endif + break; + } + } + spin_unlock (&lock); + if (R) { + /* ADD PATH TO PATHID TABLE */ + add_pathid_result = + add_pathid (int_buf->ippathid, R, R->pgm_data); + if (add_pathid_result == NULL) { + interrupt = R->interrupt_table; + if ((*interrupt).ConnectionPending) { + EBCASC (int_buf->ipvmid, 8); + + ((*interrupt). + ConnectionPending) (int_buf, + R->pgm_data); + } else { + iucv_sever (int_buf->ippathid, + no_listener); + } + } /* end if if(add_p...... */ + else { + iucv_sever (int_buf->ippathid, no_listener); +#ifdef DEBUG + printk (KERN_DEBUG + "add_pathid failed with rc = %d\n", + (int) add_pathid_result); +#endif + } + } else + iucv_sever (int_buf->ippathid, no_listener); + break; + case 0x02: /*connection complete */ + if (Q) { + if ((*interrupt).ConnectionComplete) + ((*interrupt).ConnectionComplete) + + ((iucv_ConnectionComplete *) int_buf, + (P + index2)->pgm_data); + else { +#ifdef DEBUG + printk (KERN_DEBUG + "ConnectionComplete not called\n"); + printk (KERN_DEBUG "routine@ is %p\n", + (*interrupt).ConnectionComplete); #endif - - /* I am paranoid. Ain't I? */ - if (len < sizeof(struct iphdr)) - { - printk( "iucv: Hmm... packet too short (%i octets)\n",len); - return -EINVAL; - } - - /* - * build IUCV header (preceeding halfword offset) - * works as follows: Each packet is preceded by the - * halfword offset to the next one. - * The last packet is followed by an offset of zero. - * E.g., AL2(12),10-byte packet, AL2(34), 32-byte packet, AL2(0) - */ - - memcpy(&privptr->send_buffer[2],send_buf,len+2); - privptr->send_buffer[len+2] = 0; - privptr->send_buffer[len+3] = 0; - *((unsigned short*) &privptr->send_buffer[0]) = len + 2; - -#ifdef DEBUG - printk( "iucv: iucv_hw_tx, device %s\n",dev->name); - printk( "iucv: send len: %X\n",len+4); - dumpit(privptr->send_buffer,len+4); + } + } + break; + case 0x03: /* connection severed */ + if (Q) { + if ((*interrupt).ConnectionSevered) + ((*interrupt).ConnectionSevered) + + ((iucv_ConnectionSevered *) int_buf, + (P + index2)->pgm_data); + else + iucv_sever (int_buf->ippathid, no_listener); + } else + iucv_sever (int_buf->ippathid, no_listener); + break; + case 0x04: /* connection quiesced */ + if (Q) { + if ((*interrupt).ConnectionQuiesced) + ((*interrupt).ConnectionQuiesced) + + ((iucv_ConnectionQuiesced *) int_buf, + (P + index2)->pgm_data); + else { +#ifdef DEBUG + printk (KERN_DEBUG + "ConnectionQuiesced not called\n"); + printk (KERN_DEBUG "routine@ is %p\n", + (*interrupt).ConnectionQuiesced); #endif - *((unsigned short*) &privptr->send_buffer[0]) = len + 2; - - /* Ok, now the packet is ready for transmission: send it. */ - if ((rc = iucv_send(privptr->command_buffer, - privptr->pathid, - &privptr->send_buffer[0],len+4, - privptr->recv_buf,recv_len))!=0) { - printk( "iucv: send_iucv failed, rc: %X\n",rc); - iucv_retrieve_buffer(privptr->command_buffer); - } -#ifdef DEBUG - printk( "iucv: send_iucv ended, rc: %X\n",rc); + } + } + break; + case 0x05: /* connection resumed */ + if (Q) { + if ((*interrupt).ConnectionResumed) + ((*interrupt).ConnectionResumed) + + ((iucv_ConnectionResumed *) int_buf, + (P + index2)->pgm_data); + else { +#ifdef DEBUG + printk (KERN_DEBUG + "ConnectionResumed not called\n"); + printk (KERN_DEBUG "routine@ is %p\n", + (*interrupt).ConnectionResumed); #endif - return rc; -} /* end iucv_hw_tx() */ - - - - - - -/*------------------------------------------*/ -/* Transmit a packet (called by the kernel) */ -/*------------------------------------------*/ -int iucv_tx(struct sk_buff *skb, net_device *dev) -{ - int retval=0; - - struct iucv_priv *privptr; - - if (dev == NULL) - { - printk("iucv: NULL dev passed\n"); - return 0; - } - - privptr = (struct iucv_priv *) (dev->priv); - - if (skb == NULL) - { - printk("iucv: %s: NULL buffer passed\n", dev->name); - privptr->stats.tx_errors++; - return 0; - } - -#ifdef DEBUG - printk( "iucv: enter iucv_tx, using %s\n",dev->name); + } + } + break; + case 0x06: /* priority message complete */ + case 0x07: /* nonpriority message complete */ + if (Q) { + if ((*interrupt).MessageComplete) + ((*interrupt).MessageComplete) + + ((iucv_MessageComplete *) int_buf, + (P + index2)->pgm_data); + else { +#ifdef DEBUG + printk (KERN_DEBUG + "MessageComplete not called\n"); + printk (KERN_DEBUG "routine@ is %p\n", + (*interrupt).MessageComplete); #endif - - if (netif_is_busy(dev)) /* shouldn't happen */ - { - privptr->stats.tx_errors++; - dev_kfree_skb(skb); - printk("iucv: %s: transmit access conflict ! leaving iucv_tx.\n", dev->name); - } - - netif_stop_queue(dev); /* transmission is busy*/ - dev->trans_start = jiffies; /* save the timestamp*/ - - /* actual deliver of data is device-specific, and not shown here */ - retval = iucv_hw_tx(skb->data, skb->len, dev); - - dev_kfree_skb(skb); /* release it*/ - -#ifdef DEBUG - printk( "iucv:leaving iucv_tx, device %s\n",dev->name); + } + } + break; + case 0x08: /* priority message pending */ + case 0x09: /* nonpriority message pending */ + if (Q) { + if ((*interrupt).MessagePending) + ((*interrupt).MessagePending) + + ((iucv_MessagePending *) int_buf, + (P + index2)->pgm_data); + else { +#ifdef DEBUG + printk (KERN_DEBUG + "MessagePending not called\n"); + printk (KERN_DEBUG "routine@ is %p\n", + (*interrupt).MessagePending); #endif - - return retval; /* zero == done; nonzero == fail*/ -} /* end iucv_tx( struct sk_buff *skb, struct device *dev) */ - - - - - - -/*---------------*/ -/* iucv_release */ -/*---------------*/ -int iucv_release(net_device *dev) -{ - int rc =0; - struct iucv_priv *privptr; - privptr = (struct iucv_priv *) (dev->priv); - - netif_stop(dev); - netif_stop_queue(dev); /* can't transmit any more*/ - rc = iucv_sever(privptr->command_buffer); - if (rc!=0) - { - printk("iucv: %s: iucv_release pending...rc:%02x\n",dev->name,rc); - } - + } + } + break; + default: /* unknown iucv type */ + printk (KERN_DEBUG "unknown iucv interrupt \n"); + break; + } /* end switch */ +#ifdef DEBUG3 + printk (KERN_DEBUG "BH:- Exiting do_int " + "pathid %d, type %02X\n", + int_buf->ippathid, int_buf->iptype); +#endif + return; +} /* end of function call */ + +/**************************************************************/ +/* Name: iucv_register_program */ +/* Purpose: registers a new handler */ +/* Input: pgmname- uchar[16], user id */ +/* userid - uchar[8], machine id */ +/* prmmask- mask */ +/* ops - pointer to iucv_interrupt_ops buffer */ +/* Output: new_handler - address of new handler */ +/**************************************************************/ +iucv_handle_t +iucv_register_program (uchar pgmname[16], + uchar userid[8], + uchar pgmmask[24], + iucv_interrupt_ops_t * ops, ulong pgm_data) +{ + int rc; + handler *new_handler = 0; +#ifdef DEBUG + int i; + uchar *prt_parm; + printk (KERN_DEBUG "enter iucv_register_program\n"); +#endif + my_ops = *ops; + /* Allocate handler table */ + new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL); + if (new_handler == NULL) { #ifdef DEBUG - printk("iucv: iucv_sever ended with rc: %X\n",rc); + printk (KERN_DEBUG + "IUCV: returned NULL address for new handle \n"); #endif - - return rc; -} /* end iucv_release() */ - - - - - -/*-----------------------------------------------*/ -/* Configuration changes (passed on by ifconfig) */ -/*-----------------------------------------------*/ -int iucv_config(net_device *dev, struct ifmap *map) -{ - if (dev->flags & IFF_UP) /* can't act on a running interface*/ - return -EBUSY; - - /* ignore other fields */ - return 0; -} -/* end iucv_config() */ - - - - - -/*----------------*/ -/* Ioctl commands */ -/*----------------*/ -int iucv_ioctl(net_device *dev, struct ifreq *rq, int cmd) -{ -#ifdef DEBUG - printk( "iucv: device %s; iucv_ioctl\n",dev->name); + return NULL; + } + /* fill in handler table */ + memcpy (new_handler->user_data, pgmname, 16); + memcpy (new_handler->vmid, userid, 8); + memcpy (new_handler->mask, pgmmask, 24); + new_handler->pgm_data = pgm_data; + /* Convert from ASCII to EBCDIC */ + if (new_handler->vmid) { + ASCEBC (new_handler->vmid, 8); + EBC_TOUPPER(new_handler->vmid, 8); + } + /* fill in handler table */ + new_handler->interrupt_table = ops; + new_handler->size = ADDED_STOR; + /* Allocate storage for pathid table */ + new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL); + memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong)); + if (new_handler->start == NULL) { +#ifdef DEBUG + printk (KERN_DEBUG + "IUCV: returned NULL address for pathid table," + " exiting\n"); #endif - return 0; -} - -/*---------------------------------*/ -/* Return statistics to the caller */ -/*---------------------------------*/ -struct net_device_stats *iucv_stats(net_device *dev) -{ - struct iucv_priv *priv = (struct iucv_priv *)dev->priv; -#ifdef DEBUG - printk( "iucv: device %s; iucv_stats\n",dev->name); + return NULL; + } + new_handler->end = (*new_handler).start + ADDED_STOR; + new_handler->next = 0; + new_handler->prev = 0; + /* Place handler at beginning of chain */ + spin_lock (&lock); + if (handler_anchor == NULL) + handler_anchor = new_handler; + else { + handler_anchor->prev = (ulong *) new_handler; + new_handler->next = (ulong *) handler_anchor; + handler_anchor = new_handler; +#ifdef DEBUG + printk (KERN_DEBUG "adding a another handler to list\n"); + printk (KERN_DEBUG "handler_anchor->prev is %p \n", + handler_anchor->prev); + printk (KERN_DEBUG "new_handler->next is %p \n", + new_handler->next); + printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor); #endif - return &priv->stats; -} - - -/* - * iucv_change_mtu - * IUCV can handle MTU sizes from 576 to approx. 32000 - */ - -static int iucv_change_mtu(net_device *dev, int new_mtu) -{ + } + spin_unlock (&lock); + if (declare_flag == NULL) { + rc = iucv_declare_buffer (iucv_external_int_buffer); + if (rc == 0) { + declare_flag = 1; + /* request the 0x4000 external interrupt */ + rc = + register_external_interrupt (0x4000, + top_half_interrupt); + } else { + panic ("Registration failed"); #ifdef DEBUG - printk( "iucv: device %s; iucv_change_mtu\n",dev->name); + printk (KERN_DEBUG "rc from declare buffer is: %i\n", + rc); #endif - if ((new_mtu < 64) || (new_mtu > 32000)) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} - - - - -/*--------------------------------------------*/ -/* The init function (sometimes called probe).*/ -/* It is invoked by register_netdev() */ -/*--------------------------------------------*/ -int iucv_init(net_device *dev) -{ - int rc; - struct iucv_priv *privptr; - + } + } #ifdef DEBUG - printk( "iucv: iucv_init, device: %s\n",dev->name); -#endif - - /* request the 0x4000 external interrupt */ - if (register_external_interrupt(0x4000, do_iucv_interrupt) != 0) - panic("Couldn't request external interrupts 0x4000"); - - dev->open = iucv_open; - dev->stop = iucv_release; - dev->set_config = iucv_config; - dev->hard_start_xmit = iucv_tx; - dev->do_ioctl = iucv_ioctl; - dev->get_stats = iucv_stats; - dev->change_mtu = iucv_change_mtu; - - /* keep the default flags, just add NOARP */ - - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_SLIP; - dev->tx_queue_len = 100; - dev->flags = IFF_NOARP|IFF_POINTOPOINT; - dev->mtu = 4092; - - dev_init_buffers(dev); - - /* Then, allocate the priv field. This encloses the statistics */ - /* and a few private fields.*/ - dev->priv = kmalloc(sizeof(struct iucv_priv), GFP_KERNEL); - if (dev->priv == NULL){ - printk( "iucv: no memory for dev->priv.\n"); - return -ENOMEM; - } - memset(dev->priv, 0, sizeof(struct iucv_priv)); - privptr = (struct iucv_priv *)(dev->priv); - - - privptr->send_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8); - if (privptr->send_buffer == NULL) { - printk(KERN_INFO "%s: could not get pages for send buffer\n", - dev->name); - return -ENOMEM; - } - memset(privptr->send_buffer, 0, 8*PAGE_SIZE); - privptr->send_buffer_len=8*PAGE_SIZE; - - privptr->receive_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8); - if (privptr->receive_buffer == NULL) { - printk(KERN_INFO "%s: could not get pages for receive buffer\n", - dev->name); - return -ENOMEM; - } - memset(privptr->receive_buffer, 0, 8*PAGE_SIZE); - privptr->receive_buffer_len=8*PAGE_SIZE; - - /* now use the private fields ... */ - /* init pathid */ - privptr->pathid = -1; - - /* init private userid from global userid */ - memcpy(privptr->userid,iucv_userid[dev-iucv_devs],8); - - - /* we can use only ONE buffer for external interrupt ! */ - rc=iucv_declare_buffer(privptr->command_buffer, - (DCLBFR_T *)iucv_ext_int_buffer); - if (rc!=0 && rc!=19) /* ignore existing buffer */ - { - printk( "iucv:iucv_declare failed, rc: %X\n",rc); - return -ENODEV; - } - - rc = iucv_enable(privptr->command_buffer); - if (rc!=0) - { - printk( "iucv:iucv_enable failed, rc: %x\n",rc); - iucv_retrieve_buffer(privptr->command_buffer); - return -ENODEV; - } + printk (KERN_DEBUG "address of handle is %p ", new_handler); + printk (KERN_DEBUG "size of handle is %d ", (int) (sizeof (handler))); + printk (KERN_DEBUG "exit iucv_register_program\n"); + printk (KERN_DEBUG "main_table is %p \n", main_table); + printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor); + printk (KERN_DEBUG "Handler is: \n"); + prt_parm = (uchar *) new_handler; + for (i = 0; i < sizeof (handler); i++) + printk (KERN_DEBUG " %02x ", prt_parm[i]); + printk (KERN_DEBUG "\n"); +#endif + return new_handler; /* send buffer address back */ +} /* end of register function */ + +/**************************************************************/ +/* Name: iucv_unregister */ +/* Purpose: remove handler from chain and sever all paths */ +/* Input: handle - address of handler to be severed */ +/* Output: returns 0 */ +/**************************************************************/ +int +iucv_unregister (iucv_handle_t handle) +{ + handler *temp_next = 0, *temp_prev = 0; + handler *Q = 0, *R; + handler_table_entry *H_T_E = 0; + ulong *S = 0; /*points to the beginning of block of h_t_e's*/ +#ifdef DEBUG + printk (KERN_DEBUG "enter iucv_unregister\n"); + printk (KERN_DEBUG "address of handle is %p ", handle); + printk (KERN_DEBUG "size of handle is %u ", (int) (sizeof (handle))); +#endif + spin_lock (&lock); + Q = (handler *) handle; + /* + * Checking if handle is still registered: if yes, continue + * if not registered, return. + */ + for (R = handler_anchor; R != NULL; R = (handler *) R->next) + if (Q == R) { +#ifdef DEBUG + printk (KERN_DEBUG "found a matching handler\n"); +#endif + break; + } + if (!R) { + spin_unlock (&lock); + return (0); + } + S = Q->start; #ifdef DEBUG - printk( "iucv: iucv_init endend OK for device %s.\n",dev->name); -#endif - return 0; -} - - -/* - * setup iucv devices - * - * string passed: iucv=userid1,...,useridn - */ -#if LINUX_VERSION_CODE>=0x020300 -static int __init iucv_setup(char *str) -#else -__initfunc(void iucv_setup(char *str,int *ints)) -#endif -{ - int result=0, i=0,j=0, k=0, device_present=0; - char *s = str; - net_device * dev ={0}; - -#ifdef DEBUG - printk( "iucv: start registering device(s)... \n"); -#endif - - /* - * scan device userids - */ - - while(*s != 0x20 && *s != '\0'){ - if(*s == ','){ - /* fill userid up to 8 chars */ - for(k=i;k<8;k++){ - iucv_userid[j][k] = 0x40; - } /* end for */ - /* new device */ - j++; - s++; /* ignore current char */ - i=0; - if (j>MAX_DEVICES) { - printk("iucv: setup devices: max devices %d reached.\n", - MAX_DEVICES); - break; - } /* end if */ - continue; - } /* end if */ - iucv_ascii_userid[j][i] = (int)*s; - iucv_userid[j][i] = _ascebc[(int)*s++]; - i++; - } /* end while */ - - /* - * fill last userid up to 8 chars - */ - for(k=i;k<8;k++) { - iucv_userid[j][k] = 0x40; - } - - /* - * set device name and register - */ - - for (k=0;k<=j;k++) { - memcpy(iucv_devs[k].name, "iucv0", 4); - dev = &iucv_devs[k]; - dev->name[4] = k + '0'; - -#ifdef DEBUGX - printk("iucv: (ASCII- )Userid:%s\n",&iucv_ascii_userid[k][0]); - printk("iucv: (ASCII-)Userid: "); - for (i=0;i<8;i++) { - printk( "%02X ",(int)iucv_ascii_userid[k][i]); - } - printk("\n"); - printk("iucv: (EBCDIC-)Userid: "); - for (i=0;i<8;i++) { - printk( "%02X ",(int)iucv_userid[k][i]); - } - printk("\n"); - printk("iucv: device name :%s\n",iucv_devs[k].name); -#endif - - if ( (result = register_netdev(iucv_devs + k)) ) - printk("iucv: error %i registering device \"%s\"\n", - result, iucv_devs[k].name); - else - { - device_present++; - } - } /* end for */ - -#ifdef DEBUG - printk( "iucv: end register devices, %d devices present\n",device_present); -#endif - /* return device_present ? 0 : -ENODEV; */ -#if LINUX_VERSION_CODE>=0x020300 - return 1; -#else - return; -#endif -} - -#if LINUX_VERSION_CODE>=0x020300 -__setup("iucv=", iucv_setup); -#endif - - -/*-------------*/ -/* The devices */ -/*-------------*/ -char iucv_names[MAX_DEVICES*8]; /* MAX_DEVICES eight-byte buffers */ -net_device iucv_devs[MAX_DEVICES] = { - { - iucv_names, /* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+8,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+16,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+24,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+32,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+40,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+48,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+56,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+64,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - }, - { - iucv_names+72,/* name -- set at load time */ - 0, 0, 0, 0, /* shmem addresses */ - 0x000, /* ioport */ - 0, /* irq line */ - 0, 0, 0, /* various flags: init to 0 */ - NULL, /* next ptr */ - iucv_init, /* init function, fill other fields with NULL's */ - } -}; - + printk (KERN_DEBUG "Q is handle? %p ", Q); + printk (KERN_DEBUG "Q->start is %p ", Q->start); + printk (KERN_DEBUG "&(Q->start) is %p ", &(Q->start)); + printk (KERN_DEBUG "Q->end is %p ", Q->end); + printk (KERN_DEBUG "&(Q->end) is %p ", &(Q->end)); +#endif + while (S < (Q->end)) { /* index thru table */ + if (*S) { + H_T_E = (handler_table_entry *) (*S); +#ifdef DEBUG + printk (KERN_DEBUG "Pointer to H_T_E is %p ", H_T_E); + printk (KERN_DEBUG "Address of handle in H_T_E is %p", + (H_T_E->addrs)); +#endif + if ((H_T_E->addrs) != handle) { + spin_unlock (&lock); + return (-2); /*handler addresses don't match */ + } else { + spin_unlock (&lock); + iucv_sever (H_T_E->pathid, Q->user_data); + spin_lock (&lock); + } + } + S++; /* index by size of ulong */ + } + kfree (Q->start); + temp_next = (handler *) Q->next; /* address of next handler on list */ + temp_prev = (handler *) Q->prev; /* address of prev handler on list */ + if ((temp_next != NULL) & (temp_prev != NULL)) { + (*temp_next).prev = (ulong *) temp_prev; + (*temp_prev).next = (ulong *) temp_next; + } else if ((temp_next != NULL) & (temp_prev == NULL)) { + (*temp_next).prev = NULL; + handler_anchor = temp_next; + } else if ((temp_next == NULL) & (temp_prev != NULL)) + (*temp_prev).next = NULL; + else + handler_anchor = NULL; + if (handler_anchor == NULL) + iucv_retrieve_buffer (); + kfree (handle); + spin_unlock (&lock); +#ifdef DEBUG + printk (KERN_DEBUG "exit iucv_unregister\n"); +#endif + return 0; +} + +EXPORT_SYMBOL (iucv_accept); +EXPORT_SYMBOL (iucv_connect); +EXPORT_SYMBOL (iucv_purge); +EXPORT_SYMBOL (iucv_query); +EXPORT_SYMBOL (iucv_quiesce); +EXPORT_SYMBOL (iucv_receive); +EXPORT_SYMBOL (iucv_receive_simple); +EXPORT_SYMBOL (iucv_receive_array); +EXPORT_SYMBOL (iucv_reject); +EXPORT_SYMBOL (iucv_reply); +EXPORT_SYMBOL (iucv_reply_array); +EXPORT_SYMBOL (iucv_reply_prmmsg); +EXPORT_SYMBOL (iucv_resume); +EXPORT_SYMBOL (iucv_send); +EXPORT_SYMBOL (iucv_send2way); +EXPORT_SYMBOL (iucv_send2way_array); +EXPORT_SYMBOL (iucv_send_array); +EXPORT_SYMBOL (iucv_send2way_prmmsg); +EXPORT_SYMBOL (iucv_send2way_prmmsg_array); +EXPORT_SYMBOL (iucv_send_prmmsg); +EXPORT_SYMBOL (iucv_setmask); +EXPORT_SYMBOL (iucv_sever); +EXPORT_SYMBOL (iucv_register_program); +EXPORT_SYMBOL (iucv_unregister); diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/net/iucv.h linux/drivers/s390/net/iucv.h --- v2.2.17/drivers/s390/net/iucv.h Fri Apr 21 12:46:24 2000 +++ linux/drivers/s390/net/iucv.h Sat Dec 9 20:56:03 2000 @@ -1,146 +1,353 @@ /* - * drivers/s390/net/iucv.h - * Network driver for VM using iucv + * drivers/s390/net/netiucv.h + * IUCV base support. * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Stefan Hegewald - * Hartmut Penner + * Copyright (C) 2000 IBM Corporation + * Author(s): Xenia Tkatschow (xenia@us.ibm.com) + * + * + * Functionality: + * To explore any of the IUCV functions, one must first register + * their program using iucv_register(). Once your program has + * successfully completed a register, it can use the other functions. + * For furthur reference on all IUCV functionality, refer to the + * CP Programming Services book, also available on the web + * thru www.ibm.com/s390/vm. */ - #ifndef _IUCV_H #define _IUCV_H +#define uchar unsigned char +#define ushort unsigned short +#define ulong unsigned long +#define iucv_handle_t void * +/***********************FLAGS*************************************/ +#define source_class 0x01 +#define target_class 0x01 +#define local_conn 0x01 +#define specify_pathid 0x02 +#define specify_msgid 0x04 +#define reply_array 0x08 +#define one_way_msg 0x10 +#define prior_msg 0x20 +#define array 0x40 +#define quiesce_msg 0x40 +#define parm_data 0x80 +#define IPRMDATA 0x80 +#define IPBUFLST 0x40 +#define IPPRTY 0x20 +#define IPNORPY 0x10 +#define IPANSLST 0x08 +#define IPFGMID 0x04 +#define IPFGPID 0x02 +#define IPFGMCL 0x01 + +/*---------------------------------------------------------*/ +/* Mapping of external interrupt buffers */ +/* Names: iucv_ConnectionPending -> connection pending */ +/* iucv_ConnectionComplete -> connection complete */ +/* iucv_ConnectionSevered -> connection severed */ +/* iucv_ConnectionQuiesced -> connection quiesced */ +/* iucv_ConnectionResumed -> connection resumed */ +/* iucv_MessagePending -> message pending */ +/* iucv_MessageComplete -> message complete */ +/*---------------------------------------------------------*/ +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iptype; + ushort ipmsglim; + ushort res1; + uchar ipvmid[8]; + uchar ipuser[16]; + ulong res3; + uchar ippollfg; + uchar res4[3]; +} iucv_ConnectionPending; +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iptype; + ushort ipmsglim; + ushort res1; + uchar res2[8]; + uchar ipuser[16]; + ulong res3; + uchar ippollfg; + uchar res4[3]; +} iucv_ConnectionComplete; -#define UCHAR unsigned char -#define USHORT unsigned short -#define ULONG unsigned long - -#define DEFAULT_BUFFERSIZE 2048 -#define DEFAULT_FN_LENGTH 27 -#define TRANSFERLENGTH 10 - - - -/* function ID's */ -#define RETRIEVE_BUFFER 2 -#define REPLY 3 -#define SEND 4 -#define RECEIVE 5 -#define ACCEPT 10 -#define CONNECT 11 -#define DECLARE_BUFFER 12 -#define SEVER 15 -#define SETMASK 16 -#define SETCMASK 17 -#define PURGE 9999 - -/* structures */ -typedef struct { - USHORT res0; - UCHAR ipflags1; - UCHAR iprcode; - ULONG res1; - ULONG res2; - ULONG ipbfadr1; - ULONG res[6]; -} DCLBFR_T; - -typedef struct { - USHORT ippathid; - UCHAR ipflags1; - UCHAR iprcode; - USHORT ipmsglim; - USHORT res1; - UCHAR ipvmid[8]; - UCHAR ipuser[16]; - UCHAR iptarget[8]; -} CONNECT_T; - -typedef struct { - USHORT ippathid; - UCHAR ipflags1; - UCHAR iprcode; - USHORT ipmsglim; - USHORT res1; - UCHAR res2[8]; - UCHAR ipuser[16]; - UCHAR res3[8]; -} ACCEPT_T; - -typedef struct { - USHORT ippathid; - UCHAR ipflags1; - UCHAR iprcode; - ULONG ipmsgid; - ULONG iptrgcls; - ULONG ipbfadr1; - ULONG ipbfln1f; - ULONG ipsrccls; - ULONG ipmsgtag; - ULONG ipbfadr2; - ULONG ipbfln2f; - ULONG res; -} SEND_T; - -typedef struct { - USHORT ippathid; - UCHAR ipflags1; - UCHAR iprcode; - ULONG ipmsgid; - ULONG iptrgcls; - ULONG iprmmsg1; - ULONG iprmmsg2; - ULONG res1[2]; - ULONG ipbfadr2; - ULONG ipbfln2f; - ULONG res2; -} REPLY_T; - -typedef struct { - USHORT ippathid; - UCHAR ipflags1; - UCHAR iprcode; - ULONG ipmsgid; - ULONG iptrgcls; - ULONG ipbfadr1; - ULONG ipbfln1f; - ULONG res1[3]; - ULONG ipbfln2f; - ULONG res2; -} RECEIVE_T; - -typedef struct { - USHORT ippathid; - UCHAR ipflags1; - UCHAR iprcode; - ULONG res1[3]; - UCHAR ipuser[16]; - ULONG res2[2]; -} SEVER_T; - -typedef struct { - UCHAR ipmask; - UCHAR res1[2]; - UCHAR iprcode; - ULONG res2[9]; -} MASK_T; - -typedef struct { - USHORT ippathid; - UCHAR ipflags1; - UCHAR iptype; - ULONG ipmsgid; - ULONG ipaudit; - ULONG iprmmsg1; - ULONG iprmmsg2; - ULONG ipsrccls; - ULONG ipmsgtag; - ULONG ipbfadr2; - ULONG ipbfln2f; - UCHAR ippollfg; - UCHAR res2[3]; -} INTERRUPT_T; +typedef struct { + ushort ippathid; + uchar res1; + uchar iptype; + ulong res2; + uchar res3[8]; + uchar ipuser[16]; + ulong res4; + uchar ippollfg; + uchar res5[3]; +} iucv_ConnectionSevered; + +typedef struct { + ushort ippathid; + uchar res1; + uchar iptype; + ulong res2; + uchar res3[8]; + uchar ipuser[16]; + ulong res4; + uchar ippollfg; + uchar res5[3]; +} iucv_ConnectionQuiesced; +typedef struct { + ushort ippathid; + uchar res1; + uchar iptype; + ulong res2; + uchar res3[8]; + uchar ipuser[16]; + ulong res4; + uchar ippollfg; + uchar res5[3]; +} iucv_ConnectionResumed; + +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iptype; + ulong ipmsgid; + ulong iptrgcls; + ulong iprmmsg1; + union u1 { + ulong ipbfln1f; + ulong iprmmsg2; + } ln1msg2; + ulong res1[3]; + ulong ipbfln2f; + uchar ippollfg; + uchar res2[3]; +} iucv_MessagePending; + +typedef struct { + ushort ippathid; + uchar ipflags1; + uchar iptype; + ulong ipmsgid; + ulong ipaudit; + ulong iprmmsg1; + ulong iprmmsg2; + ulong ipsrccls; + ulong ipmsgtag; + ulong res; + ulong ipbfln2f; + uchar ippollfg; + uchar res2[3]; +} iucv_MessageComplete; + +/************************structures*************************/ +/*---------------------------------------------------------*/ +/*iucv_interrupt_ops_t: List of functions for interrupt */ +/* handling. */ +/*---------------------------------------------------------*/ + +typedef struct { + void (*ConnectionPending) (iucv_ConnectionPending * eib, + ulong pgm_data); + void (*ConnectionComplete) (iucv_ConnectionComplete * eib, + ulong pgm_data); + void (*ConnectionSevered) (iucv_ConnectionSevered * eib, + ulong pgm_data); + void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib, + ulong pgm_data); + void (*ConnectionResumed) (iucv_ConnectionResumed * eib, + ulong pgm_data); + void (*MessagePending) (iucv_MessagePending * eib, + ulong pgm_data); + void (*MessageComplete) (iucv_MessageComplete * eib, + ulong pgm_data); +} iucv_interrupt_ops_t; + +/*---------------------------------------------------------*/ +/*iucv_array_t : Defines buffer array */ +/*---------------------------------------------------------*/ + +typedef struct { + void *address; + int length; +} iucv_array_t __attribute__ ((aligned (8))); + +/*************************-prototypes-******************************/ + +iucv_handle_t iucv_register_program (uchar pgmname[16], + uchar userid[8], + uchar pgmmask[24], + iucv_interrupt_ops_t * ops, + ulong pgm_data); + +int iucv_unregister (iucv_handle_t handle); + +int iucv_purge (ulong msgid, + ushort pathid, + ulong srccls, + uchar audit[4]); + +void iucv_query (ulong * bufsize, + ulong * conmax); + +int iucv_quiesce (ushort pathid, + uchar user_data[16]); + +int iucv_resume (ushort pathid, + uchar user_data[16]); + +int iucv_reject (ushort pathid, + ulong msgid, + ulong trgcls); + +int iucv_setmask (uchar non_priority_interrupts, + uchar priority_interrupts, + uchar non_priority_completion_interrupts, + uchar priority_completion_interrupts); + +int iucv_connect (ushort * pathid, + ushort msglim, + uchar user_data[16], + uchar userid[8], + uchar system_name[8], + uchar priority_requested, + uchar prmdata, + uchar quiesce, + uchar control, + uchar local, + uchar * priority_permitted, + iucv_handle_t handle, + ulong pgm_data); + +int iucv_accept (ushort pathid, + ushort msglim, + uchar user_data[16], + uchar priority_requested, + uchar prmdata, + uchar quiesce, + uchar control, + uchar * priority_permitted, + iucv_handle_t handle, + ulong pgm_data); + +int iucv_sever (ushort pathid, + uchar user_data[16]); + +int iucv_receive (ushort pathid, + ulong * msgid, + ulong * trgcls, + void *buffer, ulong buflen, + uchar * reply_required, + uchar * priority_msg, + ulong * adds_curr_buffer, + ulong * adds_curr_length); + +int iucv_receive_simple (ushort pathid, + ulong msgid, + ulong trgcls, + void *buffer, ulong buflen); + +int iucv_receive_array (ushort pathid, + ulong * msgid, + ulong * trgcls, + iucv_array_t * buffer, + ulong * buflen, + uchar * reply_required, + uchar * priority_msg, + ulong * adds_curr_buffer, + ulong * adds_curr_length); + +int iucv_send (ushort pathid, + ulong * msgid, + ulong trgcls, + ulong srccls, + ulong msgtag, + uchar priority_msg, + void *buffer, + ulong buflen); + +int iucv_send_array (ushort pathid, + ulong * msgid, + ulong trgcls, + ulong srccls, + ulong msgtag, + uchar priority_msg, + iucv_array_t * buffer, + ulong buflen); + +int iucv_send_prmmsg (ushort pathid, + ulong * msgid, + ulong trgcls, + ulong srccls, + ulong msgtag, + uchar priority_msg, + uchar prmmsg[8]); + +int iucv_send2way (ushort pathid, + ulong * msgid, + ulong trgcls, + ulong srccls, + ulong msgtag, + uchar priority_msg, + void *buffer, + ulong buflen, + void *ansbuf, + ulong anslen); + +int iucv_send2way_array (ushort pathid, + ulong * msgid, + ulong trgcls, + ulong srccls, + ulong msgtag, + uchar priority_msg, + iucv_array_t * buffer, + ulong buflen, + iucv_array_t * ansbuf, + ulong anslen); + +int iucv_send2way_prmmsg (ushort pathid, + ulong * msgid, + ulong trgcls, + ulong srccls, + ulong msgtag, + uchar priority_msg, + uchar prmmsg[8], + void *ansbuf, + ulong anslen); + +int iucv_send2way_prmmsg_array (ushort pathid, + ulong * msgid, + ulong trgcls, ulong srccls, + ulong msgtag, + uchar priority_msg, + uchar prmmsg[8], + iucv_array_t * ansbuf, + ulong anslen); +int iucv_reply (ushort pathid, + ulong msgid, + ulong trgcls, + uchar priority_msg, + void *buf, + ulong buflen); + +int iucv_reply_array (ushort pathid, + ulong msgid, + ulong trgcls, + uchar priority_msg, + iucv_array_t * buffer, + ulong buflen); + +int iucv_reply_prmmsg (ushort pathid, + ulong msgid, + ulong trgcls, + uchar priority_msg, + uchar prmmsg[8]); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c --- v2.2.17/drivers/s390/net/netiucv.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/s390/net/netiucv.c Sat Dec 9 20:56:03 2000 @@ -0,0 +1,930 @@ +/* + * drivers/s390/net/netiucv.c + * Network driver for VM using iucv + * + * S/390 version + * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Stefan Hegewald + * Hartmut Penner + * + * + * 2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * Re-write: Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 + * Uses iucv.c kernel module for IUCV services. + * + * -------------------------------------------------------------------------- + * An IUCV frame consists of one or more packets preceded by a 16-bit + * header. The header contains the offset to the next packet header, + * measured from the beginning of the _frame_. If zero, there are no more + * packets in the frame. Consider a frame which contains a 10-byte packet + * followed by a 20-byte packet: + * +-----+----------------+-----+----------------------------+-----+ + * |h'12'| 10-byte packet |h'34'| 20-byte packet |h'00'| + * +-----+----------------+-----+----------------------------+-----+ + * Offset: 0 2 12 14 34 + * + * This means that each header will always have a larger value than the + * previous one (except for the final zero header, of course). + * + * For outbound packets, we send ONE frame per packet. So, our frame is: + * AL2(packet length+2), packet, AL2(0) + * The maximum packet size is the MTU, so the maximum IUCV frame we send + * is MTU+4 bytes. + * + * For inbound frames, we don't care how long the frame is. We tear apart + * the frame, processing packets up to MTU size in length, until no more + * packets remain in the frame. + * + * -------------------------------------------------------------------------- + * The code uses the 2.3.43 network driver interfaces. If compiled on an + * an older level of the kernel, the module provides its own macros. + * Doc is in Linux Weekly News (lwn.net) memo from David Miller, 9 Feb 2000. + * There are a few other places with 2.3-specific enhancements. + * + * -------------------------------------------------------------------------- +*/ +//#define DEBUG 1 + +/* If MAX_DEVICES increased, add initialization data to iucv_netdev[] array */ +/* (See bottom of program.) */ +#define MAX_DEVICES 10 /* Allows "iucv0" to "iucv9" */ +#define MAX_VM_MTU 32764 /* 32K IUCV buffer, minus 4 */ +#define MAX_TX_Q 50 /* Maximum pending TX */ + +#include +#include + +#ifdef MODULE +#include +MODULE_AUTHOR + ("(C) 2000 IBM Corporation by Alan Altmark (Alan_Altmark@us.ibm.com)"); +MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); +MODULE_PARM (iucv, "1-" __MODULE_STRING (MAX_DEVICES) "s"); +MODULE_PARM_DESC (iucv, + "Specify the userids associated with iucv0-iucv9:\n" + "iucv=userid1,userid2,...,userid10\n"); +#ifdef MODVERSIONS +#include +#endif +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include /* task queues */ +#include /* kmalloc() */ +#include /* error codes */ +#include /* size_t */ +#include /* mark_bh */ +#include /* struct net_device, etc. */ +#include /* ARPHRD_SLIP */ +#include /* skb */ +#include /* __setup() */ +#include /* virt_to_phys() */ +#include /* memset, memcpy, etc. */ +#include "iucv.h" +#define min(a,b) (a < b) ? a : b + +#ifdef DEBUG +#undef KERN_INFO +#undef KERN_DEBUG +#define KERN_INFO KERN_EMERG +#define KERN_DEBUG KERN_EMERG +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +typedef struct net_device net_device; +#else +typedef struct device net_device; +#endif + +static __inline__ int +netif_is_busy (net_device * dev) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,45)) + return (dev->tbusy); +#else + return (test_bit (LINK_STATE_XOFF, &dev->flags)); +#endif +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,45)) + /* Provide our own 2.3.45 interfaces */ +#define netif_enter_interrupt(dev) dev->interrupt=1 +#define netif_exit_interrupt(dev) dev->interrupt=0 +#define netif_start(dev) dev->start=1 +#define netif_stop(dev) dev->start=0 + +static __inline__ void +netif_stop_queue (net_device * dev) +{ + dev->tbusy = 1; +} + +static __inline__ void +netif_start_queue (net_device * dev) +{ + dev->tbusy = 0; +} + +static __inline__ void +netif_wake_queue (net_device * dev) +{ + dev->tbusy = 0; + mark_bh (NET_BH); +} + +#else + /* As of 2.3.45, we don't do these things anymore */ +#define netif_enter_interrupt(dev) +#define netif_exit_interrupt(dev) +#define netif_start(dev) +#define netif_stop(dev) +#endif + +static int iucv_start (net_device *); +static int iucv_stop (net_device *); +static int iucv_change_mtu (net_device *, int); +static int iucv_init (net_device *); +static void iucv_rx (net_device *, uchar *, int); +static int iucv_tx (struct sk_buff *, net_device *); + +static void connection_severed (iucv_ConnectionSevered *, ulong); +static void connection_pending (iucv_ConnectionPending *, ulong); +static void connection_complete (iucv_ConnectionComplete *, ulong); +static void message_pending (iucv_MessagePending *, ulong); +static void send_complete (iucv_MessageComplete *, ulong); + +void register_iucv_dev (int, char *); + +static iucv_interrupt_ops_t netiucv_ops = { + &connection_pending, + &connection_complete, + &connection_severed, + NULL, /* Quiesced */ + NULL, /* Resumed */ + &message_pending, /* Message pending */ + &send_complete /* Message complete */ +}; + +static char iucv_userid[MAX_DEVICES][8]; +net_device iucv_netdev[MAX_DEVICES]; +static char iucv_names[MAX_DEVICES][8]; +static char eodata[2] = { '\0', '\0' }; + +/* This structure is private to each device. It contains the */ +/* information necessary to do IUCV operations. */ +struct iucv_priv { + struct net_device_stats stats; + net_device *dev; + iucv_handle_t handle; + uchar userid[9]; /* Printable userid */ + uchar userid2[8]; /* Used for IUCV operations */ + + /* Note: atomic_compare_and_swap() return value is backwards */ + /* from what you might think: FALSE=0=OK, TRUE=1=FAIL */ + atomic_t state; +#define FREE 0 +#define CONNECTING 1 +#define CONNECTED 2 + u16 pathid; +}; + +struct iucvtag { + iucv_array_t iucvvec[3]; + u16 framelen; + struct sk_buff *skb; +}; + +uchar iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uchar iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 +}; + +/* This mask means the 16-byte IUCV "magic" and the origin userid must */ +/* match exactly as specified in order to give connection_pending() */ +/* control. */ +const char mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +#ifdef DEBUG +/*--------------------------*/ +/* Dump buffer formatted */ +/*--------------------------*/ +static void +dumpit (char *buf, int len) +{ + int i; + printk (KERN_DEBUG); + for (i = 0; i < len; i++) { + if (!(i % 32) && i != 0) + printk ("\n"); + else if (!(i % 4) && i != 0) + printk (" "); + printk ("%02X", buf[i]); + } + if (len % 32) + printk ("\n"); +} +#endif + +/*-----------------------------------------------------------------*/ +/* Open a connection to another Linux or VM TCP/IP stack. */ +/* Called by kernel. */ +/* */ +/* 1. Register a handler. (Up to now, any attempt by another stack */ +/* has been rejected by the IUCV handler.) We give the handler */ +/* the net_device* so that we can locate the dev associated */ +/* with the partner userid if he tries to connect to us or */ +/* if the connection is broken. */ +/* */ +/* 2. Connect to remote stack. If we get a connection pending */ +/* interrupt while we're in the middle of connecting, don't */ +/* worry. VM will sever its and use ours, because the DEVICE */ +/* is defined to be: */ +/* DEVICE devname IUCV 0 0 linuxvm A */ +/* or DEVICE devname IUCV 0 0 linuxvm B */ +/* In EBCDIC, "0" (0xF0) is greater than "A" (0xC1) or "B", so */ +/* win all races. We will sever any connects that occur while */ +/* we are connecting. The "0 0" is where we get iucvMagic from.*/ +/* */ +/* FIXME: If two Linux machines get into this race condition, */ +/* both will sever. Manual intervention required. */ +/* Need a better IUCV "hello"-like function that permits */ +/* some negotiation. But can't do that until VM TCP/IP */ +/* would support it. */ +/* */ +/* 3. Return 0 to indicate device ok. Anything else is an error. */ +/*-----------------------------------------------------------------*/ +static int +iucv_start (net_device * dev) +{ + int rc, i; + uchar pri; + uchar unused = '\0'; + struct iucv_priv *p = (struct iucv_priv *) dev->priv; + + pr_debug ("iucv_start(%s)\n", dev->name); + + if (p == NULL) { + /* Allocate priv data */ + p = (struct iucv_priv *) kmalloc (sizeof (struct iucv_priv), + GFP_KERNEL); + if (p == NULL) { + printk (KERN_CRIT "%s: no memory for dev->priv.\n", + dev->name); + return -ENOMEM; + } + memset (p, 0, sizeof (struct iucv_priv)); + dev->priv = p; + p->dev = dev; + + memcpy (p->userid, iucv_userid[dev - iucv_netdev], 8); /* Save userid */ + memcpy (p->userid2, p->userid, 8); /* Again, with feeling. */ + + for (i = 0; i < 8; i++) { /* Change userid to printable form */ + if (p->userid[i] == ' ') { + p->userid[i] = '\0'; + break; + } + } + p->userid[8] = '\0'; + atomic_set (&p->state, FREE); + p->handle = + iucv_register_program (iucvMagic, p->userid2, (char *) mask, + &netiucv_ops, (ulong) dev); + if (p->handle <= 0) { + printk (KERN_ERR + "%s: iucv_register_program error, rc=%i\n", + dev->name, (int) p->handle); + dev->priv = NULL; + kfree (p); + return -ENODEV; + } + pr_debug ("state@ = %p\n", &p->state); + MOD_INC_USE_COUNT; + } + + if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) { + pr_debug ("Other side connecting during start\n"); + return 0; + } + + rc = + iucv_connect (&(p->pathid), MAX_TX_Q, iucvMagic, p->userid2, + iucv_host, unused, unused, unused, unused, unused, + &pri, p->handle, (ulong) p); + + /* Some errors are not fatal. In these cases we will report "OK". */ + switch (rc) { + case 0: /* Wait for connection to complete */ + pr_debug ("...waiting for connection to complete..."); + return 0; + case 11: /* Wait for parter to connect */ + printk (KERN_NOTICE "Device %s: " + "User %s is not available now.\n", + dev->name, p->userid); + atomic_set (&p->state, FREE); + return 0; + case 12: /* Wait for partner to connect */ + printk (KERN_NOTICE "Device %s: " + "User %s is not ready to talk now.\n", + dev->name, p->userid); + atomic_set (&p->state, FREE); + return 0; + case 13: /* Fatal */ + printk (KERN_ERR "Device %s: " + "You have too many IUCV connections." + "Check MAXCONN in CP directory.\n", dev->name); + break; + case 14: /* Fatal */ + printk (KERN_ERR "Device %s: " + "User %s has too many IUCV connections." + "Check MAXCONN in CP directory.\n", + dev->name, p->userid); + break; + case 15: /* Fatal */ + printk (KERN_ERR "Device %s: " + "No IUCV authorization found in CP directory.\n", + dev->name); + break; + default: /* Really fatal! Should not occur!! */ + printk (KERN_ERR "%s: " + "return code %i from iucv_connect()\n", dev->name, rc); + } + + rc = iucv_unregister (p->handle); + dev->priv = NULL; + kfree (p); + MOD_DEC_USE_COUNT; + return -ENODEV; +} /* end iucv_start() */ + +/*********************************************************************/ +/* Our connection TO another stack has been accepted. */ +/*********************************************************************/ +static void +connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data) +{ + struct iucv_priv *p = (struct iucv_priv *) pgm_data; + pr_debug ("...%s connection complete... txq=%u\n", + p->dev->name, cci->ipmsglim); + atomic_set (&p->state, CONNECTED); + p->pathid = cci->ippathid; + p->dev->tx_queue_len = cci->ipmsglim; + netif_start (p->dev); + netif_start_queue (p->dev); + printk (KERN_INFO "%s: Connection to user %s is up\n", + p->dev->name, p->userid); +} /* end connection_complete() */ + +/*********************************************************************/ +/* A connection FROM another stack is pending. If we are in the */ +/* middle of connecting, sever the new connection. */ +/* */ +/* We only get here if we've done an iucv_register(), so we know */ +/* the remote user is the correct user. */ +/*********************************************************************/ +static void +connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data) +{ + /* Only get this far if handler is set up, so we know userid is ok. */ + /* and the device is started. */ + /* pgm_data is different for this one. We get dev*, not priv*. */ + net_device *dev = (net_device *) pgm_data; + struct iucv_priv *p = (struct iucv_priv *) dev->priv; + int rc; + uchar udata[16]; + uchar no = '\0'; + uchar na; + + /* If we're not waiting on a connect, reject the connection */ + if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) { + iucv_sever (cpi->ippathid, udata); + return; + } + + rc = iucv_accept (cpi->ippathid, /* Path id */ + MAX_TX_Q, /* msglimit */ + udata, /* user_Data */ + no, /* will we send priority msgs? */ + no, /* do we accept prmdata? */ + no, /* quiece immediately? */ + no, /* control path? */ + &na, /* other side accept prmdata? */ + p->handle, /* registration handle */ + (ulong) p); /* private data */ + if (rc != 0) { + atomic_set (&p->state, FREE); + printk (KERN_ERR "%s: iucv accept failed rc=%i\n", + p->dev->name, rc); + } else { + p->pathid = cpi->ippathid; + p->dev->tx_queue_len = cpi->ipmsglim; + netif_start (p->dev); + netif_start_queue (p->dev); + atomic_set (&p->state, CONNECTED); + printk (KERN_INFO "Device %s: Connection to user %s is up\n", + p->dev->name, p->userid); + } +} /* end connection_pending() */ + +/*********************************************************************/ +/* Our connection to another stack has been severed. */ +/*********************************************************************/ +static void +connection_severed (iucv_ConnectionSevered * eib, ulong pgm_data) +{ + struct iucv_priv *p = (struct iucv_priv *) pgm_data; + + printk (KERN_INFO "%s: Connection to user %s is down\n", + p->dev->name, p->userid); + + if (atomic_compare_and_swap (CONNECTED, FREE, &p->state) != 0) + return; /* In case reconnect in progress already */ + + netif_stop_queue (p->dev); + netif_stop (p->dev); +} /* end connection_severed() */ + +/*-----------------------------------------------------*/ +/* STOP device. Called by kernel. */ +/*-----------------------------------------------------*/ +static int +iucv_stop (net_device * dev) +{ + int rc = 0; + struct iucv_priv *p; + pr_debug ("%s: iucv_stop\n", dev->name); + + netif_stop_queue (dev); + netif_stop (dev); + + p = (struct iucv_priv *) (dev->priv); + if (p == NULL) + return 0; + + rc = iucv_unregister (p->handle); /* Will sever connections */ + dev->priv = NULL; + kfree (p); + MOD_DEC_USE_COUNT; + return 0; +} /* end iucv_stop() */ + +/*---------------------------------------------------------------------*/ +/* Inbound packets from other host are ready for receipt. Receive */ +/* them (they arrive as a single transmission), break them up into */ +/* separate packets, and send them to the "generic" packet processor. */ +/*---------------------------------------------------------------------*/ +static void +message_pending (iucv_MessagePending * mpi, ulong pgm_data) +{ + struct iucv_priv *p = (struct iucv_priv *) pgm_data; + int rc; + u32 buffer_length; + u16 packet_offset, prev_offset = 0; + void *buffer; + + buffer_length = mpi->ln1msg2.ipbfln1f; + pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid, + buffer_length); + + buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA); + if (buffer == NULL) { + p->stats.rx_dropped++; + return; + } + + rc = iucv_receive_simple (p->pathid, mpi->ipmsgid, mpi->iptrgcls, + buffer, buffer_length); + + if (rc != 0 || buffer_length < 5) { + printk (KERN_INFO + "%s: iucv_receive error. rc=%X, length=%u\n", + p->dev->name, rc, buffer_length); + p->stats.rx_errors++; + kfree (buffer); + return; + } + + packet_offset = *((u16 *) buffer); + + while (packet_offset != 0) { + if (packet_offset <= prev_offset + || packet_offset > buffer_length - 2) { + printk (KERN_INFO "%s: bad inbound packet offset %u, " + "prev %u, total %u\n", p->dev->name, + packet_offset, prev_offset, buffer_length); + p->stats.rx_errors++; + break; + } else { + /* Kick the packet upstairs */ + iucv_rx (p->dev, + buffer + prev_offset + 2, + packet_offset - prev_offset - 2); + prev_offset = packet_offset; + packet_offset = *((u16 *) (buffer + packet_offset)); + } + } + + kfree (buffer); + return; +} /* end message_pending() */ + +/*-------------------------------------------------------------*/ +/* Add meta-data to packet and send upstairs. */ +/*-------------------------------------------------------------*/ +static void +iucv_rx (net_device * dev, uchar * buf, int len) +{ + struct iucv_priv *p = (struct iucv_priv *) dev->priv; + struct sk_buff *skb; + + pr_debug ("%s: iucv_rx len=%u\n", p->dev->name, len); +#ifdef DEBUG + dumpit (buf, 20); +#endif + + if (len > p->dev->mtu) { + printk (KERN_INFO + "%s: inbound packet length %u exceeds MTU %i\n", + p->dev->name, len, p->dev->mtu); + p->stats.rx_errors++; + return; + } + + skb = dev_alloc_skb (len); + if (!skb) { + p->stats.rx_dropped++; + return; + } + + /* If not enough room, skb_put will panic */ + memcpy (skb_put (skb, len), buf, len); + + /* Write metadata, and then pass to the receive level. Since we */ + /* are not an Ethernet device, we have special fields to set. */ + /* This is all boilerplace, not to be messed with. */ + skb->dev = p->dev; /* Set device */ + skb->mac.raw = skb->data; /* Point to packet */ + skb->pkt_type = PACKET_HOST; /* ..for this host. */ + skb->protocol = htons (ETH_P_IP); /* IP packet */ + skb->ip_summed = CHECKSUM_UNNECESSARY; /* No checksum */ + p->stats.rx_packets++; + p->stats.rx_bytes += len; + netif_rx (skb); + + return; +} /* end iucv_rx() */ + +/*-------------------------------------------------------------*/ +/* TRANSMIT a packet. Called by kernel. */ +/* This function deals with hw details of packet transmission. */ +/*-------------------------------------------------------------*/ +static int +iucv_tx (struct sk_buff *skb, net_device * dev) +{ + int rc, pktlen; + struct iucvtag *tag; + struct iucv_priv *p = (struct iucv_priv *) dev->priv; + + if (skb == NULL) /* Nothing to do */ + return 0; + + if (netif_is_busy (dev)) { + p->stats.tx_dropped++; + dev_kfree_skb (skb); + printk (KERN_ERR "%s: tx conflict! leave iucv_tx.\n", + dev->name); + return -EBUSY; + } + + netif_stop_queue (dev); /* transmission is busy */ + + dev->trans_start = jiffies; /* save the timestamp */ + + /* Tag contains data that must survive exit from this */ + /* routine. MessageComplete exit will free the tag */ + /* and any structures it points to. */ + tag = + (struct iucvtag *) kmalloc (sizeof (struct iucvtag), + GFP_DMA | GFP_KERNEL); + if (!tag) { + p->stats.tx_dropped++; + dev_kfree_skb (skb); + return -ENOMEM; + } + + pktlen = skb->len; + tag->framelen = (u16) pktlen + 2; + tag->skb = skb; + tag->iucvvec[0].address = &tag->framelen; + tag->iucvvec[0].length = 2; + tag->iucvvec[1].address = (void *) virt_to_phys (skb->data); + tag->iucvvec[1].length = pktlen; + tag->iucvvec[2].address = (void *) virt_to_phys (eodata); + tag->iucvvec[2].length = 2; + pr_debug ("iucv_tx: length=%i, skb=%p tag=%p\n", pktlen, tag->skb, tag); + + /* Ok, now the packet is ready for transmission: send it. */ + rc = + iucv_send_array (p->pathid, NULL, 0, 0, (ulong) tag, 0, + tag->iucvvec, pktlen + 4); + if (rc == 0) + p->stats.tx_packets++; + else { + if (rc == 3) /* Exceeded MSGLIMIT */ + p->stats.tx_dropped++; + else { + p->stats.tx_errors++; + printk (KERN_INFO "%s: iucv send failed, rc=%i\n", + p->dev->name, rc); + } + dev_kfree_skb (skb); + kfree (tag); + } + + netif_wake_queue (p->dev); + return rc; /* zero == done; nonzero == fail */ +} /* end iucv_tx() */ + +/*-----------------------------------------------------------*/ +/* SEND COMPLETE Called by IUCV handler. */ +/* Free SKB associated with this transmission and free */ +/* the IUCV buffer list and SKB pointer. */ +/*-----------------------------------------------------------*/ +static void +send_complete (iucv_MessageComplete * mci, ulong pgm_data) +{ + struct iucvtag *tag = (struct iucvtag *) mci->ipmsgtag; + pr_debug ("TX COMPLETE: Tag=%p skb=%p\n", tag, tag->skb); + dev_kfree_skb (tag->skb); + kfree (tag); +} /* end send_complete() */ + +/*-----------------------------------------------------------*/ +/* STATISTICS reporting. Called by kernel. */ +/*-----------------------------------------------------------*/ +static struct net_device_stats * +iucv_stats (net_device * dev) +{ + struct iucv_priv *p = (struct iucv_priv *) dev->priv; + return &p->stats; +} /* end iucv_stats() */ + +/*-----------------------------------------------------------*/ +/* MTU change . Called by kernel. */ +/* IUCV can handle mtu sizes from 576 (the IP architectural */ +/* minimum) up to maximum supported by VM. I don't think IP */ +/* pays attention to new mtu until device is restarted. */ +/*-----------------------------------------------------------*/ +static int +iucv_change_mtu (net_device * dev, int new_mtu) +{ + if ((new_mtu < 576) || (new_mtu > MAX_VM_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} /* end iucv_change_mtu() */ + +/*-----------------------------------------------------------*/ +/* INIT device. Called by kernel. */ +/* Called by register_netdev() in kernel. */ +/*-----------------------------------------------------------*/ +static int +iucv_init (net_device * dev) +{ + dev->open = iucv_start; + dev->stop = iucv_stop; + dev->hard_start_xmit = iucv_tx; + dev->get_stats = iucv_stats; + dev->change_mtu = iucv_change_mtu; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = ARPHRD_SLIP; + dev->tx_queue_len = MAX_TX_Q; /* Default - updated based on IUCV */ + /* keep the default flags, just add NOARP and POINTOPOINT */ + dev->flags = IFF_NOARP | IFF_POINTOPOINT; + dev->mtu = 9216; + + dev_init_buffers (dev); + pr_debug ("%s: iucv_init dev@=%p\n", dev->name, dev); + return 0; +} + +#ifndef MODULE +/*-----------------------------------------------------------------*/ +/* Process iucv=userid1,...,useridn kernel parameter. */ +/* */ +/* Each user id provided will be associated with device 'iucvnn'. */ +/* iucv_init will be called to initialize each device. */ +/*-----------------------------------------------------------------*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +#define init_return(a) return a +static int __init +iucv_setup (char *iucv) +#else +#define init_return(a) return +__initfunc (void iucv_setup (char *iucv, int *ints)) +#endif +{ + int i, devnumber; + char *s; + char temp_userid[9]; + + i = devnumber = 0; + memset (temp_userid, ' ', 8); + temp_userid[8] = '\0'; + + if (!iucv) + init_return (0); + + for (s = iucv; *s != '\0'; s++) { + if (*s == ' ') /* Compress out blanks */ + continue; + + if (devnumber >= MAX_DEVICES) { + printk (KERN_ERR "More than %i IUCV hosts specified\n", + MAX_DEVICES); + init_return (-ENODEV); + } + + if (*s != ',') { + temp_userid[i++] = *s; + + if (i == 8 || *(s + 1) == ',' || *(s + 1) == '\0') { + register_iucv_dev (devnumber, temp_userid); + devnumber++; + i = 0; + memset (temp_userid, ' ', 8); + if (*(s + 1) != '\0') + *(s + 1) = ' '; + } + } + } /* while */ + + init_return (1); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) +__setup ("iucv=", iucv_setup); +#endif +#else /* BUILT AS MODULE */ +/*-------------------------------------------------------------------*/ +/* Process iucv=userid1,...,useridn module paramter. */ +/* */ +/* insmod passes the module an array of string pointers, each of */ +/* which points to a userid. The commas are stripped out by insmod. */ +/* MODULE_PARM defines the name of the array. (See start of module.)*/ +/* */ +/* Each user id provided will be associated with device 'iucvnn'. */ +/* iucv_init will be called to initialize each device. */ +/*-------------------------------------------------------------------*/ +char *iucv[MAX_DEVICES] = { NULL }; +int +init_module (void) +{ + int i; + for (i = 0; i < MAX_DEVICES; i++) { + if (iucv[i] == NULL) + break; + register_iucv_dev (i, iucv[i]); + } + return 0; +} + +void +cleanup_module (void) +{ + int i; + for (i = 0; i < MAX_DEVICES; i++) { + if (iucv[i]) + unregister_netdev (&iucv_netdev[i]); + } + return; +} +#endif /* MODULE */ + +void +register_iucv_dev (int devnumber, char *userid) +{ + int rc; + net_device *dev; + + memset (iucv_userid[devnumber], ' ', 8); + memcpy (iucv_userid[devnumber], userid, min (strlen (userid), 8)); + dev = &iucv_netdev[devnumber]; + sprintf (dev->name, "iucv%i", devnumber); + + pr_debug ("netiucv: registering %s\n", dev->name); + + if ((rc = register_netdev (dev))) { + printk (KERN_ERR + "netiucv: register_netdev(%s) error %i\n", + dev->name, rc); + } + return; +} + +/* These structures are static because setup() can be called very */ +/* early in kernel init if this module is built into the kernel. */ +/* Certainly no kmalloc() is available, probably no C runtime. */ +/* If support changed to be module only, this can all be done */ +/* dynamically. */ +static char iucv_names[MAX_DEVICES][8]; /* Allows "iucvXXX" plus null */ +net_device iucv_netdev[MAX_DEVICES] = { + { + &iucv_names[0][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[1][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[2][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[3][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[4][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[5][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[6][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[7][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[8][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + }, + { + &iucv_names[9][0], /* Name filled in at load time */ + 0, 0, 0, 0, /* shmem addresses */ + 0x0000, /* I/O port */ + 0, /* irq line */ + 0, 0, 0, /* flags */ + NULL, /* next device in list */ + iucv_init, /* probe function, rest to null */ + } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/sbus/audio/Config.in linux/drivers/sbus/audio/Config.in --- v2.2.17/drivers/sbus/audio/Config.in Fri Apr 21 12:46:24 2000 +++ linux/drivers/sbus/audio/Config.in Thu Nov 2 13:05:35 2000 @@ -7,8 +7,10 @@ comment 'Linux/SPARC audio subsystem (EXPERIMENTAL)' tristate 'Audio support (EXPERIMENTAL)' CONFIG_SPARCAUDIO - dep_tristate ' AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO + if [ "$CONFIG_SPARC64" != "y" ]; then + dep_tristate ' AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO + dep_tristate ' DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO + fi dep_tristate ' CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO - dep_tristate ' DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO dep_tristate ' Dummy Lowlevel Driver' CONFIG_SPARCAUDIO_DUMMY $CONFIG_SPARCAUDIO fi diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c --- v2.2.17/drivers/sbus/char/envctrl.c Sun Jun 11 21:44:15 2000 +++ linux/drivers/sbus/char/envctrl.c Wed Nov 8 22:48:54 2000 @@ -1,4 +1,4 @@ -/* $Id: envctrl.c,v 1.9.2.1 2000/05/02 04:23:33 davem Exp $ +/* $Id: envctrl.c,v 1.9.2.2 2000/11/08 09:43:04 davem Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -11,6 +11,9 @@ * http://www-eu2.semiconductors.com/pip/PCF8584P * http://www-eu2.semiconductors.com/pip/PCF8574AP * http://www-eu2.semiconductors.com/pip/PCF8591P + * + * EB - Added support for CP1500 Global Address and PS/Voltage monitoring. + * Eric Brower * */ @@ -74,15 +77,16 @@ * Firmware definitions. */ #define PCF8584_MAX_CHANNELS 8 +#define PCF8584_GLOBALADDR_TYPE 6 /* global address monitor */ #define PCF8584_FANSTAT_TYPE 3 /* fan status monitor */ #define PCF8584_VOLTAGE_TYPE 2 /* voltage monitor */ -#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/ +#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/ /* Monitor type of i2c child device. * Driver definitions. */ -#define ENVCTRL_NOMON 0 -#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */ +#define ENVCTRL_NOMON 0 +#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */ #define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */ #define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */ #define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */ @@ -90,6 +94,7 @@ #define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */ #define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */ #define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */ +#define ENVCTRL_GLOBALADDR_MON 8 /* global address */ /* Child device type. * Driver definitions. @@ -111,6 +116,15 @@ #define ENVCTRL_MAX_CPU 4 #define CHANNEL_DESC_SZ 256 +/* Mask values for combined GlobalAddress/PowerStatus node */ +#define ENVCTRL_GLOBALADDR_ADDR_MASK 0x1F +#define ENVCTRL_GLOBALADDR_PSTAT_MASK 0x60 + +/* Node 0x70 ignored on CompactPCI CP1400/1500 platforms + * (see envctrl_init_i2c_child) + */ +#define ENVCTRL_CPCI_IGNORED_NODE 0x70 + struct pcf8584_reg { unsigned char data; unsigned char csr; @@ -198,7 +212,7 @@ int limit = 1000000; while (--limit > 0) { - if(!(envctrl_readb(&i2c->csr) & STATUS_PIN)) + if (!(envctrl_readb(&i2c->csr) & STATUS_PIN)) break; udelay(1); } @@ -472,6 +486,31 @@ return 1; } +/* Function Description: Read global addressing line. + * Return : Always 1 byte. Status stored in bufdata. + */ +static int envctrl_i2c_globaladdr(struct i2c_child_t *pchild, + unsigned char data, + char *bufdata) +{ + /* Translatation table is not necessary, as global + * addr is the integer value of the GA# bits. + * + * NOTE: MSB is documented as zero, but I see it as '1' always.... + * + * ----------------------------------------------- + * | 0 | FAL | DEG | GA4 | GA3 | GA2 | GA1 | GA0 | + * ----------------------------------------------- + * GA0 - GA4 integer value of Global Address (backplane slot#) + * DEG 0 = cPCI Power supply output is starting to degrade + * 1 = cPCI Power supply output is OK + * FAL 0 = cPCI Power supply has failed + * 1 = cPCI Power supply output is OK + */ + bufdata[0] = (data & ENVCTRL_GLOBALADDR_ADDR_MASK); + return 1; +} + /* Function Description: Read voltage and power supply status. * Return : Always 1 byte. Status stored in bufdata. */ @@ -598,9 +637,19 @@ copy_to_user((unsigned char*)buf, data, ret); break; + case ENVCTRL_RD_GLOBALADDRESS: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON))) + return 0; + data[0] = envctrl_i2c_read_8574(pchild->addr); + ret = envctrl_i2c_globaladdr(pchild, data[0], data); + copy_to_user((unsigned char*)buf, data, ret); + break; + case ENVCTRL_RD_VOLTAGE_STATUS: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON))) - return 0; + /* If voltage monitor not present, check for CPCI equivalent */ + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON))) + return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_voltage_status(pchild, data[0], data); copy_to_user((unsigned char*)buf, data, ret); @@ -631,6 +680,7 @@ case ENVCTRL_RD_VOLTAGE_STATUS: case ENVCTRL_RD_ETHERNET_TEMPERATURE: case ENVCTRL_RD_SCSI_TEMPERATURE: + case ENVCTRL_RD_GLOBALADDRESS: file->private_data = (void *)(long)cmd; break; @@ -729,9 +779,6 @@ if (!(strcmp(chnl_desc,"temp,ethernet"))) pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON; - - if (!(strcmp(chnl_desc,"temp,ethernet"))) - pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON; } /* Function Description: Initialize monitor channel with channel desc, @@ -785,6 +832,39 @@ pchild->mon_type[0] = ENVCTRL_FANSTAT_MON; } +/* Function Description: Initialize child device for global addressing line. + * Return: None. + */ +static void envctrl_init_globaladdr(struct i2c_child_t *pchild) +{ + int i; + + /* Voltage/PowerSupply monitoring is piggybacked + * with Global Address on CompactPCI. See comments + * within envctrl_i2c_globaladdr for bit assignments. + * + * The mask is created here by assigning mask bits to each + * bit position that represents PCF8584_VOLTAGE_TYPE data. + * Channel numbers are not consecutive within the globaladdr + * node (why?), so we use the actual counter value as chnls_mask + * index instead of the chnl_array[x].chnl_no value. + * + * NOTE: This loop could be replaced with a constant representing + * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK). + */ + for (i = 0; i < pchild->total_chnls; i++) { + if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) { + pchild->voltage_mask |= chnls_mask[i]; + } + } + + /* We only need to know if this child has global addressing + * line monitored. We dont care which channels since we know + * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK). + */ + pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON; +} + /* Initialize child device monitoring voltage status. */ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) { @@ -832,6 +912,26 @@ } } + /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04) + * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is + * "For Factory Use Only." + * + * We ignore the node on these platforms by assigning the + * 'NULL' monitor type. + */ + if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) { + int len; + char prop[56]; + + len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); + if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) { + for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) { + pchild->mon_type[len] = ENVCTRL_NOMON; + } + return; + } + } + /* Get the monitor channels. */ len = prom_getproperty(node, "channels-in-use", (char *)pchild->chnl_array, PCF8584_MAX_CHANNELS*sizeof(struct pcf8584_channel)); @@ -843,6 +943,11 @@ envctrl_init_adc(pchild, node); break; + case PCF8584_GLOBALADDR_TYPE: + envctrl_init_globaladdr(pchild); + i = pchild->total_chnls; + break; + case PCF8584_FANSTAT_TYPE: envctrl_init_fanstat(pchild); i = pchild->total_chnls; @@ -940,6 +1045,18 @@ if (misc_register(&envctrl_dev)) { printk("envctrl: Unable to get misc minor %d\n", envctrl_dev.minor); + } + + /* Note above traversal routine post-incremented 'i' to accomodate + * a next child device, so we decrement before reverse-traversal of + * child devices. + */ + printk("envctrl: initialized "); + for (--i; i >= 0; --i) { + printk("[%s 0x%lx]%s", + (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : + ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), + i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); } return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.2.17/drivers/sbus/char/rtc.c Sat Sep 9 18:42:40 2000 +++ linux/drivers/sbus/char/rtc.c Sun Sep 10 14:49:10 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.13 1998/08/26 10:29:44 davem Exp $ +/* $Id: rtc.c,v 1.13.2.1 2000/08/18 23:40:04 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/ChangeLog.ips linux/drivers/scsi/ChangeLog.ips --- v2.2.17/drivers/scsi/ChangeLog.ips Sun Jun 11 21:44:15 2000 +++ linux/drivers/scsi/ChangeLog.ips Tue Sep 5 21:54:35 2000 @@ -1,7 +1,22 @@ IBM ServeRAID driver Change Log ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 4.20.14 - Update patch files for kernel 2.4.0-test5 + + 4.20.13 - Fix some failure cases / reset code + - Hook into the reboot_notifier to flush the controller + cache + + 4.20.03 - Rename version to coincide with new release schedules + - Performance fixes + - Fix truncation of /proc files with cat + - Merge in changes through kernel 2.4.0test1ac21 + + 4.10.13 - Fix for dynamic unload and proc file system + + 4.10.00 - Add support for ServeRAID 4M/4L + 4.00.06 - Fix timeout with initial FFDC command - + 4.00.05 - Remove wish_block from init routine - Use linux/spinlock.h instead of asm/spinlock.h for kernels 2.3.18 and later diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.2.17/drivers/scsi/ChangeLog.ncr53c8xx Fri Apr 21 12:46:28 2000 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Sat Sep 2 19:38:56 2000 @@ -1,12 +1,146 @@ -Wed Jul 21 1999 23:00 Gerard Roudier (groudier@club-internet.fr) - * revision 3.2a-2 - - merge of driver 3.2a-1 with linux-2.3.11-pre3 - -Sun May 9 15:00 1999 Gerard Roudier (groudier@club-internet.fr) - * revision 3.2a-1 - - Fix the misdetection of SYM53C875E (was detected as a 876). - - Set the actual host ID used for each host in the scsi host data - structure. The mid-layer SCSI driver needs this information. +Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.1 + - Provide OpenFirmare path through the proc FS on PPC. + - Remove trailing argument #2 from a couple of #undefs. + +Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.0 + - Remove the PROFILE C and SCRIPTS code. + This facility was not this useful and thus was not longer + desirable given the increasing complexity of the driver code. + - Merges from FreeBSD sym-1.6.2 driver: + * Clarify memory barriers needed by the driver for architectures + that implement a weak memory ordering. + - General cleanup: + Move definitions for barriers and IO/MMIO operations to the + sym53c8xx_defs.h header files. They are now shared by the + both drivers. + Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED. + +Thu May 11 12:30 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.3b + +Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2i + - Return value 1 (instead of 0) from the driver setup routine. + - Let the driver also attach controllers that have been set to + OFF in the NVRAM as it did prior to revision 3.2g. + +Sat Apr 1 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2h + - Fix a compilation problem on Alpha introduced in version 3.2g. + (`port' changed to `base_io'). + - Move from `sym' to this driver a tiny change for __sparc__ that + applies to cache line size (? Probably from David S Miller). + - Make sure no data transfer will happen for Scsi_Cmnd requests + that supply SCSI_DATA_NONE direction (this avoids some BUG() + statement in the PCI code when a data buffer is also supplied). + +Thu Mar 16 9:30 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.3b-3 + - Added exclusion for the 53C1010 and 53C1010_66 chips + to the driver (change to sym53c8xx_comm.h). + +Mon March 6 23:15 2000 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2g + - Add the file sym53c8xx_comm.h that collects code that should + be shared by sym53c8xx and ncr53c8xx drivers. For now, it is + a header file that is only included by the ncr53c8xx driver, + but things will be cleaned up later. This code addresses + notably: + * Chip detection and PCI related initialisations + * NVRAM detection and reading + * DMA mapping + * Boot setup command + * And some other ... + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) when this information is available. + +Mon March 6 23:15 2000 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2g + - Add the file sym53c8xx_comm.h that collects code that should + be shared by sym53c8xx and ncr53c8xx drivers. For now, it is + a header file that is only included by the ncr53c8xx driver, + but things will be cleaned up later. This code addresses + notably: + * Chip detection and PCI related initialisations + * NVRAM detection and reading + * DMA mapping + * Boot setup command + * And some other ... + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) when this information is available. + +Fri Jan 14 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * revision pre-3.3b-1 + - Merge parallel driver series 3.31 and 3.2e + +Tue Jan 11 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.31 + - Added support for mounting disks on wide-narrow-wide + scsi configurations. + - Built off of version 3.30 + +Mon Jan 10 13:30 2000 Pam Delaney (pam.delaney@lsil.com) + * revision 3.30 + - Added capability to use the integrity checking code + in the kernel (optional). + - Disabled support for the 53C1010. + - Built off of version 3.2c + +Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2e + - Add year 2000 copyright. + - Display correctly bus signals when bus is detected wrong. + - Remove the dead code that broke driver 3.2d. + +Mon Dec 6 22:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2d + - Change messages written by the driver at initialisation and + through the /proc FS (rather cosmetic changes that consist in + printing out the PCI bus number and device/function). + - Get rid of the old PCI bios interface, but preserve kernel 2.0 + compatibility from a simple wrapper. + - Remove the compilation condition about having to acquire the + io_request_lock since it seems to be a definite feature now.:) + - proc_dir structure no longer needed for kernel >= 2.3.27. + - Change the driver detection code by the sym53c8xx one, modulo + some minor changes. The driver can now attach any number of + controllers (>40) and does no longer hoger stack space at + initialisation. + - Definitely disable overlapped PCI arbitration for all dual + function chips, since I cannot make sure for what chip revisions + it is actually safe. + - Add support for the SYM53C1510D. + - Update the poor Tekram sync factor table. + - Remove the compilation condition about having to acquire the + io_request_lock since it seems to be a definite feature now.:) + - proc_dir structure no longer needed for kernel >= 2.3.27. + +Sat Sep 11 18:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2c + - Handle correctly (hopefully) jiffies wrap-around. + - Restore the entry used to detect 875 until revision 0xff. + (I removed it inadvertently, it seems :) ) + - Replace __initfunc() which is deprecated stuff by __init which + is not yet so. ;-) + - Add support of some 'resource handling' for linux-2.3.13. + Basically the BARs have been changed to something more complex + in the pci_dev structure. + - Remove some deprecated code. + +Sat May 10 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision pre-3.2b-1 + - Support for the 53C895A by Pamela Delaney + The 53C895A contains all of the features of the 896 but has only + one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing + using dual cycle PCI data transfers. + - Miscellaneous minor fixes. + - Some additions to the README.ncr53c8xx file. Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr) * revision 3.2a diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx --- v2.2.17/drivers/scsi/ChangeLog.sym53c8xx Fri Apr 21 12:46:28 2000 +++ linux/drivers/scsi/ChangeLog.sym53c8xx Sat Sep 2 19:38:56 2000 @@ -1,23 +1,279 @@ -Sat Jul 24 12:00 1999 Gerard Roudier (groudier@club-internet.fr) - * version sym53c8xx-1.3g - - merge of driver 1.3f with linux-2.2.11-pre3 - - remove the broken testing of the chip being connected to SCSI - from the SCSI interrupt handling code. +Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.1 + - Provide OpenFirmare path through the proc FS on PPC. + - Download of on-chip SRAM using memcpy_toio() doesn't work + on PPC. Restore previous method (MEMORY MOVE from SCRIPTS). + - Remove trailing argument #2 from a couple of #undefs. -Sun May 9 15:00 1999 Gerard Roudier (groudier@club-internet.fr) - * version sym53c8xx-1.3f +Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.0 + - Remove the PROFILE C and SCRIPTS code. + This facility was not this useful and thus was not longer + desirable given the increasing complexity of the driver code. + - Merges from FreeBSD sym-1.6.2 driver: + * Clarify memory barriers needed by the driver for architectures + that implement a weak memory ordering. + * Simpler handling of illegal phases and data overrun from + SCRIPTS. These errors are now immediately reported to + the C code by an interrupt. + * Sync the residual handling code with sym-1.6.2 and now + report `resid' to user for linux version >= 2.3.99 + - General cleanup: + Move definitions for barriers and IO/MMIO operations to the + sym53c8xx_defs.h header files. They are now shared by the + both drivers. + Remove unused options that claimed to optimize for the 896. + If fact, they were not this clever. :) + Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED. + Remove a couple of unused fields from data structures. + +Thu May 11 12:40 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.6b + - Merged version. + +Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5m + - Return value 1 (instead of 0) from the driver setup routine. + - Donnot enable PCI DAC cycles. This just broke support for + SYM534C896 on sparc64. Problem fixed by David S. Miller. + +Fri Apr 14 9:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.6b-9 + - Added 53C1010_66 support. + - Small fix to integrity checking code. + - Removed requirement for integrity checking if want to run + at ultra 3. + +Sat Apr 1 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5l + - Tiny change for __sparc__ appeared in 2.3.99-pre4.1 that + applies to cache line size (? Probably from David S Miller). + - Make sure no data transfer will happen for Scsi_Cmnd requests + that supply SCSI_DATA_NONE direction (this avoids some BUG() + statement in the PCI code when a data buffer is also supplied). + +Sat Mar 11 12:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.6b-5 + - Test against expected data transfer direction from SCRIPTS. + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + Many thanks to David S. Miller for his preliminary changes + that have been useful guidelines. + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) with kernels that provide this information. + +Mon Mar 6 23:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5k + - Test against expected data transfer direction from SCRIPTS. + - Revert the change in 'ncr_flush_done_cmds()' but unmap the + scsi dma buffer prior to queueing the command to our done + list. + - Miscellaneous (minor) fixes in the code added in driver + version 1.5j. + +Mon Feb 14 4:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-pre-1.6b-2. + - Updated the SCRIPTS error handling of the SWIDE + condition - to remove any reads of the sbdl + register. Changes needed because the 896 and 1010 + chips will check parity in some special circumstances. + This will cause a parity error interrupt if not in + data phase. Changes based on those made in the + FreeBSD driver version 1.3.2. + +Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5j + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + Many thanks to David S. Miller for his preliminary changes + that have been useful guidelines, for having reviewed the + code and having tested this driver version on Ultra-Sparc. + - 2 tiny bugs fixed in the PCI wrapper that provides support + for early kernels without pci device structure. + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) with kernels that provide this information. + - Fix an old bug that only affected 896 rev. 1 when driver + profile support option was set in kernel configuration. + +Fri Jan 14 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-pre-1.6b-1. + - Merge parallel driver series 1.61 and 1.5e + +Tue Jan 11 14:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.61 + - Added support for mounting disks on wide-narrow-wide + scsi configurations. + - Modified offset to be a maximum of 31 in ST mode, + 62 in DT mode. + - Based off of 1.60 + +Mon Jan 10 10:00 2000 Pam Delaney (pam.delaney@lsil.com) + * version sym53c8xx-1.60 + - Added capability to use the integrity checking code + in the kernel (optional). + - Added PPR negotiation. + - Added support for 53C1010 Ultra 3 part. + - Based off of 1.5f + +Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5h + - Add year 2000 copyright. + - Display correctly bus signals when bus is detected wrong. + - Some fix for Sparc from DSM that went directly to kernel tree. + +Mon Dec 6 22:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5g + - Change messages written by the driver at initialisation and + through the /proc FS (rather cosmetic changes that consist in + printing out the PCI bus number and PCI device/function). + - Ensure the SCRIPTS processor is stopped while calibrating the + SCSI clock (the initialisation code has been a bit reworked). + Change moved to the FreeBSD sym_hipd driver). + - Some fixes in the MODIFY_DP/IGN_RESIDUE code and residual + calculation (moved from FreeBSD sym_hipd driver). + - Add NVRAM support for Tekram boards that use 24C16 EEPROM. + Code moved from the FreeBSD sym_hipd driver, since it has + been that one that got this feature first. + - Definitely disable overlapped PCI arbitration for all dual + function chips, since I cannot make sure for what chip revisions + it is actually safe. + - Add support for the SYM53C1510D (also for ncr53c8xx). + - Fix up properly the PCI latency timer when needed or asked for. + - Get rid of the old PCI bios interface, but preserve kernel 2.0 + compatibility from a simple wrapper. + - Update the poor Tekram sync factor table. + - Fix in a tiny 'printk' bug that may oops in case of extended + errors (unrecovered parity error, data overrun, etc ...) + (Sent by Pamela Delaney from LSILOGIC) + - Remove the compilation condition about having to acquire the + io_request_lock since it seems to be a definite feature now.:) + - Change get_pages by GetPages since Linux >= 2.3.27 now wants + get_pages to ever be used as a kernel symbol (from 2.3.27). + - proc_dir structure no longer needed for kernel >= 2.3.27. + +Sun Oct 3 19:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5f + - Change the way the driver checks the PCI clock frequency, so + that overclocked PCI BUS up to 48 MHz will not be refused. + The more the BUS is overclocked, the less the driver will + guarantee that its measure of the SCSI clock is correct. + - Backport some minor improvements of SCRIPTS from the sym_hipd + driver. + - Backport the code rewrite of the START QUEUE dequeuing (on + bad scsi status received) from the sym_hipd driver. + +Sat Sep 11 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5e + - New linux-2.3.13 __setup scheme support added. + - Cleanup of the extended error status handling: + Use 1 bit per error type. + - Also save the extended error status prior to auto-sense. + - Add the FE_DIFF chip feature bit to indicate support of + diff probing from GPIO3 (825/825A/876/875). + - Remove the quirk handling that has been useless since day one. + - Work-around PCI chips being reported twice on some platforms. + - Add some redundant PCI reads in order to deal with common + bridge misbehaviour regarding posted write flushing. + - Add some other conditionnal code for people who have to deal + with really broken bridges (they will have to edit a source + file to try these options). + - Handle correctly (hopefully) jiffies wrap-around. + - Restore the entry used to detect 875 until revision 0xff. + (I removed it inadvertently, it seems :) ) + - Replace __initfunc() which is deprecated stuff by __init which + is not yet so. ;-) + - Rewrite the MESSAGE IN scripts more generic by using a MOVE + table indirect. Extended messages of any size are accepted now. + (Size is limited to 8 for now, but a constant is just to be + increased if necessary) + - Fix some bug in the fully untested MDP handling:) and share + some code between MDP handling and residual calculation. + - Calculate the data transfer residual as the 2's complement + integer (A positive value in returned on data overrun, and + a negative one on underrun). + - Add support of some 'resource handling' for linux-2.3.13. + Basically the BARs have been changed to something more complex + in the pci_dev structure. + - Remove some deprecated code. + +Sat Jun 5 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5c + - Donnot negotiate on auto-sense if we are currently using 8 bit + async transfer for the target. + - Only check for SISL/RAID on i386 platforms. + (A problem has been reported on PPC with that code). + - On MSG REJECT for a negotiation, the driver attempted to restart + the SCRIPT processor when this one was already running. + +Sat May 29 12:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5b + - Force negotiation prior auto-sense. + This ensures that the driver will be able to grab the sense data + from a device that has received a BUS DEVICE RESET message from + another initiator. + - Complete all disconnected CCBs for a logical UNIT if we are told + about a UNIT ATTENTION for a RESET condition by this target. + - Add the control command 'cleardev' that allows to send a ABORT + message to a logical UNIT (for test purpose). + +Tue May 25 23:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5a + - Add support for task abort and bus device reset SCSI message + and implement proper synchonisation with SCRIPTS to handle + correctly task abortion without races. + - Send an ABORT message (if untagged) or ABORT TAG message (if tagged) + when the driver is told to abort a command that is disconnected and + complete the command with appropriate error. + If the aborted command is not yet started, remove it from the start + queue and complete it with error. + - Add the control command 'resetdev' that allows to send a BUS + DEVICE RESET message to a target (for test purpose). + - Clean-up some unused or useless code. + +Fri May 21 23:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5 + - Add support for CHMOV with Wide controllers. + - Handling of the SWIDE (low byte residue at the end of a CHMOV + in DATA IN phase with WIDE transfer when the byte count gets odd). + - Handling of the IGNORE WIDE RESIDUE message. + Handled from SCRIPTS as possible with some optimizations when both + a wide device and the controller are odd at the same time (SWIDE + present and IGNORE WIDE RESIDUE message on the BUS at the same time). + - Check against data OVERRUN/UNDERRUN condition at the end of a data + transfer, whatever a SWIDE is present (OVERRUN in DATA IN phase) + or the SODL is full (UNDERRUN in DATA out phase). + - Handling of the MODIFY DATA POINTER message. + This one cannot be handled from SCRIPTS, but hopefully it will not + happen very often. :) + - Large rewrite of the SCSI MESSAGE handling. + +Sun May 9 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.4 + - Support for IMMEDIATE ARBITRATION. + See the README file for detailed information about this feature. + Requires both a compile option and a boot option. + - Minor SCRIPTS optimization in reselection pattern for LUN 0. + - Simpler algorithm to deal with SCSI command starvation. + Just use 2 tag counters in flip/flop and switch to the other + one every 3 seconds. + - Do some work in SCRIPTS after the SELECT instruction and prior + to testing for a PHASE. SYMBIOS say this feature is working fine. + (Btw, only problems with Toshiba 3401B had been reported). + - Measure the PCI clock speed and donnot attach controllers if + result is greater than 37 MHz. Since the precision of the + algorithm (from Stefan Esser) is better than 2%, this should + be fine. - Fix the misdetection of SYM53C875E (was detected as a 876). - Fix the misdetection of SYM53C810 not A (was detected as a 810A). + - Support for up to 256 TAGS per LUN (CMD_PER_LUN). + Currently limited to 255 due to Linux limitation. :) + - Support for up to 508 active commands (CAN_QUEUE). - Support for the 53C895A by Pamela Delaney The 53C895A contains all of the features of the 896 but has only one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing using dual cycle PCI data transfers. - - Call request_region() event if MMIO is used and not normal IO. - This allows sym and the ncr driver to be loaded in any order - without any risk of attaching the same device. - - Set the actual host ID used for each host in the scsi host data - structure. The mid-layer SCSI driver needs this information. - Miscellaneous minor fixes. + - Some additions to the README.ncr53c8xx file. Tue Apr 15 10:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.3e diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.2.17/drivers/scsi/Config.in Fri Apr 21 12:46:28 2000 +++ linux/drivers/scsi/Config.in Fri Sep 15 22:44:39 2000 @@ -43,6 +43,9 @@ if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then bool ' Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT fi +if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate 'Compaq Fibre Channel 64-bit/66Mhz HBA support' CONFIG_SCSI_CPQFCTS $CONFIG_SCSI +fi dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI if [ "$CONFIG_SCSI_EATA" != "n" ]; then @@ -94,7 +97,6 @@ int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 - bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then bool ' include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.2.17/drivers/scsi/Makefile Fri Apr 21 12:46:30 2000 +++ linux/drivers/scsi/Makefile Fri Sep 15 22:44:39 2000 @@ -5,6 +5,10 @@ # unless it's something special (ie not a .c file). # +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + L_TARGET := scsi.a L_OBJS := M_OBJS := @@ -273,6 +277,7 @@ endif endif + ifeq ($(CONFIG_SCSI_QLOGIC_FAS),y) L_OBJS += qlogicfas.o else @@ -322,6 +327,14 @@ endif endif +ifeq ($(CONFIG_SCSI_CPQFCTS),y) +L_OBJS += cpqfc.o +else + ifeq ($(CONFIG_SCSI_CPQFCTS),m) + M_OBJS += cpqfc.o + endif +endif + ifeq ($(CONFIG_SCSI_AHA152X),y) L_OBJS += aha152x.o else @@ -682,6 +695,28 @@ sim710.o : sim710_d.h +# if we have a triggerable HBA (extra circuit addition for +# TTL level output on GPIO line), build in the trigger file + +#CPQTRIGGER_FILE = cpqfcTStrigger.c + +CPQTRIG = cpqfcTStrigger.o + +cpqfcTStrigger.o: cpqfcTStrigger.c + +cpqfcTSinit.o: cpqfcTSinit.c cpqfcTSstructs.h cpqfcTSchip.h cpqfcTSioctl.h + +cpqfcTScontrol.o: cpqfcTScontrol.c cpqfcTSstructs.h cpqfcTSchip.h + +cpqfcTSi2c.o: cpqfcTSi2c.c cpqfcTSchip.h + +cpqfcTSworker.o: cpqfcTSworker.c cpqfcTSchip.h cpqfcTSstructs.h cpqfcTSioctl.h + +cpqfc.o: cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o cpqfcTSworker.o $(CPQTRIG) + $(LD) -r -o cpqfc.o cpqfcTSinit.o cpqfcTScontrol.o \ + cpqfcTSi2c.o cpqfcTSworker.o $(CPQTRIG) + + initio.o: ini9100u.c i91uscsi.c $(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o @@ -705,3 +740,4 @@ sd_mod.o: sd.o sd_ioctl.o $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o + diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/README.ibmmca linux/drivers/scsi/README.ibmmca --- v2.2.17/drivers/scsi/README.ibmmca Fri Apr 21 12:46:31 2000 +++ linux/drivers/scsi/README.ibmmca Sat Jul 29 18:07:34 2000 @@ -10,10 +10,10 @@ General Public License. Originally written by Martin Kolinek, December 1995. Officially maintained by Michael Lang since January 1999. - Version 3.1e + Version 3.2 - Last update: 20 February 1999 + Last update: 29 July 2000 Authors of this Driver @@ -23,7 +23,8 @@ - Klaus Kudielka (multiple SCSI-host management/detection, adaption to Linux Kernel 2.1.x, module support) - Michael Lang (assigning original pun,lun mapping, dynamical ldn - assignment, this file, patch, official driver maintenance) + assignment, this file, patch, official driver maintenance + and subsequent pains related with the driver :-)) Table of Contents ----------------- @@ -51,7 +52,11 @@ 5.3 Bugreports 5.4 Support WWW-page 6 References - 7 Trademarks + 7 Credits to + 7.1 People + 7.2 Sponsors & Supporters + 8 Trademarks + 9 Disclaimer * * * @@ -64,7 +69,7 @@ quite outdated. The history of the driver development is also kept inside here. Multiple historical developments have been summarized to shorten the textsize a bit. At the end of this file you can find a small manual for - this driver and hints to get it running even on your machine (hopefully). + this driver and hints to get it running on your machine. 2 Driver Description -------------------- @@ -74,27 +79,35 @@ Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the Microchannel. In a next step, a free interrupt is chosen and the main interrupt handler is connected to it to handle answers of the SCSI- - subsystem(s). In a further step, it is checked, wether there was a forced - detection of the adapter via the kernel commandline, where the I/O port - and the SCSI-subsystem id can be specified. The next step checks if there - is an integrated SCSI-subsystem installed. This register area is fixed - through all IBM PS/2 MCA-machines and appears as something like a virtual - slot 10 of the MCA-bus. If POS-register 2 is not 0xff, there must be a SCSI- + subsystem(s). If the F/W SCSI-adapter is forced by the BIOS to use IRQ11 + instead of IRQ14, IRQ11 is used for the IBM SCSI-2 F/W adapter. In a + further step it is checked, if the adapter gets detected by force from + the kernel commandline, where the I/O port and the SCSI-subsystem id can + be specified. The next step checks if there is an integrated SCSI-subsystem + installed. This register area is fixed through all IBM PS/2 MCA-machines + and appears as something like a virtual slot 10 of the MCA-bus. On most + PS/2 machines, the POS registers of slot 10 are set to 0xff or 0x00 if not + integrated SCSI-controller is available. But on certain PS/2s, like model + 9595, this slot 10 is used to store other information which at earlier + stage confused the driver and resulted in the detection of some ghost-SCSI. + If POS-register 2 and 3 are not 0x00 and not 0xff, but all other POS + registers are either 0xff or 0x00, there must be an integrated SCSI- subsystem present and it will be registered as IBM Integrated SCSI- Subsystem. The next step checks, if there is a slot-adapter installed on the MCA-bus. To get this, the first two POS-registers, that represent the adapter ID are checked. If they fit to one of the ids, stored in the - adapter list, a SCSI-subsystem is assumed to be found and will be + adapter list, a SCSI-subsystem is assumed to be found in a slot and will be registered. This check is done through all possible MCA-bus slots to allow more than one SCSI-adapter to be present in the PS/2-system and this is already the first point of problems. Looking into the technical reference manual for the IBM PS/2 common interfaces, the POS2 register must have - different interpretation of its single bits. While one can assume, that the - integrated subsystem has a fix I/O-address at 0x3540 - 0x3547, further - installed IBM SCSI-adapters must use a different I/O-address. This is - expressed by bit 1 to 3 of POS2 (multiplied by 8 + 0x3540). Bits 2 and 3 - are reserved for the integrated subsystem, but not for the adapters! The - following list shows, how the bits of POS2 and POS3 should be interpreted. + different interpretation of its single bits to avoid overlapping I/O + regions. While one can assume, that the integrated subsystem has a fix + I/O-address at 0x3540 - 0x3547, further installed IBM SCSI-adapters must + use a different I/O-address. This is expressed by bit 1 to 3 of POS2 + (multiplied by 8 + 0x3540). Bits 2 and 3 are reserved for the integrated + subsystem, but not for the adapters! The following list shows, how the + bits of POS2 and POS3 should be interpreted. The POS2-register of all PS/2 models' integrated SCSI-subsystems has the following interpretation of bits: @@ -102,20 +115,25 @@ Bit 3 - 2 : Reserved Bit 1 : 8k NVRAM Disabled Bit 0 : Chip Enable (EN-Signal) - The POS3-register is interpreted as follows (for ALL IBM SCSI-subsys.): + The POS3-register is interpreted as follows (for most IBM SCSI-subsys.): Bit 7 - 5 : SCSI ID Bit 4 - 0 : Reserved = 0 - (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common - Interfaces (1991)"). - In short words, this means, that IBM PS/2 machines only support 1 single - subsystem by default. But (additional) slot-adapters must have another - configuration on pos2 in order to be enabled to use more than one IBM SCSI- - subsystem, e.g. for a network server. From tests with the IBM SCSI Adapter - w/cache, the POS2-register for slot adapters should be interpreted in the - following way: - Bit 7 - 4 : Chip Revision ID (Release) - Bit 3 - 1 : port offset factor ( * 8 + 0x3540 ) - Bit 0 : Chip Enable (EN-Signal) + The slot-adapters have different interpretation of these bits. The IBM SCSI + adapter (w/Cache) and the IBM SCSI-2 F/W adapter use the following + interpretation of the POS2 register: + Bit 7 - 4 : ROM Segment Address Select + Bit 3 - 1 : Adapter I/O Address Select (*8+0x3540) + Bit 0 : Adapter Enable (EN-Signal) + and for the POS3 register: + Bit 7 - 5 : SCSI ID + Bit 4 : Fairness Enable (SCSI ID3 f. F/W) + Bit 3 - 0 : Arbitration Level + The most modern product of the series is the IBM SCSI-2 F/W adapter, it + allows dual-bus SCSI and SCSI-wide addressing, which means, PUNs may be + between 0 and 15. Here, Bit 4 is the high-order bit of the 4-bit wide + adapter PUN expression. In short words, this means, that IBM PS/2 machines + can only support 1 single integrated subsystem by default. Additional + slot-adapters get ports assigned by the automatic configuration tool. One day I found a patch in ibmmca_detect(), forcing the I/O-address to be 0x3540 for integrated SCSI-subsystems, there was a remark placed, that on @@ -156,12 +174,18 @@ number or pun, also called the scsi id, this is the number you select with hardware jumpers), and each physical unit can have up to 8 "logical units" (each identified by logical unit number, or lun, - between 0 and 7). + between 0 and 7). The IBM SCSI-2 F/W adapter offers this on up to two + busses and provides support for 30 logical devices at the same time, where + in wide-addressing mode you can have 16 puns with 32 luns on each device. + This section dexribes you the handling of devices on non-F/W adapters. + Just imagine, that you can have 16 * 32 = 512 devices on a F/W adapter + which means a lot of possible devices for such a small machine. Typically the adapter has pun=7, so puns of other physical units - are between 0 and 6. Almost all physical units have only one - logical unit, with lun=0. A CD-ROM jukebox would be an example of - a physical unit with more than one logical unit. + are between 0 and 6(15). On a wide-adapter a pun higher than 7 is + possible, but is normally not used. Almost all physical units have only + one logical unit, with lun=0. A CD-ROM jukebox would be an example of a + physical unit with more than one logical unit. The embedded microprocessor of the IBM SCSI-subsystem hides the complex two-dimensional (pun,lun) organization from the operating system. @@ -169,7 +193,8 @@ checks, on its own, all 56 possible (pun,lun) combinations, and the first 15 devices found are assigned into a one-dimensional array of so-called "logical devices", identified by "logical device numbers" or ldn. The last - ldn=15 is reserved for the subsystem itself. + ldn=15 is reserved for the subsystem itself. Wide adapters may have + to check up to 15 * 8 = 120 pun/lun combinations. 2.3 SCSI-Device Recognition and dynamical ldn Assignment -------------------------------------------------------- @@ -177,8 +202,12 @@ numbers are also hidden. The two possibilities to get around this problem is to offer fake pun/lun combinations to the operating system or to delete the whole mapping of the adapter and to reassign the ldns, using - the immediate assign command of the SCSI-subsystem. At the beginning of the - development of this driver, the following approach was used: + the immediate assign command of the SCSI-subsystem for probing through + all possible pun/lun combinations. a ldn is a "logical device number" + which is used by IBM SCSI-subsystems to access some valid SCSI-device. + At the beginning of the development of this driver, the following approach + was used: + First, the driver checked the ldn's (0 to 6) to find out which ldn's have devices assigned. This was done by the functions check_devices() and device_exists(). The interrupt handler has a special paragraph of code @@ -199,7 +228,7 @@ and later, realizes the device recognition in the following way: The physical SCSI-devices on the SCSI-bus are probed via immediate_assign- and device_inquiry-commands, that is all implemented in a completely new - made check_devices() subroutine. This delivers a exact map of the physical + made check_devices() subroutine. This delivers an exact map of the physical SCSI-world that is now stored in the get_scsi[][]-array. This means, that the once hidden pun,lun assignment is now known to this driver. It no longer believes in default-settings of the subsystem and maps all @@ -230,7 +259,7 @@ can be different from the old, faked puns. Therefore, Linux will eventually change /dev/sdXXX assignments and prompt you for corrupted superblock repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!! - You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file + You have to reboot (CTRL-D) with an old kernel and set the /etc/fstab-file entries right. After that, the system should come up as errorfree as before. If your boot-partition is not coming up, also edit the /etc/lilo.conf-file in a Linux session booted on old kernel and run lilo before reboot. Check @@ -332,17 +361,19 @@ ---------------------------------- The following IBM SCSI-subsystems are supported by this driver: - - IBM Fast SCSI-2 Adapter + - IBM Fast/Wide SCSI-2 Adapter - IBM 7568 Industrial Computer SCSI Adapter w/cache - IBM Expansion Unit SCSI Controller - IBM SCSI Adapter w/Cache - IBM SCSI Adapter - IBM Integrated SCSI Controller + - All clones, 100% compatible with the chipset and subsystem command + system of IBM SCSI-adapters (forced detection) 2.14 Linux Kernel Versions -------------------------- The IBM SCSI-subsystem low level driver is prepared to be used with - all versions of Linux between 2.0.x and 2.2.x. The compatibility checks + all versions of Linux between 2.0.x and 2.4.x. The compatibility checks are fully implemented up from version 3.1e of the driver. This means, that you just need the latest ibmmca.h and ibmmca.c file and copy it in the linux/drivers/scsi directory. The code is automatically adapted during @@ -717,18 +748,149 @@ addition more flexibility. - Michael Lang + Apr 23, 2000 (v3.2pre1) + 1) During a very long time, I collected a huge amount of bugreports from + various people, trying really quite different things on their SCSI- + PS/2s. Today, all these bugreports are taken into account and should be + mostly solved. The major topics were: + - Driver crashes during boottime by no obvious reason. + - Driver panics while the midlevel-SCSI-driver is trying to inquire + the SCSI-device properties, even though hardware is in perfect state. + - Displayed info for the various slot-cards is interpreted wrong. + The main reasons for the crashes were two: + 1) The commands to check for device information like INQUIRY, + TEST_UNIT_READY, REQUEST_SENSE and MODE_SENSE cause the devices + to deliver information of up to 255 bytes. Midlevel drivers offer + 1024 bytes of space for the answer, but the IBM-SCSI-adapters do + not accept this, as they stick quite near to ANSI-SCSI and report + a COMMAND_ERROR message which causes the driver to panic. The main + problem was located around the INQUIRY command. Now, for all the + mentioned commands, the buffersize, sent to the adapter is at + maximum 255 which seems to be a quite reasonable solution. + TEST_UNIT_READY gets a buffersize of 0 to make sure, that no + data is transferred in order to avoid any possible command failure. + 2) On unsuccessful TEST_UNIT_READY, the midlevel-driver has to send + a REQUEST_SENSE in order to see, where the problem is located. This + REQUEST_SENSE may have various length in its answer-buffer. IBM + SCSI-subsystems report a command failure, if the returned buffersize + is different from the sent buffersize, but this can be supressed by + a special bit, which is now done and problems seem to be solved. + 2) Code adaption to all kernel-releases. Now, the 3.2 code compiles on + 2.0.x, 2.1.x, 2.2.x and 2.3.x kernel releases without any code-changes. + 3) Commandline-parameters are recognized again, even under Kernel 2.3.x or + higher. + - Michael Lang + + April 27, 2000 (v3.2pre2) + 1) Bypassed commands get read by the adapter by one cycle instead of two. + This increases SCSI-performance. + 2) Synchronous datatransfer is provided for sure to be 5 MHz on older + SCSI and 10 MHz on internal F/W SCSI-adapter. + 3) New commandline parameters allow to force the adapter to slow down while + in synchronous transfer. Could be helpful for very old devices. + - Michael Lang + + June 2, 2000 (v3.2pre5) + 1) Added Jim Shorney's contribution to make the activity indicator + flashing in addition to the LED-alphanumeric display-panel on + models 95A. To be enabled to choose this feature freely, a new + commandline parameter is added, called 'activity'. + 2) Added the READ_CONTROL bit for test_unit_ready SCSI-command. + 3) Added some suppress_exception bits to read_device_capacity and + all device_inquiry occurences in the driver code. + 4) Complaints about the various KERNEL_VERSION implementations are + taken into account. Every local_LinuxKernelVersion occurence is + now replaced by KERNEL_VERSION, defined in linux/version.h. + Corresponding changes were applied to ibmmca.h, too. This was a + contribution to all kernel-parts by Philipp Hahn. + - Michael Lang + + July 17, 2000 (v3.2pre8) + A long period of collecting bugreports from all corners of the world + now lead to the following corrections to the code: + 1) SCSI-2 F/W support crashed with a COMMAND ERROR. The reason for this + was, that it is possible to disbale Fast-SCSI for the external bus. + The feature-control command, where this crash appeared regularly tried + to set the maximum speed of 10MHz synchronous transfer speed and that + reports a COMMAND ERROR, if external bus Fast-SCSI is disabled. Now, + the feature-command probes down from maximum speed until the adapter + stops to complain, which is at the same time the maximum possible + speed selected in the reference program. So, F/W external can run at + 5 MHz (slow-) or 10 MHz (fast-SCSI). During feature probing, the + COMMAND ERROR message is used to detect if the adapter does not complain. + 2) Up to now, only combined busmode is supported, if you use external + SCSI-devices, attached to the F/W-controller. If dual bus is selected, + only the internal SCSI-devices get accessed by Linux. For most + applications, this should do fine. + 3) Wide-SCSI-addressing (16-Bit) is now possible for the internal F/W + bus on the F/W adapter. If F/W adapter is detected, the driver + automatically uses the extended PUN/LUN <-> LDN mapping tables, which + are now new from 3.2pre8. This allows PUNs between 0 and 15 and should + provide more fun with the F/W adapter. + 4) Several machines use the SCSI: POS registers for internal/undocumented + storage of system relevant info. This confused the driver, mainly on + models 9595, as it expected no onboard SCSI only, if all POS in + the integrated SCSI-area are set to 0x00 or 0xff. Now, the mechanism + to check for integrated SCSI is much more restrictive and these problems + should be history. + - Michael Lang + + July 18, 2000 (v3.2pre9) + This develop rather quickly at the moment. Two major things were still + missing in 3.2pre8: + 1) The adapter PUN for F/W adapters has 4-bits, while all other adapters + have 3-bits. This is now taken into account for F/W. + 2) When you select CONFIG_IBMMCA_SCSI_ORDER_STANDARD, you should + normally get the inverse probing order of your devices on the SCSI-bus. + The ANSI device order gets scrambled in version 3.2pre8!! Now, a new + and tested algorithm inverts the device-order on the SCSI-bus and + automatically avoids accidental access to whatever SCSI PUN the adapter + is set and works with SCSI- and Wide-SCSI-addressing. + - Michael Lang + + July 23, 2000 (v3.2pre10 unpublished) + 1) LED panel display supports wide-addressing in ibmmca=display mode. + 2) Adapter-information and autoadaption to address-space is done. + 3) Auto-probing for maximum synchronous SCSI transfer rate is working. + 4) Optimization to some embedded function calls is applied. + 5) Added some comment for the user to wait for SCSI-devices beeing probed. + 6) Finished version 3.2 for Kernel 2.4.0. It least, I thought it is but... + - Michael Lang + + July 26, 2000 (v3.2pre11) + 1) I passed a horrible weekend getting mad with NMIs on kernel 2.2.14 and + a model 9595. Asking around in the community, nobody except of me has + seen such errors. Weired, but I am trying to recompile everything on + the model 9595. Maybe, as I use a specially modified gcc, that could + cause problems. But, it was not the reason. The true background was, + that the kernel was compiled for i386 and the 9595 has a 486DX-2. + Normally, no troubles should appear, but for this special machine, + only the right processor support is working fine! + 2) Previous problems with synchronous speed, slowing down from one adapter + to the next during probing are corrected. Now, local variables store + the synchronous bitmask for every single adapter found on the MCA bus. + 3) LED alphanumeric panel support for XX95 systems is now showing some + alive rotator during boottime. This makes sense, when no monitor is + connected to the system. You can get rid of all display activity, if + you do not use any parameter or just ibmmcascsi=activity, for the + harddrive activity LED, existant on all PS/2, except models 8595-XXX. + If no monitor is available, please use ibmmcascsi=display, which works + fine together with the linuxinfo utility for the LED-panel. + - Michael Lang + + July 29, 2000 (v3.2) + 1) Submission of this driver for kernel 2.4test-XX and 2.2.17. + - Michael Lang + 4 To do ------- + - IBM SCSI-2 F/W external SCSI bus support in seperate mode. - It seems that the handling of bad disks is really bad - non-existent, in fact. - More testing of the full driver-controlled dynamical ldn - (re)mapping for up to 56 SCSI-devices. - - Support more of the SCSI-command set. - - Support some of the caching abilities, particularly Read Prefetch. - This fetches data into the cache, which later gets hit by the - regular Read Data. (<--- This is coming soon!!!!) - - Abort and Reset functions still slightly buggy or better say, - it is the new episode, called SCREAM III. + (re)mapping for up to 56 SCSI-devices. I guess, it won't work + at the moment, but nobody ever really tried it. + - Abort and Reset functions still slightly buggy. 5 Users' Manual --------------- @@ -749,7 +911,13 @@ where '-' stays dark, 'D' shows the SCSI-device id and 'A' shows the SCSI hostindex, beeing currently - accessed. + accessed. During boottime, this will give the message + + SCSIini* + + on the LED-panel, where the * represents a rotator, + showing the activity during the probing phase of the + driver which can take up to two minutes per SCSI-adapter. adisplay This works like display, but gives more optical overview of the activities on the SCSI-bus. The display will have the following output: @@ -761,7 +929,22 @@ hostindex. If display nor adisplay is set, the internal PS/2 harddisk LED is used for media-activities. So, if you really do not have a system with a LED-display, you - should not set display or adisplay. + should not set display or adisplay. Keep in mind, that + display and adisplay can only be used alternatively. It + is not recommended to use this option, if you have some + wide-addressed devices e.g. at the SCSI-2 F/W adapter in + your system. In addition, the usage of the display for + other tasks in parallel, like the linuxinfo-utility makes + no sense with this option. + activity This enables the PS/2 harddisk LED activity indicator. + Most PS/2 have no alphanumeric LED display, but some + indicator. So you should use this parameter to activate it. + If you own model 9595 (Server95), you can have both, the + LED panel and the activity indicator in parallel. However, + some PS/2s, like the 8595 do not have any harddisk LED + activity indicator, which means, that you must use the + alphanumeric LED display if you want to monitor SCSI- + activity. bypass This commandline parameter forces the driver never to use SCSI-subsystems' integrated SCSI-command set. Except of the immediate assign, which is of vital importance for @@ -775,7 +958,10 @@ this flag will slow-down SCSI-accesses slightly, as the software generated commands are always slower than the hardware. Non-harddisk devices always get read/write- - commands in bypass mode. + commands in bypass mode. On the most recent releases of + the Linux IBM-SCSI-driver, the bypass command should be + no longer a necessary thing, if you are sure about your + SCSI-hardware! normal This is the parameter, introduced on the 2.0.x development rail by ZP Gu. This parameter defines the SCSI-device scan order in the new industry standard. This means, that @@ -789,6 +975,19 @@ pun=6 gets sda and a harddisk at pun=0 gets sdb. If you like to have the same SCSI-device order, as in DOS, OS-9 or OS/2, just use this parameter. + fast SCSI-I/O in synchronous mode is done at 5 MHz for IBM- + SCSI-devices. SCSI-2 Fast/Wide Adapter/A external bus + should then run at 10 MHz if Fast-SCSI is enabled, + and at 5 MHz if Fast-SCSI is disabled on the external + bus. This is the default setting when nothing is + specified here. + medium Synchronous rate is at 50% approximately, which means + 2.5 MHz for IBM SCSI-adapters and 5.0 MHz for F/W ext. + SCSI-bus (when Fast-SCSI speed enabled on external bus). + slow The slowest possible synchronous transfer rate is set. + This means 1.82 MHz for IBM SCSI-adapters and 2.0 MHz + for F/W external bus at Fast-SCSI speed on the external + bus. A further option is that you can force the SCSI-driver to accept a SCSI- subsystem at a certain I/O-address with a predefined adapter PUN. This @@ -805,7 +1004,7 @@ ibmmcascsi=adisplay,bypass This will use the advanced display mode for the model 95 LED display and - every SCSI-command passed to a attached device will get bypassed in order + every SCSI-command passed to an attached device will get bypassed in order not to use any of the subsystem built-in commands. ibmmcascsi=display,0x3558,7 @@ -837,9 +1036,9 @@ with OS/2 and DOS, you have to activate this flag in the kernel configuration or you should set 'ansi' as parameter for the kernel. The parameter 'normal' sets the new industry standard, starting - from pun 0, scaning up to pun 6. This allows you to change your + from pun 0, scanning up to pun 6. This allows you to change your opinion still after having already compiled the kernel. - Q: Why can I not find the IBM MCA SCSI support in the config menue? + Q: Why I cannot find the IBM MCA SCSI support in the config menue? A: You have to activate MCA bus support, first. Q: Where can I find the latest info about this driver? A: See the file MAINTAINERS for the current WWW-address, which offers @@ -849,13 +1048,9 @@ A: Just force it to be recognized by kernel parameters. See section 5.1. Q: The driver screws up, if it starts to probe SCSI-devices, is there some way out of it? - A: This is based on some problems with the driver. In such cases, send - e-mail to the maintainer. If you are owner of a model with the serial - number 95XX, just send as subject NOTIFY 95XX PROBLEM and the - maintainer immediately knows about your problem. But please: - Check your hardware and only if it works fine with other operating - systems, send E-Mail to me to notify the troubles. See the homepage - for how to send bug-reports or please read the next Q/A, here: + A: Yes, that was some recognition problem of the correct SCSI-adapter + and its I/O base addresses. Upgrade your driver to the latest release + and it should be fine again. Q: I get a message: panic IBM MCA SCSI: command error .... , what can I do against this? A: Previously, I followed the way by ignoring command errors by using @@ -867,8 +1062,8 @@ ibmmcascsi=forgiveall. Are there other possibilities to prevent such panics? A: No, get just the latest release of the driver and it should work - better and better with increasing version number. Forget this - ibmmcascsi=forgiveall, as also ignorecmd are obsolete. + better and better with increasing version number. Forget about this + ibmmcascsi=forgiveall, as also ignorecmd are obsolete.! Q: Linux panics or stops without any comment, but it is probable, that my harddisk(s) have bad blocks. A: Sorry, the bad-block handling is still a feeble point of this driver, @@ -893,10 +1088,45 @@ Astonishingly, reset works in most cases quite ok, but the harddisks won't run in synchonous mode anymore after a reset, until you reboot. Q: Why does my XXX w/Cache adapter not use read-prefetch? - A: w/Cache technical manuals are incoming here, so if I understood the - command of read-prefetch, it should be an easy thing to get harddisks - read in read-prefetch with w/Cache controllers. Some weeks or months, - still ahead and a lot of work still to do, sigh ... + A: Ok, that is not completely possible. If a cache is present, the + adapter tries to use it internally. Explicitly, one can use the cache + with a read prefetch command, maybe in future, but this requires + some major overhead of SCSI-commands that risks the performance to + go down more than it gets improved. Tests with that are running. + Q: I have a IBM SCSI-2 Fast/Wide adapter, it boots in some way and hangs. + A: Yes, that is understood, as for sure, your SCSI-2 Fast/Wide adapter + was in such a case recognized as integrated SCSI-adapter or something + else, but not as the correct adapter. As the I/O-ports get assigned + wrongly by that reason, the system should crash in most cases. You + should upgrade to the latest release of the SCSI-driver. The + recommended version is 3.2 or later. Here, the F/W support is in + a stable and reliable condition. Wide-addressing is in addition + supported. + Q: I get a Ooops message and something like "killing interrupt". + A: The reason for this is that the IBM SCSI-subsystem only sends a + termination status back, if some error appeared. In former releases + of the driver, it was not checked, if the termination status block + is NULL. From version 3.2, it is taken care of this. + Q: I have a F/W adapter and the driver sees my internal SCSI-devices, + but ignores the external ones. + A: Select combined busmode in the config-program and check for that + no SCSI-id on the external devices appears on internal devices. + Reboot afterwards. Dual busmode is supported, but works only for the + internal bus, yet. External bus is still ignored. Take care for your + SCSI-ids. If combined bus-mode is activated, on some adapters, + the wide-addressing is not possible, so devices with ids between 8 + and 15 get ignored by the driver & adapter! + Q: I have a 9595 and I get a NMI during heavy SCSI I/O e.g. during fsck. + A COMMAND ERROR is reported and characters on the screen are missing. + Warm reboot is not possible. Things look like quite weired. + A: Check the processor type of your 9595. If you have an 80486 or 486DX-2 + processor complex on your mainboard and you compiled a kernel that + supports 80386 processors, it is possible, that the kernel cannot + keep track of the PS/2 interrupt handling and stops on an NMI. Just + compile a kernel for the correct processor type of your PS/2 and + everything should be fine. This is necessary even if one assumes, + that some 80486 system should be downward compatible to 80386 + software. 5.3 Bugreports -------------- @@ -909,7 +1139,9 @@ Zubkoff, as Linus is burried in E-Mail and Leonard is supervising all SCSI-drivers and won't have the time left to look inside every single driver to fix a bug and especially DO NOT send modified code to Linus - Torvalds, which has not been checked here!!! Recently, I got a lot of + Torvalds or Alan J. Cox which has not been checked here!!! They are both + quite burried in E-mail (as me, sometimes, too) and one should first check + for problems on my local teststand. Recently, I got a lot of bugreports for errors in the ibmmca.c code, which I could not imagine, but a look inside some Linux-distribution showed me quite often some modified code, which did no longer work on most other machines than the one of the @@ -934,23 +1166,36 @@ http://www.uni-mainz.de/~langm000/linux.html Here you can find info about the background of this driver, patches, - news and a bugreport form. + troubleshooting support, news and a bugreport form. Please check that + WWW-page regularly for latest hints. + + For the bugreport, please fill out the formular on the corresponding + WWW-page. Read the dedicated instructions and write as much as you + know about your problem. If you do not like such formulars, please send + some e-mail directly, but at least with the same information as required by + the formular. + + If you have extensive bugreports, including Ooops messages and + screen-shots, please feel free to send it directly to the address + of the maintainer, too. The current address of the maintainer is: + + Michael Lang 6 References ------------ - The source of information is "Update for the PS/2 Hardware - Interface Technical Reference, Common Interfaces", September 1991, - part number 04G3281, available in the U.S. for $21.75 at - 1-800-IBM-PCTB, elsewhere call your local friendly IBM - representative. E.g. in Germany, "Hallo IBM" works really great. - In addition to SCSI subsystem, this update contains fairly detailed - (at hardware register level) sections on diskette controller, - keyboard controller, serial port controller, VGA, and XGA. + IBM Corp., "Update for the PS/2 Hardware Interface Technical Reference, + Common Interfaces", Armonk, September 1991, PN 04G3281, + (available in the U.S. for $21.75 at 1-800-IBM-PCTB or in Germany for + around 40,-DM at "Hallo IBM"). - Additional information from "Personal System/2 Micro Channel SCSI - Adapter with Cache Technical Reference", March 1990, PN 68X2365, - probably available from the same source (or possibly found buried - in officemates desk). + IBM Corp., "Personal System/2 Micro Channel SCSI + Adapter with Cache Technical Reference", Armonk, March 1990, PN 68X2365. + + IBM Corp., "Personal System/2 Micro Channel SCSI + Adapter Technical Reference", Armonk, March 1990, PN 68X2397. + + IBM Corp., "SCSI-2 Fast/Wide Adapter/A Technical Reference - Dual Bus", + Armonk, March 1994, PN 83G7545. Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie- Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl. @@ -965,14 +1210,101 @@ Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme * Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988 - 7 Trademarks + 7 Credits to + ------------ + 7.1 People + ---------- + Klaus Grimm + who already a long time ago gave me the old code from the + SCSI-driver in order to get it running for some old machine + in our institute. + Martin Kolinek + who wrote the first release of the IBM SCSI-subsystem driver. + Chris Beauregard + who for a long time maintained MCA-Linux and the SCSI-driver + in the beginning. Chris, wherever you are: Cheers to you! + Klaus Kudielka + with whom in the 2.1.x times, I had a quite fruitful + cooperation to get the driver running as a module and to get + it running with multiple SCSI-adapters. + David Weinehall + for his excellent maintenance of the MCA-stuff and the quite + detailed bug reports and ideas for this driver (and his + patience ;-)). + Alan J. Cox + for his bugreports and his bold activities in cross-checking + the driver-code with his teststand. + + 7.2 Sponsors & Supporters + ------------------------- + "Hallo IBM", + IBM-Deutschland GmbH + the service of IBM-Deutschland for customers. Their E-Mail + service is unbeatable. Whatever old stuff I asked for, I + always got some helpful answers. + Karl-Otto Reimers, + IBM Klub - Sparte IBM Geschichte, Sindelfingen + for sending me a copy of the w/Cache manual from the + IBM-Deutschland archives. + Harald Staiger + for his extensive hardware donations which allows me today + still to test the driver in various constellations. + Erich Fritscher + for his very kind sponsoring. + Louis Ohland, + Charles Lasitter + for support by shipping me an IBM SCSI-2 Fast/Wide manual. + In addition, the contribution of various hardware is quite + decessive and will make it possible to add FWSR (RAID) + adapter support to the driver in the near future! So, + complaints about no RAID support won't remain forever. + Yes, folks, that is no joke, RAID support is going to rise! + Erik Weber + for the great deal we made about a model 9595 and the nice + surrounding equipment and the cool trip to Mannheim + second-hand computer market. + Anthony Hogbin + for his direct shipment of a SCSI F/W adapter, which allowed + me immediately on the first stage to try it on model 8557 + together with onboard SCSI adapter and some SCSI w/Cache. + Andreas Hotz + for his support by memory and an IBM SCSI-adapter. Collecting + all this together now allows me to try really things with + the driver at maximum load and variety on various models in + a very quick and efficient way. + Peter Jennewein + for his model 30, which serves me as part of my teststand + and his cool remark about how you make an ordinary diskette + drive working and how to connect it to an IBM-diskette port. + Johannes Gutenberg-University, Mainz & + Institut fuer Kernphysik, MAMI + for the offered space, the link, placed on the central + homepage and the space to store and offer the driver and + related material and the free working times, which allow + me to answer all your e-mail. + + 8 Trademarks ------------ IBM, PS/2, OS/2, Microchannel are registered trademarks of International - Business Machines Corp. + Business Machines Corporation MS-DOS is a registered trademark of Microsoft Corporation - OS-9 is a registered trademark of Microware Systems + Microware, OS-9 are registered trademarks of Microware Systems + + 9 Disclaimer + ------------ + Beside the GNU public license and the dependant disclaimers and disclaimers + concerning the Linux-kernel in special, this SCSI-driver comes without any + warranty. Its functionality is tested as good as possible on certain + machines and combinations of computer hardware, which does not exclude, + that dataloss or severe damage of hardware is possible while using this + part of software on some arbitrary computer hardware or in combination + with other software packages. It is highly recommended to make backup + copies of your data before using this software. + + This driver supports hardware, produced by International Business Machines + Corporation (IBM). ------ Michael Lang diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.2.17/drivers/scsi/README.ncr53c8xx Fri Apr 21 12:46:31 2000 +++ linux/drivers/scsi/README.ncr53c8xx Thu Aug 31 14:50:52 2000 @@ -1,10 +1,10 @@ -The Linux NCR53C8XX driver README file +The Linux NCR53C8XX/SYM53C8XX drivers README file Written by Gerard Roudier 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -9 May 1999 +29 May 1999 =============================================================================== 1. Introduction @@ -25,14 +25,39 @@ 8.6 Clear profile counters 8.7 Set flag (no_disc) 8.8 Set verbose level + 8.9 Reset all logical units of a target + 8.10 Abort all tasks of all logical units of a target 9. Configuration parameters 10. Boot setup commands 10.1 Syntax 10.2 Available arguments + 10.2.1 Master parity checking + 10.2.2 Scsi parity checking + 10.2.3 Scsi disconnections + 10.2.4 Special features + 10.2.5 Ultra SCSI support + 10.2.6 Default number of tagged commands + 10.2.7 Default synchronous period factor + 10.2.8 Negotiate synchronous with all devices + 10.2.9 Verbosity level + 10.2.10 Debug mode + 10.2.11 Burst max + 10.2.12 LED support + 10.2.13 Max wide + 10.2.14 Differential mode + 10.2.15 IRQ mode + 10.2.16 Reverse probe + 10.2.17 Fix up PCI configuration space + 10.2.18 Serial NVRAM + 10.2.19 Check SCSI BUS + 10.2.20 Exclude a host from being attached + 10.2.21 Suggest a default SCSI id for hosts + 10.2.22 Enable use of IMMEDIATE ARBITRATION 10.3 Advised boot setup commands 10.4 PCI configuration fix-up boot option 10.5 Serial NVRAM support boot option 10.6 SCSI BUS checking boot option + 10.7 IMMEDIATE ARBITRATION boot option 11. Some constants and flags of the ncr53c8xx.h header file 12. Installation 13. Architecture dependent features @@ -43,6 +68,8 @@ 14.4 Possible data corruption during a Memory Write and Invalidate 14.5 IRQ sharing problems 15. SCSI problem troubleshooting + 15.1 Problem tracking + 15.2 Understanding hardware error reports 16. Synchonous transfer negotiation tables 16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers 16.2 Synchronous timings for fast SCSI-2 53C8XX controllers @@ -69,11 +96,12 @@ It is now available as a bundle of 2 drivers: - ncr53c8xx generic driver that supports all the SYM53C8XX family including - the ealiest 810 rev. 1 and the latest 896 2 channels LVD SCSI controller. + the ealiest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and + the new 895A (1 channel LVD SCSI controller). - sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest chips in order to gain advantage of new features, as LOAD/STORE intructions available since the 810A and hardware phase mismatch available with the - latest 896. + 896 and the 895A. You can find technical information about the NCR 8xx family in the PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by @@ -95,15 +123,17 @@ These tools are not ALPHA but quite clean and work quite well. It is essential you have the 'scsiinfo' package. -This short documentation only describes the features of the NCR53C8XX -driver, configuration parameters and control commands available -through the proc SCSI file system read / write operations. +This short documentation describes the features of the generic and enhanced +drivers, configuration parameters and control commands available through +the proc SCSI file system read / write operations. This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC. Latest driver version and patches are available at: ftp://ftp.tux.org/pub/people/gerard-roudier +or + ftp://ftp.symbios.com/mirror/ftp.tux.org/pub/tux/roudier/drivers I am not a native speaker of English and there are probably lots of mistakes in this README file. Any help will be welcome. @@ -136,7 +166,14 @@ 875 Y Y FAST20 40 MB/s Y Y 876 Y Y FAST20 40 MB/s Y Y 895 Y Y FAST40 80 MB/s Y Y +895A Y Y FAST40 80 MB/s Y Y 896 Y Y FAST40 80 MB/s Y Y +897 Y Y FAST40 80 MB/s Y Y +1510D Y Y FAST40 80 MB/s Y Y +1010 Y Y FAST80 160 MB/s N Y +1010_66* Y Y FAST80 160 MB/s N Y + +* Chip supports 33MHz and 66MHz PCI buses. Summary of other supported features: @@ -156,21 +193,25 @@ 3.1 Optimized SCSI SCRIPTS. -The 810A, 825A, 875, 895 and newest 896 support new SCSI SCRIPTS instructions -named LOAD and STORE that allow to move 1 DWORD from/to an IO register to/from -memory much faster that the MOVE MEMORY instruction that is supported by the -53c7xx and 53c8xx family. The LOAD/STORE instructions support absolute and -DSA relative addressing modes. The SCSI SCRIPTS had been entirely rewritten -using LOAD/STORE instead of MOVE MEMORY instructions. +The 810A, 825A, 875, 895, 896 and 895A support new SCSI SCRIPTS instructions +named LOAD and STORE that allow to move up to 1 DWORD from/to an IO register +to/from memory much faster that the MOVE MEMORY instruction that is supported +by the 53c7xx and 53c8xx family. +The LOAD/STORE instructions support absolute and DSA relative addressing +modes. The SCSI SCRIPTS had been entirely rewritten using LOAD/STORE instead +of MOVE MEMORY instructions. 3.2 New features of the SYM53C896 (64 bit PCI dual LVD SCSI controller) -The 896 allows to handle the phase mismatch context saving from SCRIPTS -(avoids the phase mismatch interrupt that stops the SCSI processor +The 896 and the 895A allows handling of the phase mismatch context from +SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor until the C code has saved the context of the transfer). Implementing this without using LOAD/STORE instructions would be painfull -and I did'nt even try it. This chip also supports 64 bit PCI transactions -and addressing. The SCRIPTS processor is not true 64 bit, but uses segment +and I did'nt even want to try it. + +The 896 chip supports 64 bit PCI transactions and addressing, while the +895A supports 32 bit PCI transactions and 64 bit addressing. +The SCRIPTS processor of these chips is not true 64 bit, but uses segment registers for bit 32-63. Another interesting feature is that LOAD/STORE instructions that address the on-chip RAM (8k) remain internal to the chip. @@ -219,9 +260,13 @@ is currently set to 8 by default. This value is suitable for most SCSI disks. With large SCSI disks (>= 2GB, cache >= 512KB, average seek time <= 10 ms), using a larger value may give better performances. -The driver supports up to 64 commands per device, but using more than -32 is generally not worth it, unless you are using a very large disk -or disk array. + +The sym53c8xx driver supports up to 255 commands per device, and the +generic ncr53c8xx driver supports up to 64, but using more than 32 is +generally not worth-while, unless you are using a very large disk or disk +array. It is noticeable that most of recent hard disks seem not to accept +more than 64 simultaneous commands. So, using more than 64 queued commands +is probably just resource wasting. If your controller does not have NVRAM or if it is managed by the SDMS BIOS/SETUP, you can configure tagged queueing feature and device queue @@ -491,6 +536,24 @@ The driver default verbose level is 1. This command allows to change th driver verbose level after boot-up. +8.9 Reset all logical units of a target + + resetdev + + target: target number + The driver will try to send a BUS DEVICE RESET message to the target. + (Only supported by the SYM53C8XX driver and provided for test purpose) + +8.10 Abort all tasks of all logical units of a target + + cleardev + + target: target number + The driver will try to send a ABORT message to all the logical units + of the target. + (Only supported by the SYM53C8XX driver and provided for test purpose) + + 9. Configuration parameters If the firmware of all your devices is perfect enough, all the @@ -566,10 +629,11 @@ Setup commands can be passed to the driver either at boot time or as a string variable using 'insmod'. -A boot setup command for the ncr53c8xx driver begins with the driver name -"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of -integers separated with comma followed by an optionnal list of comma- -separated strings. Example of boot setup command under lilo prompt: +A boot setup command for the ncr53c8xx (sym53c8xx) driver begins with the +driver name "ncr53c8xx="(sym53c8xx). The kernel syntax parser then expects +an optionnal list of integers separated with comma followed by an optional +list of comma-separated strings. Example of boot setup command under lilo +prompt: lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200 @@ -582,7 +646,7 @@ The following command will install driver module with the same options as above. -insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200" + insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200" For the moment, the integer list of arguments is discarded by the driver. It will be used in the future in order to allow a per controller setup. @@ -590,40 +654,54 @@ Each string argument must be specified as "keyword:value". Only lower-case characters and digits are allowed. +In a system that contains multiple 53C8xx adapters insmod will install the +specified driver on each adapter. To exclude a chip use the 'excl' keyword. + +The sequence of commands, + + insmod sym53c8xx sym53c8xx=excl:0x1400 + insmod ncr53c8xx + +installs the sym53c8xx driver on all adapters except the one at IO port +address 0x1400 and then installs the ncr53c8xx driver to the adapter at IO +port address 0x1400. + + 10.2 Available arguments -Master parity checking - mpar:y enabled - mpar:n disabled - -Scsi parity checking - spar:y enabled - spar:n disabled - -Scsi disconnections - disc:y enabled - disc:n disabled +10.2.1 Master parity checking + mpar:y enabled + mpar:n disabled + +10.2.2 Scsi parity checking + spar:y enabled + spar:n disabled + +10.2.3 Scsi disconnections + disc:y enabled + disc:n disabled -Special features +10.2.4 Special features Only apply to 810A, 825A, 860, 875 and 895 controllers. Have no effect with other ones. - specf:y (or 1) enabled - specf:n (or 0) disabled - specf:3 enabled except Memory Write And Invalidate + specf:y (or 1) enabled + specf:n (or 0) disabled + specf:3 enabled except Memory Write And Invalidate The default driver setup is 'specf:3'. As a consequence, option 'specf:y' must be specified in the boot setup command to enable Memory Write And Invalidate. -Ultra SCSI support - Only apply to 860, 875 and 895 controllers. +10.2.5 Ultra SCSI support + Only apply to 860, 875, 895, 895a, 896, 1010 and 1010_66 controllers. Have no effect with other ones. - ultra:2 Ultra2 enabled - ultra:1 Ultra enabled - ultra:n disabled - -Default number of tagged commands - tags:0 (or tags:1 ) tagged command queuing disabled - tags:#tags (#tags > 1) tagged command queuing enabled + ultra:n All ultra speeds enabled + ultra:2 Ultra2 enabled + ultra:1 Ultra enabled + ultra:0 Ultra speeds disabled + +10.2.6 Default number of tagged commands + tags:0 (or tags:1 ) tagged command queuing disabled + tags:#tags (#tags > 1) tagged command queuing enabled #tags will be truncated to the max queued commands configuration parameter. This option also allows to specify a command queue depth for each device that support tagged command queueing. @@ -635,9 +713,9 @@ - controller #1 target #1 logical unit #2 -> 32 commands, - all other logical units (all targets, all controllers) -> 10 commands. -Default synchronous period factor - sync:255 disabled (asynchronous transfer mode) - sync:#factor +10.2.7 Default synchronous period factor + sync:255 disabled (asynchronous transfer mode) + sync:#factor #factor = 10 Ultra-2 SCSI 40 Mega-transfers / second #factor = 11 Ultra-2 SCSI 33 Mega-transfers / second #factor < 25 Ultra SCSI 20 Mega-transfers / second @@ -646,19 +724,19 @@ In all cases, the driver will use the minimum transfer period supported by controllers according to NCR53C8XX chip type. -Negotiate synchronous with all devices - (force sync nego) - fsn:y enabled - fsn:n disabled - -Verbosity level - verb:0 minimal - verb:1 normal - verb:2 too much - -Debug mode - debug:0 clear debug flags - debug:#x set debug flags +10.2.8 Negotiate synchronous with all devices + (force sync nego) + fsn:y enabled + fsn:n disabled + +10.2.9 Verbosity level + verb:0 minimal + verb:1 normal + verb:2 too much + +10.2.10 Debug mode + debug:0 clear debug flags + debug:#x set debug flags #x is an integer value combining the following power-of-2 values: DEBUG_ALLOC 0x1 DEBUG_PHASE 0x2 @@ -677,10 +755,10 @@ You can play safely with DEBUG_NEGO. However, some of these flags may generate bunches of syslog messages. -Burst max - burst:0 burst disabled - burst:255 get burst length from initial IO register settings. - burst:#x burst enabled (1<<#x burst transfers max) +10.2.11 Burst max + burst:0 burst disabled + burst:255 get burst length from initial IO register settings. + burst:#x burst enabled (1<<#x burst transfers max) #x is an integer value which is log base 2 of the burst transfers max. The NCR53C875 and NCR53C825A support up to 128 burst transfers (#x = 7). Other chips only support up to 16 (#x = 4). @@ -688,42 +766,42 @@ and revision ids. By default the driver uses the maximum value supported by the chip. -LED support - led:1 enable LED support - led:0 disable LED support +10.2.12 LED support + led:1 enable LED support + led:0 disable LED support Donnot enable LED support if your scsi board does not use SDMS BIOS. (See 'Configuration parameters') -Max wide - wide:1 wide scsi enabled - wide:0 wide scsi disabled +10.2.13 Max wide + wide:1 wide scsi enabled + wide:0 wide scsi disabled Some scsi boards use a 875 (ultra wide) and only supply narrow connectors. If you have connected a wide device with a 50 pins to 68 pins cable converter, any accepted wide negotiation will break further data transfers. In such a case, using "wide:0" in the bootup command will be helpfull. -Differential mode - diff:0 never set up diff mode - diff:1 set up diff mode if BIOS set it - diff:2 always set up diff mode - diff:3 set diff mode if GPIO3 is not set - -IRQ mode - irqm:0 always open drain - irqm:1 same as initial settings (assumed BIOS settings) - irqm:2 always totem pole - irqm:0x10 driver will not use SA_SHIRQ flag when requesting irq - irqm:0x20 driver will not use SA_INTERRUPT flag when requesting irq +10.2.14 Differential mode + diff:0 never set up diff mode + diff:1 set up diff mode if BIOS set it + diff:2 always set up diff mode + diff:3 set diff mode if GPIO3 is not set + +10.2.15 IRQ mode + irqm:0 always open drain + irqm:1 same as initial settings (assumed BIOS settings) + irqm:2 always totem pole + irqm:0x10 driver will not use SA_SHIRQ flag when requesting irq + irqm:0x20 driver will not use SA_INTERRUPT flag when requesting irq (Bits 0x10 and 0x20 can be combined with hardware irq mode option) -Reverse probe - revprob:n probe chip ids from the PCI configuration in this order: - 810, 815, 820, 860, 875, 885, 895, 896 - revprob:y probe chip ids in the reverse order. +10.2.16 Reverse probe + revprob:n probe chip ids from the PCI configuration in this order: + 810, 815, 820, 860, 875, 885, 895, 896 + revprob:y probe chip ids in the reverse order. -Fix up PCI configuration space - pcifix: